Compare commits

...

97 Commits

Author SHA1 Message Date
Unknwon
b5f6206a65 prepare release 2015-12-06 15:34:17 -05:00
Unknwon
3de9c11ea7 Merge pull request #2110 from msoedov/misspellings
Fix misspelled words
2015-12-06 15:27:11 -05:00
Alex Myasoedov
ae54d878c0 Fix misspelled words 2015-12-06 16:42:23 +02:00
Unknwon
89244b74c6 remember page number when delete repo 2015-12-05 17:49:46 -05:00
Unknwon
ca8ce793d1 #2063 Ability to delete repo from admin panel 2015-12-05 17:39:29 -05:00
Unknwon
978dc00305 APIs: admin users 2015-12-05 17:13:13 -05:00
Unknwon
bf26808fb3 update README 2015-12-05 13:50:43 -05:00
Unknwon
404867f206 fix #2105 and fix #1857 2015-12-05 13:24:13 -05:00
Unknwon
f0ee33267c fix #2102 2015-12-05 11:46:42 -05:00
Unknwon
f3eaa4c592 Set default language for i18n 2015-12-05 01:20:11 -05:00
Unknwon
f41360d864 #2052 advanced select ops for system notices 2015-12-05 01:09:14 -05:00
Unknwon
e82ee40e9e init with all enabled 2015-12-04 21:34:37 -05:00
Unknwon
1ee7c33e93 template fix 2015-12-04 21:32:33 -05:00
Unknwon
e538ff2770 fix #1829 and fix #890 2015-12-04 21:30:33 -05:00
Unknwon
76d4b9288b #2045 have fallback but empty value 2015-12-04 19:01:34 -05:00
Unknwon
05ba8622f0 #2045 move fallback to empty string 2015-12-04 18:31:45 -05:00
Unknwon
4795fa01d8 fix #2101 2015-12-04 17:30:32 -05:00
Unknwon
942fd6be53 fix panic for #2045 2015-12-04 17:20:23 -05:00
Unknwon
56dd430a10 refactor API routes and some work for #976 2015-12-04 17:16:42 -05:00
Unknwon
e0bae9547a more fixes on #2045 2015-12-04 15:41:56 -05:00
Unknwon
bfe6027266 Merge branch 'develop' of github.com:gogits/gogs into develop 2015-12-03 18:10:54 -05:00
Unknwon
4d9499c2d3 fix broken link 2015-12-03 18:10:45 -05:00
Unknwon
98e989d52c minor JS and UI fix 2015-12-03 15:01:15 -05:00
Unknwon
5742f9fe69 fix #2095 2015-12-03 14:31:31 -05:00
Unknwon
1802d52362 Merge pull request #2094 from nanoant/patch/less-pronounced-sha-labels
UI: Use more subtle grey SHA1 labels
2015-12-03 14:28:30 -05:00
Adam Strzelecki
cab2911f23 UI: More subtle strips on commits list
With grey SHA1 labels, we should consider having also more subtle strips on
commits list. As current strips blend too much with grey SHA1 labels and top
bar, making hard to distinguish headers from content.
2015-12-03 20:26:06 +01:00
Unknwon
81133d45a1 work on #2093 2015-12-03 14:21:13 -05:00
Unknwon
a51acf1751 Merge pull request #2092 from nanoant/patch/non-bold-last-commit-sha
UI: Remove CSS rule making last-commit SHA bold
2015-12-03 13:14:57 -05:00
Adam Strzelecki
edbb67cb3f UI: Use more subtle grey SHA1 labels
Current green SHA1 labels are more pronounced than other UI elements attracting
attention as if they were most important thing in the UI, while they are not as
important, especially without real Git client.

Using grey SHA1 labels makes the UI more balanced, less aggressive and lets
user to focus on other content elements.

NOTE: Neither GitHub or Bitbucket uses so heavy pronunciation as Gogs.
2015-12-03 14:21:20 +01:00
Adam Strzelecki
c5e249c0be UI: Remove CSS rule making last-commit SHA bold
This removes remains from old design, that was not cleaned by previous #2068 PR.
2015-12-03 13:30:16 +01:00
Unknwon
37a372f6f5 500 when wiki not exists 2015-12-03 02:08:25 -05:00
Unknwon
f122d0856e fix #2090 2015-12-03 01:59:32 -05:00
Unknwon
4a6016f5af fix #2087 2015-12-03 01:03:06 -05:00
Unknwon
cc8f5add6e fix #976 2015-12-03 00:24:37 -05:00
Unknwon
ec2423ad7c more UI minor fixes 2015-12-02 20:56:26 -05:00
Unknwon
c4bab163cb Merge pull request #2088 from nanoant/patch/further-layout-fixes
Further layout fixes
2015-12-02 20:26:48 -05:00
Adam Strzelecki
0068b8106b CSS: Octicons 16px fix outside of _octicons.less
Otherwise the fix will be overwritten by next _octicons.less update.

This is follow-up for 22b0dfbb35.
2015-12-03 02:18:38 +01:00
Adam Strzelecki
2580e7b57e UI: Always show menu on repo pages
Merges repo/sidebar.tmpl with repo/header.tmpl and makes every repo page use
middleware.RepoRef() necessary to display information on this menu.
2015-12-03 02:16:18 +01:00
Unknwon
3d3498bda1 clean test data 2015-12-02 20:10:47 -05:00
Unknwon
29375059e1 minor CSS fix 2015-12-02 20:10:00 -05:00
Unknwon
85449b2f11 minor CSS fix for #2068 2015-12-02 19:53:39 -05:00
Unknwon
b83cb36049 minor fix for #2086 2015-12-02 19:45:43 -05:00
Unknwon
73d9eebf01 Merge pull request #2068 from nanoant/patch/repo-file-list-layout
Repo file list layout & misc fixes
2015-12-02 19:44:16 -05:00
Adam Strzelecki
b73241ceb1 UI: Display last-commit header without 2nd column
This uses a CSS trick making first th to be relative block with width equal to
first two columns, effectively working around inability to use colspan="2" on
first row that was breaking "fixed-layout" for tables.

Also use grey header for last-commit SHA1 tag.
2015-12-03 01:15:40 +01:00
Unknwon
e350d74c8a fix #2085 2015-12-02 18:58:13 -05:00
Unknwon
149e540322 Merge pull request #2086 from nanoant/patch/translation-add-code-entry
Translation: Add missing entry for new "code" tab
2015-12-02 18:53:38 -05:00
Adam Strzelecki
314664892c UI: Keep repo URL action right of ref combo & path
Just use secondary menu instead custom ".head.meta", which simplifies code.

Also do not display repo URL action when we are in subdirectory or viewing a
file.
2015-12-02 23:48:36 +01:00
Adam Strzelecki
a9a386a1e5 Translation: Add missing entry for new "code" tab
We have new tab, but we had no entry. That's why it was showing "code"
(lowercase) as this is text id, where we were expecting properly title cased
"Code" to be shown in English version.

Also add Polish translation "code=Kod".
2015-12-02 23:00:23 +01:00
Adam Strzelecki
3eae4ecde7 UI: Make repository menu divide header and content
This is more inline with way GitHub looks like and feels much more natural and
in style with rest of the interface.
2015-12-02 22:40:22 +01:00
Adam Strzelecki
ec98deeb8c UI: Keep repository settings menu button right 2015-12-02 22:06:50 +01:00
Adam Strzelecki
61fdd8c571 Commits & files UI: SUI fixed single line table
Instead using own ellipsis, uses Semantic UI fixed single line table which
effectively applies ellipsis to all overflowing table cells.

NOTE: File list cannot use colspan="2" for 1st "Last commit" elements,
otherwise layout breaks with fixed table.
2015-12-02 21:57:39 +01:00
Adam Strzelecki
4813665d0a CSS: Reduce .sha.label font size to 13px 2015-12-02 21:43:30 +01:00
Adam Strzelecki
640dce12a8 CSS: .repository .sha.label -> .ui .sha.label
This is because SHA1 label is used in many other places, not only inside
.repository container.
2015-12-02 21:42:31 +01:00
Adam Strzelecki
99b958db43 UI: Mark top menu icons blue only when non-zero 2015-12-02 21:38:52 +01:00
Adam Strzelecki
22b0dfbb35 CSS: Ensure Octicons are used with 16px font size
Semantic UI .icon 1em font-size has priority over .octicon 16px, resulting
octicons rendered at 14px font-size, which is not okay since Octicons are meant
to be shown sizes that are multiples of 16px.
2015-12-02 21:33:32 +01:00
Unknwon
4a64ae4abf fix #2083 2015-12-02 13:47:22 -05:00
Unknwon
926e91820a #2071 Diff is not showing full content when has super long one line 2015-12-02 01:10:13 -05:00
Unknwon
91ae2ad28b Merge pull request #2081 from angus-g/en-trans
Update English translations
2015-12-01 23:46:05 -05:00
Angus Gibson
db30ea03d8 Fix casing in English translation 2015-12-02 15:43:56 +11:00
Unknwon
0be8b1b1a1 #2052 Ability to batch delete system notices 2015-12-01 23:33:08 -05:00
Angus Gibson
d45302a6ba Update English translations
Just some phrasing changes to make the English translations sound more natural.
2015-12-02 15:27:08 +11:00
Unknwon
834d38a8fb #2045 add short version as fallback to Slack payload 2015-12-01 21:16:19 -05:00
Unknwon
5572884c6b fix #2057 2015-12-01 20:51:31 -05:00
Unknwon
3460ec1039 update REMADE and locale 2015-12-01 19:53:19 -05:00
Unknwon
53bf23d965 Merge pull request #2079 from nanoant/patch/ldap-custom-username-attr
LDAP: Optional user name attribute specification
2015-12-01 18:23:12 -05:00
Adam Strzelecki
573305f3d3 LDAP: Optional user name attribute specification
Consider following LDAP search query example:

    (&(objectClass=Person)(|(uid=%s)(mail=%s)))

Right now on first login attempt Gogs will use the text supplied on login form
as the newly created user name. In example query above the text matches against
both e-mail or user name. So if user puts the e-mail then the new Gogs user
name will be e-mail which may be undesired.

Using optional user name attribute setting we can explicitly say we want Gogs
user name to be certain LDAP attribute eg. `uid`, so even user will use e-mail
to login 1st time, the new account will receive correct user name.
2015-12-02 00:20:14 +01:00
Unknwon
7ccce4d110 Merge pull request #2078 from nanoant/patch/makefile-improvements
Makefile improvements
2015-12-01 17:26:25 -05:00
Unknwon
9ed60d96a9 fix API 2015-12-01 16:33:45 -05:00
Unknwon
b6d2b96259 Merge pull request #2076 from Gibheer/new_mirror
add new mirror button to dashboard
2015-12-01 16:33:00 -05:00
Adam Strzelecki
e5fe367b82 scripts: Remove less.sh superseded by Makefile
We no longer need to manually build CSS files as Makefile keeps track of it.
2015-12-01 22:28:21 +01:00
Adam Strzelecki
19e8ce0354 Makefile: Remove trailing whitespace & add last LF
This is pure cleanup commit.
2015-12-01 22:20:21 +01:00
Adam Strzelecki
f907a5c98b Makefile: Auto-build CSS & bin-data when necessary
This will ensure that running `make` we will get all necessary files built and
we do not need manually remember to rebuild them.
2015-12-01 22:18:30 +01:00
Adam Strzelecki
da607c611d Makefile: Copy installed binary instead 2nd build
This speeds up single build/rebuild rather than install & build which compiles
everything twice, we just copy installed binary back to the project root.
2015-12-01 22:16:00 +01:00
Gibheer
3d54f6c0a4 add new mirror button to dashboard
This adds the button to create a new mirror on the dashboard at the same
place where "new repository" and "new organization" already exist.
2015-12-01 21:10:36 +01:00
Unknwon
2093586241 Merge pull request #2016 from raxetul/develop
Dockerfile for RaspberryPi is added.
2015-12-01 14:46:03 -05:00
Unknwon
117afe7620 Merge pull request #2069 from nanoant/patch/admin-see-all-organizations
Admin should be able to see all organizations
2015-11-30 21:18:33 -05:00
Unknwon
d3a5ff7b6b fix #2042 2015-11-30 20:50:40 -05:00
Unknwon
dcb391d341 Merge branch 'feature/wiki' into develop 2015-11-30 20:46:19 -05:00
Unknwon
830d000667 finish wiki 2015-11-30 20:45:55 -05:00
Unknwon
5a14c3cf98 Merge pull request #2053 from kakwa/develop
various fixes in gogs dump command
2015-11-30 16:18:18 -05:00
Adam Strzelecki
e57b2dffa4 Admin should be able to see all organizations
This is follow-up for 56c66ee486 allowing admin
to see private repositories, even when not being member of them.
2015-11-30 21:46:01 +01:00
Unknwon
ca96e04e5f #1681 carry --config flag for builtin SSH 2015-11-30 15:40:05 -05:00
Unknwon
9950f5a5bd add line break after SSH error message 2015-11-30 10:00:52 -05:00
kakwa
1d7a1b6034 add name of the dump file in last log message 2015-11-28 15:22:10 +01:00
kakwa
a59b1fcc21 Fix dump of log and custom directory in dump cmd
Now, the dump cmd uses setting.CustomPath and setting.LogRootPath
instead of setting.WorkDir which was kind of broken if the gogs
binary was in a different directory than gogs data.
Additionally, the backup of setting.CustomPath directory is only done
if it exists.
2015-11-28 15:08:50 +01:00
kakwa
c5a9be9115 Using a tmp dir to generate db and repo dumps
Using a tmp dir makes gogs dump more robust to concurrent runs.

It also permits an easier cleaning of the tmp files (gogs-db.sql and
gog-repo.zip) by just removing the tmp dir.

As a side effect, it partially fix bugs on workdir.
Previously, 'gogs dump' created the archives in the current directory,
and tried to include these archives from the directory where the
gogs binary lies.
ex: if gogs binary is in /usr/bin/gogs, and gogs dump is run from /tmp/,
/tmp/gog-repo.zip is created, but gogs dump tried to include
/usr/bin/gogs-repo.zip.
2015-11-28 14:07:51 +01:00
kakwa
f86afb04a2 Adding more error handling in dump cmd
The dump cmd did not check the return value of the z.AddFile or
z.AddDir when building the final archive.
It caused the dump command to succeed even if an error occurred.
The resulted dump archive could be corrupted/empty.
(errors could be various: removal by a concurrent process, disk full,
bugs in the dump cmd itself)
2015-11-28 12:11:38 +01:00
Unknwon
5d1f5f32d0 wiki: finish pages 2015-11-27 02:16:12 -05:00
Unknwon
e42fcb033d wiki: finish edit 2015-11-27 01:50:38 -05:00
Unknwon
392f3ee210 wiki: finish new 2015-11-27 00:24:24 -05:00
Unknwon
c50a3503e6 introduce git-shell 2015-11-26 17:33:45 -05:00
Unknwon
aaa3f1b2b9 Use better LDAP lib and should fix #1139 2015-11-26 14:04:58 -05:00
Unknwon
2b10fdc4dc Wiki: UI for page new 2015-11-25 20:10:25 -05:00
Unknwon
2f28a0310b Merge branch '0.8.0' of github.com:gogits/gogs into develop 2015-11-25 11:01:40 -05:00
Unknwon
eb30cbab81 add unsupported migration prompt 2015-11-25 09:27:27 -05:00
Emrah URHAN
737da1a374 Latest develop updates is merged with my RaspberryPi Dockerfile version.
Merge branch 'develop' of https://github.com/gogits/gogs into develop
2015-11-22 19:40:18 +02:00
Emrah URHAN
f63a468dfc Dockerfile for RaspberryPi is added. 2015-11-22 17:14:08 +02:00
155 changed files with 4334 additions and 6963 deletions

View File

@@ -4,41 +4,44 @@ path = github.com/gogits/gogs
[deps]
github.com/bradfitz/gomemcache = commit:72a68649ba
github.com/codegangsta/cli = commit:0302d39
github.com/go-macaron/binding = commit:864a5ce
github.com/go-macaron/binding = commit:2502aaf
github.com/go-macaron/cache = commit:5617353
github.com/go-macaron/captcha = commit:8aa5919
github.com/go-macaron/csrf = commit:3372b25
github.com/go-macaron/csrf = commit:715bca0
github.com/go-macaron/gzip = commit:4938e9b
github.com/go-macaron/i18n = commit:5e728b6
github.com/go-macaron/i18n = commit:d2d3329
github.com/go-macaron/inject = commit:c5ab7bf
github.com/go-macaron/session = commit:66031fc
github.com/go-macaron/toolbox = commit:ab30a81
github.com/go-sql-driver/mysql = commit:d512f20
github.com/go-xorm/core = commit:3e10003353
github.com/go-xorm/xorm = commit:c643188
github.com/go-xorm/core = commit:acb6f00
github.com/go-xorm/xorm = commit:a8fba4d
github.com/gogits/chardet = commit:2404f77725
github.com/gogits/go-gogs-client = commit:7c02c95
github.com/issue9/identicon = commit:5a61672
github.com/klauspost/compress = commit:bbfa9dc
github.com/gogits/git-shell = commit:de77627
github.com/gogits/go-gogs-client = commit:4b541fa
github.com/issue9/identicon = commit:f8c0d2c
github.com/klauspost/compress = commit:bcd0709
github.com/klauspost/cpuid = commit:8d9fe96
github.com/klauspost/crc32 = commit:3e5c38b
github.com/lib/pq = commit:83c4f41
github.com/klauspost/crc32 = commit:0aff1ea
github.com/lib/pq = commit:11fc39a
github.com/mattn/go-sqlite3 = commit:5651a9d
github.com/mcuadros/go-version = commit:d52711f
github.com/microcosm-cc/bluemonday = commit:4ac6f27
github.com/msteinert/pam = commit:6534f23b39
github.com/msteinert/pam = commit:02ccfbf
github.com/nfnt/resize = commit:dc93e1b98c
github.com/russross/blackfriday = commit:300106c
github.com/shurcooL/sanitized_anchor_name = commit:10ef21a
github.com/Unknwon/cae = commit:7f5e046
github.com/Unknwon/com = commit:28b053d
github.com/Unknwon/i18n = commit:7457d88830
github.com/Unknwon/i18n = commit:3b48b66
github.com/Unknwon/paginater = commit:7748a72
golang.org/x/net =
golang.org/x/text =
golang.org/x/crypto =
gopkg.in/asn1-ber.v1 = commit:4e86f43
gopkg.in/gomail.v2 = commit:df6fc79
gopkg.in/ini.v1 = commit:2e44421
gopkg.in/ini.v1 = commit:65f8c74
gopkg.in/ldap.v2 = e9a325d
gopkg.in/macaron.v1 = commit:1c6dd87
gopkg.in/redis.v2 = commit:e617904962

22
Dockerfile.rpi Normal file
View File

@@ -0,0 +1,22 @@
FROM sander85/rpi-alpine:latest
MAINTAINER roemer.jp@gmail.com, raxetul@gmail.com
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.6/gosu-armhf /usr/sbin/gosu
RUN echo "@edge http://dl-4.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories \
&& echo "@community http://dl-4.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories \
&& apk -U --no-progress upgrade \
&& apk -U --no-progress add ca-certificates bash git linux-pam s6@edge curl openssh socat \
&& chmod +x /usr/sbin/gosu
ENV GOGS_CUSTOM /data/gogs
COPY . /app/gogs/
WORKDIR /app/gogs/
RUN ./docker/build.sh
# Configure Docker Container
VOLUME ["/data"]
EXPOSE 22 3000
ENTRYPOINT ["docker/start.sh"]
CMD ["/usr/bin/s6-svscan", "/app/gogs/docker/s6/"]

View File

@@ -1,17 +1,21 @@
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildTime=$(shell date -u '+%Y-%m-%d %I:%M:%S %Z')"
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildGitHash=$(shell git rev-parse HEAD)"
DATA_FILES := $(shell find conf | sed 's/ /\\ /g')
LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
GENERATED := modules/bindata/bindata.go public/css/gogs.css
TAGS = ""
RELEASE_ROOT = "release"
RELEASE_GOGS = "release/gogs"
NOW = $(shell date -u '+%Y%m%d%I%M%S')
.PHONY: build pack release bindata clean
.PHONY: build pack release bindata clean
build:
build: $(GENERATED)
go install -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
go build -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
govet:
go tool vet -composites=false -methods=false -structtags=false .
@@ -25,11 +29,18 @@ pack:
release: build pack
bindata:
go-bindata -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
bindata: modules/bindata/bindata.go
modules/bindata/bindata.go: $(DATA_FILES)
go-bindata -o=$@ -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
less: public/css/gogs.css
public/css/gogs.css: $(LESS_FILES)
lessc $< $@
clean:
go clean -i ./...
clean-mac: clean
find . -name ".DS_Store" -print0 | xargs -0 rm
find . -name ".DS_Store" -print0 | xargs -0 rm

View File

@@ -5,25 +5,13 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
![](public/img/gogs-large-resize.png)
##### Current version: 0.7.22 Beta
##### Current version: 0.7.33 Beta
<table>
<tr>
<td width="33%"><img src="https://gogs.io/img/screenshots/1.png"></td>
<td width="33%"><img src="https://gogs.io/img/screenshots/2.png"></td>
<td width="33%"><img src="https://gogs.io/img/screenshots/3.png"></td>
</tr>
<tr>
<td><img src="https://gogs.io/img/screenshots/4.png"></td>
<td><img src="https://gogs.io/img/screenshots/5.png"></td>
<td><img src="https://gogs.io/img/screenshots/6.png"></td>
</tr>
<tr>
<td><img src="https://gogs.io/img/screenshots/7.png"></td>
<td><img src="https://gogs.io/img/screenshots/8.png"></td>
<td><img src="https://gogs.io/img/screenshots/9.png"></td>
</tr>
</table>
| Web | UI | Preview |
|:-------------:|:-------:|:-------:|
|![Dashboard](https://gogs.io/img/screenshots/1.png)|![Repository](https://gogs.io/img/screenshots/2.png)|![Commits History](https://gogs.io/img/screenshots/3.png)|
|![Profile](https://gogs.io/img/screenshots/4.png)|![Admin Dashboard](https://gogs.io/img/screenshots/5.png)|![Diff](https://gogs.io/img/screenshots/6.png)|
|![Issues](https://gogs.io/img/screenshots/7.png)|![Releases](https://gogs.io/img/screenshots/8.png)|![Organization](https://gogs.io/img/screenshots/9.png)|
### NOTICES
@@ -45,7 +33,7 @@ The goal of this project is to make the easiest, fastest, and most painless way
- Please see the [Documentation](http://gogs.io/docs/intro) for common usages and change log.
- See the [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs) or go down to the **Installation -> Install from binary** section!
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs)!
- Having trouble? Get help with [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html).
- Want to help with localization? Check out the [guide](http://gogs.io/docs/features/i18n.html)!
@@ -63,7 +51,6 @@ The goal of this project is to make the easiest, fastest, and most painless way
- Gravatar and custom source
- Mail service
- Administration panel
- CI integration: [Drone](https://github.com/drone/drone)
- Supports MySQL, PostgreSQL, SQLite3 and [TiDB](https://github.com/pingcap/tidb) (experimental)
- Multi-language support ([14 languages](https://crowdin.com/project/gogs))
@@ -109,6 +96,13 @@ There are 5 ways to install Gogs:
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
- [Portal](https://portaldemo.xyz/cloud/)
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
## Software and Service Support
- [Drone](https://github.com/drone/drone) (CI)
- [Fabric8](http://fabric8.io/) (DevOps)
- [Taiga](https://taiga.io/) (Project Management)
### Product Support

View File

@@ -29,7 +29,6 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 支持 Gravatar 以及自定义源
- 支持邮件服务
- 支持后台管理面板
- 支持 CI 集成:[Drone](https://github.com/drone/drone)
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([14 种语言]([more](https://crowdin.com/project/gogs))
@@ -67,6 +66,13 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
- [Portal](https://portaldemo.xyz/cloud/)
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
## 软件及服务支持
- [Drone](https://github.com/drone/drone)CI
- [Fabric8](http://fabric8.io/)DevOps
- [Taiga](https://taiga.io/)(项目管理)
### 产品支持

View File

@@ -11,6 +11,8 @@ import (
"path"
"time"
"io/ioutil"
"github.com/Unknwon/cae/zip"
"github.com/codegangsta/cli"
@@ -38,16 +40,23 @@ func runDump(ctx *cli.Context) {
models.LoadConfigs()
models.SetEngine()
TmpWorkDir, err := ioutil.TempDir(os.TempDir(), "gogs-dump-")
if err != nil {
log.Fatalf("Fail to create tmp work directory: %v", err)
}
log.Printf("Creating tmp work dir: %s", TmpWorkDir)
reposDump := path.Join(TmpWorkDir, "gogs-repo.zip")
dbDump := path.Join(TmpWorkDir, "gogs-db.sql")
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
zip.Verbose = ctx.Bool("verbose")
defer os.Remove("gogs-repo.zip")
if err := zip.PackTo(setting.RepoRootPath, "gogs-repo.zip", true); err != nil {
if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
log.Fatalf("Fail to dump local repositories: %v", err)
}
log.Printf("Dumping database...")
defer os.Remove("gogs-db.sql")
if err := models.DumpDatabase("gogs-db.sql"); err != nil {
if err := models.DumpDatabase(dbDump); err != nil {
log.Fatalf("Fail to dump database: %v", err)
}
@@ -59,16 +68,30 @@ func runDump(ctx *cli.Context) {
log.Fatalf("Fail to create %s: %v", fileName, err)
}
workDir, _ := setting.WorkDir()
z.AddFile("gogs-repo.zip", path.Join(workDir, "gogs-repo.zip"))
z.AddFile("gogs-db.sql", path.Join(workDir, "gogs-db.sql"))
z.AddDir("custom", path.Join(workDir, "custom"))
z.AddDir("log", path.Join(workDir, "log"))
if err := z.AddFile("gogs-repo.zip", reposDump); err !=nil {
log.Fatalf("Fail to include gogs-repo.zip: %v", err)
}
if err := z.AddFile("gogs-db.sql", dbDump); err !=nil {
log.Fatalf("Fail to include gogs-db.sql: %v", err)
}
customDir, err := os.Stat(setting.CustomPath)
if err == nil && customDir.IsDir() {
if err := z.AddDir("custom", setting.CustomPath); err !=nil {
log.Fatalf("Fail to include custom: %v", err)
}
} else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
if err := z.AddDir("log", setting.LogRootPath); err !=nil {
log.Fatalf("Fail to include log: %v", err)
}
// FIXME: SSH key file.
if err = z.Close(); err != nil {
os.Remove(fileName)
log.Fatalf("Fail to save %s: %v", fileName, err)
}
log.Println("Finish dumping!")
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
os.RemoveAll(TmpWorkDir)
log.Printf("Finish dumping in file %s", fileName)
}

View File

@@ -77,7 +77,7 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if len(logMessage) > 0 {
if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage, args...)
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
log.GitLogger.Fatal(3, logMessage, args...)
return
@@ -87,7 +87,7 @@ func fail(userMessage, logMessage string, args ...interface{}) {
os.Exit(1)
}
func handleUpdateTask(uuid string, user *models.User, repoUserName, repoName string) {
func handleUpdateTask(uuid string, user *models.User, username, reponame string, isWiki bool) {
task, err := models.GetUpdateTaskByUUID(uuid)
if err != nil {
if models.IsErrUpdateTaskNotExist(err) {
@@ -95,19 +95,21 @@ func handleUpdateTask(uuid string, user *models.User, repoUserName, repoName str
return
}
log.GitLogger.Fatal(2, "GetUpdateTaskByUUID: %v", err)
}
if err = models.Update(task.RefName, task.OldCommitID, task.NewCommitID,
user.Name, repoUserName, repoName, user.Id); err != nil {
log.GitLogger.Error(2, "Update: %v", err)
}
if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
} else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
log.GitLogger.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
}
if isWiki {
return
}
if err = models.Update(task.RefName, task.OldCommitID, task.NewCommitID,
user.Name, username, reponame, user.Id); err != nil {
log.GitLogger.Error(2, "Update: %v", err)
}
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.AppUrl + repoUserName + "/" + repoName + "/tasks/trigger?branch=" +
reqURL := setting.AppUrl + username + "/" + reponame + "/tasks/trigger?branch=" +
strings.TrimPrefix(task.RefName, "refs/heads/")
log.GitLogger.Trace("Trigger task: %s", reqURL)
@@ -147,21 +149,27 @@ func runServ(c *cli.Context) {
if len(rr) != 2 {
fail("Invalid repository path", "Invalid repository path: %v", args)
}
repoUserName := strings.ToLower(rr[0])
repoName := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
repoUser, err := models.GetUserByName(repoUserName)
if err != nil {
if models.IsErrUserNotExist(err) {
fail("Repository owner does not exist", "Unregistered owner: %s", repoUserName)
}
fail("Internal error", "Failed to get repository owner(%s): %v", repoUserName, err)
isWiki := false
if strings.HasSuffix(reponame, ".wiki") {
isWiki = true
reponame = reponame[:len(reponame)-5]
}
repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
repoUser, err := models.GetUserByName(username)
if err != nil {
if models.IsErrUserNotExist(err) {
fail("Repository owner does not exist", "Unregistered owner: %s", username)
}
fail("Internal error", "Failed to get repository owner(%s): %v", username, err)
}
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
if err != nil {
if models.IsErrRepoNotExist(err) {
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, repoName)
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, reponame)
}
fail("Internal error", "Failed to get repository: %v", err)
}
@@ -258,7 +266,7 @@ func runServ(c *cli.Context) {
}
if requestedMode == models.ACCESS_MODE_WRITE {
handleUpdateTask(uuid, user, repoUserName, repoName)
handleUpdateTask(uuid, user, username, reponame, isWiki)
}
// Update user key activity.

View File

@@ -29,11 +29,8 @@ import (
"gopkg.in/ini.v1"
"gopkg.in/macaron.v1"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/auth/apiv1"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/log"
@@ -42,7 +39,7 @@ import (
"github.com/gogits/gogs/modules/template"
"github.com/gogits/gogs/routers"
"github.com/gogits/gogs/routers/admin"
"github.com/gogits/gogs/routers/api/v1"
apiv1 "github.com/gogits/gogs/routers/api/v1"
"github.com/gogits/gogs/routers/dev"
"github.com/gogits/gogs/routers/org"
"github.com/gogits/gogs/routers/repo"
@@ -85,7 +82,7 @@ func checkVersion() {
{"github.com/go-macaron/binding", binding.Version, "0.1.0"},
{"github.com/go-macaron/cache", cache.Version, "0.1.2"},
{"github.com/go-macaron/csrf", csrf.Version, "0.0.3"},
{"github.com/go-macaron/i18n", i18n.Version, "0.0.7"},
{"github.com/go-macaron/i18n", i18n.Version, "0.2.0"},
{"github.com/go-macaron/session", session.Version, "0.1.6"},
{"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"},
{"gopkg.in/ini.v1", ini.Version, "1.3.4"},
@@ -143,6 +140,7 @@ func newMacaron() *macaron.Macaron {
CustomDirectory: path.Join(setting.CustomPath, "conf/locale"),
Langs: setting.Langs,
Names: setting.Names,
DefaultLang: "en-US",
Redirect: true,
}))
m.Use(cache.Cacher(cache.Options{
@@ -186,7 +184,6 @@ func runWeb(ctx *cli.Context) {
ignSignInAndCsrf := middleware.Toggle(&middleware.ToggleOptions{DisableCsrf: true})
reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true})
bind := binding.Bind
bindIgnErr := binding.BindIgnErr
// Routers.
@@ -197,61 +194,8 @@ func runWeb(ctx *cli.Context) {
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
// ***** START: API *****
// FIXME: custom form error response.
m.Group("/api", func() {
m.Group("/v1", func() {
// Miscellaneous.
m.Post("/markdown", bindIgnErr(apiv1.MarkdownForm{}), v1.Markdown)
m.Post("/markdown/raw", v1.MarkdownRaw)
// Users.
m.Group("/users", func() {
m.Get("/search", v1.SearchUsers)
m.Group("/:username", func() {
m.Get("", v1.GetUserInfo)
m.Group("/tokens", func() {
m.Combo("").Get(v1.ListAccessTokens).
Post(bind(v1.CreateAccessTokenForm{}), v1.CreateAccessToken)
}, middleware.ApiReqBasicAuth())
})
})
// Repositories.
m.Combo("/user/repos", middleware.ApiReqToken()).Get(v1.ListMyRepos).
Post(bind(api.CreateRepoOption{}), v1.CreateRepo)
m.Post("/org/:org/repos", middleware.ApiReqToken(), bind(api.CreateRepoOption{}), v1.CreateOrgRepo)
m.Group("/repos", func() {
m.Get("/search", v1.SearchRepos)
})
m.Group("/repos", func() {
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.MigrateRepo)
m.Combo("/:username/:reponame").Get(v1.GetRepo).
Delete(v1.DeleteRepo)
m.Group("/:username/:reponame", func() {
m.Combo("/hooks").Get(v1.ListRepoHooks).
Post(bind(api.CreateHookOption{}), v1.CreateRepoHook)
m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), v1.EditRepoHook)
m.Get("/raw/*", middleware.RepoRef(), v1.GetRepoRawFile)
m.Get("/archive/*", v1.GetRepoArchive)
m.Group("/keys", func() {
m.Combo("").Get(v1.ListRepoDeployKeys).
Post(bind(api.CreateDeployKeyOption{}), v1.CreateRepoDeployKey)
m.Combo("/:id").Get(v1.GetRepoDeployKey).
Delete(v1.DeleteRepoDeploykey)
})
}, middleware.ApiRepoAssignment())
}, middleware.ApiReqToken())
m.Any("/*", func(ctx *middleware.Context) {
ctx.Error(404)
})
})
apiv1.RegisterRoutes(m)
}, ignSignIn)
// ***** END: API *****
@@ -323,7 +267,8 @@ func runWeb(ctx *cli.Context) {
})
m.Group("/repos", func() {
m.Get("", admin.Repositories)
m.Get("", admin.Repos)
m.Post("/delete", admin.DeleteRepo)
})
m.Group("/auths", func() {
@@ -337,7 +282,8 @@ func runWeb(ctx *cli.Context) {
m.Group("/notices", func() {
m.Get("", admin.Notices)
m.Get("/:id:int/delete", admin.DeleteNotice)
m.Post("/delete", admin.DeleteNotices)
m.Get("/empty", admin.EmptyNotices)
})
}, adminReq)
// ***** END: Admin *****
@@ -378,6 +324,7 @@ func runWeb(ctx *cli.Context) {
}
reqRepoAdmin := middleware.RequireRepoAdmin()
reqRepoPusher := middleware.RequireRepoPusher()
// ***** START: Organization *****
m.Group("/org", func() {
@@ -451,6 +398,7 @@ func runWeb(ctx *cli.Context) {
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/:id/test", repo.TestWebhook)
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
@@ -470,13 +418,13 @@ func runWeb(ctx *cli.Context) {
}, func(ctx *middleware.Context) {
ctx.Data["PageIsSettings"] = true
})
}, reqSignIn, middleware.RepoAssignment(true), reqRepoAdmin, middleware.RepoRef())
}, reqSignIn, middleware.RepoAssignment(), reqRepoAdmin, middleware.RepoRef())
m.Group("/:username/:reponame", func() {
m.Get("/action/:action", repo.Action)
m.Group("/issues", func() {
m.Combo("/new").Get(repo.NewIssue).
m.Combo("/new", repo.MustEnableIssues).Get(middleware.RepoRef(), repo.NewIssue).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
@@ -496,15 +444,15 @@ func runWeb(ctx *cli.Context) {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
}, reqRepoAdmin)
}, reqRepoAdmin, middleware.RepoRef())
m.Group("/milestones", func() {
m.Get("/new", repo.NewMilestone)
m.Post("/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
m.Get("/:id/edit", repo.EditMilestone)
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Get("/:id/:action", repo.ChangeMilestonStatus)
m.Post("/delete", repo.DeleteMilestone)
}, reqRepoAdmin)
}, reqRepoAdmin, middleware.RepoRef())
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
@@ -514,30 +462,40 @@ func runWeb(ctx *cli.Context) {
m.Post("/delete", repo.DeleteRelease)
}, reqRepoAdmin, middleware.RepoRef())
m.Combo("/compare/*").Get(repo.CompareAndPullRequest).
m.Combo("/compare/*", repo.MustEnablePulls).Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
}, reqSignIn, middleware.RepoAssignment(true))
}, reqSignIn, middleware.RepoAssignment())
m.Group("/:username/:reponame", func() {
m.Group("", func() {
m.Get("/releases", repo.Releases)
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
m.Get("/milestones", repo.Milestones)
}, middleware.RepoRef(),
func(ctx *middleware.Context) {
ctx.Data["PageIsList"] = true
})
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
}, middleware.RepoRef())
// m.Get("/branches", repo.Branches)
m.Group("/wiki", func() {
m.Get("/?:page", repo.Wiki)
m.Get("/_pages", repo.WikiPages)
m.Group("", func() {
m.Combo("/_new").Get(repo.NewWiki).
Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
m.Combo("/:page/_edit").Get(repo.EditWiki).
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
}, reqSignIn, reqRepoPusher)
}, repo.MustEnableWiki, middleware.RepoRef())
m.Get("/branches", repo.Branches)
m.Get("/archive/*", repo.Download)
m.Group("/pulls/:index", func() {
m.Get("/commits", repo.ViewPullCommits)
m.Get("/files", repo.ViewPullFiles)
m.Post("/merge", reqRepoAdmin, repo.MergePullRequest)
})
}, repo.MustEnablePulls)
m.Group("", func() {
m.Get("/src/*", repo.Home)
@@ -550,13 +508,13 @@ func runWeb(ctx *cli.Context) {
}, middleware.RepoRef())
m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff)
}, ignSignIn, middleware.RepoAssignment(true))
}, ignSignIn, middleware.RepoAssignment())
m.Group("/:username", func() {
m.Group("/:reponame", func() {
m.Get("", repo.Home)
m.Get("\\.git$", repo.Home)
}, ignSignIn, middleware.RepoAssignment(true, true), middleware.RepoRef())
}, ignSignIn, middleware.RepoAssignment(true), middleware.RepoRef())
m.Group("/:reponame", func() {
m.Any("/*", ignSignInAndCsrf, repo.HTTP)

View File

@@ -32,7 +32,7 @@ USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 50
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50

View File

@@ -20,10 +20,11 @@ Luc Stepniewski <luc AT stepniewski DOT fr>
Marc Schiller <marc AT schiller DOT im>
Miguel de la Cruz <miguel AT mcrx DOT me>
Morten Sørensen <klim8d AT gmail DOT com>
Nakao Takamasa <at.mattenn AT gmail DOT com>
Natan Albuquerque <natanalbuquerque5 AT gmail DOT com>
Odilon Junior <odilon DOT junior93 AT gmail DOT com>
Thomas Fanninger <gogs DOT thomas AT fanninger DOT at>
Tilmann Bach <tilmann AT outlook DOT com>
Vladimir Vissoultchev <wqweto AT gmail DOT com>
YJSoft <yjsoft AT yjsoft DOT pe DOT kr>
Łukasz Jan Niemier <lukasz AT niemier DOT pl>
Łukasz Jan Niemier <lukasz AT niemier DOT pl>

View File

@@ -4,10 +4,10 @@ home=Начало
dashboard=Табло
explore=Преглед
help=Помощ
sign_in=Влизане
sign_in=Вписване
sign_out=Излизане
sign_up=Регистрирайте се
register=Регистриране
register=Регистрация
website=Уебсайт
version=Версия
page=Страница
@@ -375,11 +375,11 @@ copy_link=Копирай
copy_link_success=Копирано!
copy_link_error=Натиснете ⌘-C или Ctrl-C за да копирате
copied=Успешно копиране
unwatch=Не следи
watch=Следи
unwatch=Не наблюдавам
watch=Наблюдаван
unstar=Не харесвам
star=Харесвам
fork=Разклонение
star=Харесван
fork=Разклонения
no_desc=Няма описание
quick_guide=Бърз справочник
@@ -388,6 +388,7 @@ create_new_repo_command=Създай ново хранилище чрез ком
push_exist_repo=Предай съществуващо хранилище през командния ред
repo_is_empty=Това хранилище е празно. Моля проверете по-късно пак!
code=Code
branch=Клон
tree=ИН на ревизия
filter_branch_and_tag=Филтър по маркер или клон
@@ -399,9 +400,9 @@ labels=Етикети
milestones=Етапи
commits=Ревизии
releases=Издания
file_raw=Изходен файл
file_raw=Директен файл
file_history=История
file_view_raw=Виж изходен файл
file_view_raw=Виж директен файл
file_permalink=Постоянна връзка
commits.commits=Ревизии
@@ -535,16 +536,39 @@ milestones.deletion=Изтрий етап
milestones.deletion_desc=При изтриване на етап ще се премахне информацията за него от всички свързани проблеми. Желаете ли да продължите?
milestones.deletion_success=Етапът е изтрит успешно!
wiki=Уики
wiki.welcome=Добре дошли в Уики!
wiki.welcome_desc=Уики е място, където заедно можете да документирате проекта си, за да го направите по-добър.
wiki.create_first_page=Създай първата страница
wiki.page=Страница
wiki.filter_page=Филтър страница
wiki.new_page=Създай нова страница
wiki.default_commit_message=Напишете описание на тази модификация (опционално).
wiki.save_page=Запис на страница
wiki.last_commit_info=%s редактира тази страница %s
wiki.edit_page_button=Редакция
wiki.new_page_button=Нова страница
wiki.page_already_exists=Страница със същото име вече съществува.
wiki.pages=Страници
wiki.last_updated=Последна модификация на %s
settings=Настройки
settings.options=Опции
settings.collaboration=Сътрудничество
settings.hooks=Уеб-куки
settings.githooks=Git куки
settings.basic_settings=Основни настройки
settings.danger_zone=Опасна зона
settings.site=Официален сайт
settings.update_settings=Обнови настройките
settings.change_reponame_prompt=Тази промяна ще засегне връзките, които се отнасят до това хранилището.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Опасна зона
settings.transfer=Прехвърли притежание
settings.transfer_desc=Прехвърля това хранилище на друг потребител или към организация, в която имате права на администратор.
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Тази операция ще изтрие всич
settings.delete_notices_fork_1=- Ако това хранилище е публично, всички негови разклонения ще останат независими след изтриването му.
settings.delete_notices_fork_2=- Ако това хранилище е частно, всички негови разклонения ще бъдат премахнати по време на изтриването.
settings.delete_notices_fork_3=- Ако желаете да запазите всички разклонения след изтриването му, първо направете хранилището публично.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Настройките на хранилището са запазени успешно.
settings.transfer_owner=Нов притежател
settings.make_transfer=Прехвърли
@@ -573,6 +598,9 @@ settings.hooks_desc=Уеб-куките много приличат на оби
settings.webhook_deletion=Изтрий уеб-кука
settings.webhook_deletion_desc=При изтриване на тази уеб-кука ще се премахне информацията за нея и цялата хронология на нейното изпращане. Желаете ли да продължите?
settings.webhook_deletion_success=Уеб-куката е изтрита успешно!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Заявка
settings.webhook.response=Отговор
settings.webhook.headers=Заглавки
@@ -612,6 +640,7 @@ settings.slack_domain=Домейн
settings.slack_channel=Канал
settings.deploy_keys=Ключове за внедряване
settings.add_deploy_key=Добави ключ за внедряване
settings.deploy_key_desc=Този ключ за внедряване има права само за четене. Това не е същото като SSH ключове на персонален потребител.
settings.no_deploy_keys=Все още няма настроен никакъв ключ за внедряване.
settings.title=Заглавие
settings.deploy_key_content=Съдържание
@@ -622,14 +651,14 @@ settings.deploy_key_deletion=Изтрий ключ за внедряване
settings.deploy_key_deletion_desc=При изтриването на този ключ за внедряване ще се премахнат свързаните права за достъп до това хранилище. Желаете ли да продължите?
settings.deploy_key_deletion_success=Ключът за внедряване е изтрит успешно!
diff.browse_source=Всички файлове в ревизията
diff.browse_source=Преглед на файлове
diff.parent=родител
diff.commit=ревизия
diff.data_not_available=Няма данни за разлики.
diff.show_diff_stats=Покажи статистика за разликите
diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда
diff.bin=BIN
diff.view_file=Преглед на файла
diff.view_file=Целия файл
release.releases=Издания
release.new_release=Ново издание
@@ -861,6 +890,8 @@ auths.bind_password=Парола за свръзка
auths.bind_password_helper=Внимание: Тази парола се запазва некриптирана. Моля използвайте потребител, който няма административен достъп.
auths.user_base=Базов OU за търсене
auths.user_dn=Име (DN) на потребител
auths.attribute_username=Атрибут за име
auths.attribute_username_placeholder=Оставете празно за да използва потребителското име от форма за вписване.
auths.attribute_name=Атрибут за име
auths.attribute_surname=Атрибут за фамилия
auths.attribute_mail=Атрибут за ел. поща
@@ -964,11 +995,18 @@ monitor.start=Начален час
monitor.execute_time=Време за изпълнение
notices.system_notice_list=Системни известия
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Тип
notices.type_1=Хранилище
notices.desc=Описание
notices.op=Oп.
notices.delete_success=Системното съобщение е изтрито успешно.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=създаде хранилище <a href="%s"> %s</a>

View File

@@ -388,6 +388,7 @@ create_new_repo_command=Erstelle eine neue Repository mittels Kommandozeile
push_exist_repo=Übertrage eine existierende Repository von der Kommandozeile
repo_is_empty=Das Repository ist leer, bitte komm später wieder!
code=Code
branch=Branch
tree=Struktur
filter_branch_and_tag=Nach Zweig oder Tag filtern
@@ -535,16 +536,39 @@ milestones.deletion=Meilenstein löschen
milestones.deletion_desc=Das Löschen dieses Meilensteins wird alle zugehörigen Informationen in allen Issues entfernen. Wirklich fortfahren?
milestones.deletion_success=Meilenstein erfolgreich gelöscht!
wiki=Wiki
wiki.welcome=Willkommen im Wiki!
wiki.welcome_desc=Das Wiki ist der Ort, wo du zusammen dein Projekt dokumentieren und es besser machen kannst.
wiki.create_first_page=Erstelle die erste Seite
wiki.page=Seite
wiki.filter_page=Seite filtern
wiki.new_page=Neue Seite erstellen
wiki.default_commit_message=Schreibe eine Notiz zu dieser Aktualisierung (optional).
wiki.save_page=Seite speichern
wiki.last_commit_info=%s hat diese Seite bearbeitet %s
wiki.edit_page_button=Bearbeiten
wiki.new_page_button=Neue Seite
wiki.page_already_exists=Eine Wiki-Seite mit dem gleichen Namen existiert bereits.
wiki.pages=Seiten
wiki.last_updated=Zuletzt aktualisiert %s
settings=Einstellungen
settings.options=Optionen
settings.collaboration=Zusammenarbeit
settings.hooks=Webhooks
settings.githooks=Git-Hooks
settings.basic_settings=Grundeinstellungen
settings.danger_zone=Gefahrenzone
settings.site=Offizielle Webseite
settings.update_settings=Einstellungen speichern
settings.change_reponame_prompt=Diese Änderung wirkt sich darauf aus, wie sich Links auf Repositories beziehen.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Gefahrenzone
settings.transfer=Besitz übertragen
settings.transfer_desc=Übertrage diese Repository auf einen anderen Benutzer oder eine Organisation in der du Admin-Rechte hast.
settings.new_owner_has_same_repo=Der neue Eigentümer hat bereits ein Repository mit dem gleichen Namen.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Die Operation wird alles, was mit dieser Git-Reposit
settings.delete_notices_fork_1=- Wenn dies eine öffentliche Repository ist, werden nach der Löschung alle Forks unabhängig.
settings.delete_notices_fork_2=- Wenn dies eine private Repository ist, dann werden gleichzeitig alle Forks entfernt.
settings.delete_notices_fork_3=Wenn alle Forks erhalten bleiben sollen, dann muss zuerst die Sichtbarkeit der Repository auf öffentlich gesetzt werden.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Repository-Optionen aktualisiert.
settings.transfer_owner=Neuer Besitzer
settings.make_transfer=übertragen
@@ -573,6 +598,9 @@ settings.hooks_desc=Webhooks erlauben es dir, externe Dienste zu informieren, we
settings.webhook_deletion=Webhook entfernen
settings.webhook_deletion_desc=Das Löschen dieses Webhooks wird alle zugehörigen Informationen und den Übertragungsverlauf entfernen. Wirklich fortfahren?
settings.webhook_deletion_success=Webhook wurde erfolgreich entfernt!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Anfrage
settings.webhook.response=Rückmeldung
settings.webhook.headers=Kopfzeilen
@@ -612,6 +640,7 @@ settings.slack_domain=Domain
settings.slack_channel=Kanal
settings.deploy_keys=Deploy-Keys
settings.add_deploy_key=Deploy-Key hinzufügen
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=Du hast noch keine Deploy-Schlüssel hinzugefügt.
settings.title=Titel
settings.deploy_key_content=Inhalt
@@ -861,6 +890,8 @@ auths.bind_password=Passwort binden
auths.bind_password_helper=Warnung: Das Passwort wird im Klartext gespeichert. Benutze keinen Account mit hohen Zugriffsrechten.
auths.user_base=Benutzer-Such-Basis
auths.user_dn=Benutzer DN
auths.attribute_username=Attribute des Benutzernamens
auths.attribute_username_placeholder=Leer lassen, um den Wert aus dem Login-Formular als Benutzername zu verwenden.
auths.attribute_name=Vorname Attribut
auths.attribute_surname=Nachname Attribut
auths.attribute_mail=E-Mail Attribut
@@ -964,11 +995,18 @@ monitor.start=Startzeit
monitor.execute_time=Ausführungszeit
notices.system_notice_list=System-Mitteilungen
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Typ
notices.type_1=Repository
notices.desc=Beschreibung
notices.op=Op.
notices.delete_success=System-Mitteilung erfolgreich gelöscht.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=hat Repository <a href="%s">%s</a> erstellt

View File

@@ -18,7 +18,7 @@ user_profile_and_more = User profile and more
signed_in_as = Signed in as
username = Username
email = E-mail
email = Email
password = Password
re_type = Re-Type
captcha = Captcha
@@ -84,14 +84,14 @@ ssh_port_helper = Port number which your SSH server is using, leave it empty to
http_port = HTTP Port
http_port_helper = Port number which application will listen on.
app_url = Application URL
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail.
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in email.
optional_title = Optional Settings
email_title = E-mail Service Settings
email_title = Email Service Settings
smtp_host = SMTP Host
smtp_from = From
smtp_from_helper = Mail from address, RFC 5322. It can be just an email address, or the "Name" <email@example.com> format.
mailer_user = Sender E-mail
mailer_user = Sender Email
mailer_password = Sender Password
register_confirm = Enable Register Confirmation
mail_notify = Enable Mail Notification
@@ -111,7 +111,7 @@ admin_title = Admin Account Settings
admin_name = Username
admin_password = Password
confirm_password = Confirm Password
admin_email = Admin E-mail
admin_email = Admin Email
install_gogs = Install Gogs
test_git_failed = Fail to test 'git' command: %v
sqlite3_not_available = Your release version does not support SQLite3, please download the official binary version from %s, NOT the gobuild version.
@@ -123,7 +123,7 @@ invalid_admin_setting = Admin account setting is invalid: %v
install_success = Welcome! We're glad that you chose Gogs, have fun and take care.
[home]
uname_holder = Username or E-mail
uname_holder = Username or email
password_holder = Password
switch_dashboard_context = Switch Dashboard Context
my_repos = My Repositories
@@ -147,13 +147,13 @@ remember_me = Remember Me
forgot_password= Forgot Password
forget_password = Forgot password?
sign_up_now = Need an account? Sign up now.
confirmation_mail_sent_prompt = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the registration process.
confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the registration process.
active_your_account = Activate Your Account
resent_limit_prompt = Sorry, you already requested an activation email recently. Please wait 3 minutes then try again.
has_unconfirmed_mail = Hi %s, you have an unconfirmed e-mail address (<b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below.
resend_mail = Click here to resend your activation e-mail
email_not_associate = This e-mail address is not associated with any account.
send_reset_mail = Click here to (re)send your password reset e-mail
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
resend_mail = Click here to resend your activation email
email_not_associate = This email address is not associated with any account.
send_reset_mail = Click here to (re)send your password reset email
reset_password = Reset Your Password
invalid_code = Sorry, your confirmation code has expired or not valid.
reset_password_helper = Click here to reset your password
@@ -161,9 +161,9 @@ password_too_short = Password length cannot be less then 6.
[mail]
activate_account = Please activate your account
activate_email = Verify your e-mail address
activate_email = Verify your email address
reset_password = Reset your password
register_success = Register success, Welcome
register_success = Registration successful, welcome
register_notify = Welcome on board
[modal]
@@ -174,7 +174,7 @@ modify = Modify
[form]
UserName = Username
RepoName = Repository name
Email = E-mail address
Email = Email address
Password = Password
Retype = Re-type password
SSHTitle = SSH key name
@@ -182,7 +182,7 @@ HttpsUrl = HTTPS URL
PayloadUrl = Payload URL
TeamName = Team name
AuthName = Authorization name
AdminEmail = Admin E-mail
AdminEmail = Admin email
require_error = ` cannot be empty.`
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
@@ -190,18 +190,18 @@ alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot chara
size_error = ` must be size %s.`
min_size_error = ` must contain at least %s characters.`
max_size_error = ` must contain at most %s characters.`
email_error = ` is not a valid e-mail address.`
email_error = ` is not a valid email address.`
url_error = ` is not a valid URL.`
include_error = ` must contain substring '%s'.`
unknown_error = Unknown error:
captcha_incorrect = Captcha didn't match.
password_not_match = Password and confirm password are not same.
username_been_taken = Username has been already taken.
repo_name_been_taken = Repository name has been already taken.
org_name_been_taken = Organization name has been already taken.
team_name_been_taken = Team name has been already taken.
email_been_used = E-mail address has been already used.
username_been_taken = Username has already been taken.
repo_name_been_taken = Repository name has already been taken.
org_name_been_taken = Organization name has already been taken.
team_name_been_taken = Team name has already been taken.
email_been_used = Email address has already been used.
illegal_team_name = Team name contains illegal characters.
username_password_incorrect = Username or password is not correct.
enterred_invalid_repo_name = Please make sure that the repository name you entered is correct.
@@ -218,7 +218,7 @@ still_own_repo = Your account still has ownership over at least one repository,
still_has_org = Your account still has membership in at least one organization, you have to leave or delete your memberships first.
org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first.
still_own_user = This authentication still is in use by at least one user, please remove them from the authentication and try again.
still_own_user = This authentication is still in use by at least one user, please remove them from the authentication and try again.
target_branch_not_exist = Target branch does not exist.
@@ -246,7 +246,7 @@ delete = Delete Account
uid = Uid
public_profile = Public Profile
profile_desc = Your E-mail address is public and will be used for any account related notifications, and any web based operations made via the site.
profile_desc = Your email address is public and will be used for any account related notifications, and any web based operations made via the site.
full_name = Full Name
website = Website
location = Location
@@ -272,19 +272,19 @@ retype_new_password = Retype New Password
password_incorrect = Current password is not correct.
change_password_success = Your password was successfully changed. You can now sign using this new password.
emails = E-mail Addresses
manage_emails = Manage e-mail addresses
email_desc = Your primary e-mail address will be used for notifications and other operations.
emails = Email Addresses
manage_emails = Manage email addresses
email_desc = Your primary email address will be used for notifications and other operations.
primary = Primary
primary_email = Set as primary
delete_email = Delete
email_deletion = E-mail Deletion
email_deletion_desc = Delete this e-mail address will remove related information from your account. Do you want to continue?
email_deletion_success = E-mail has been deleted successfully!
add_new_email = Add new e-mail address
add_email = Add e-mail
add_email_confirmation_sent = A new confirmation e-mail has been sent to '%s', please check your inbox within the next %d hours to complete the confirmation process.
add_email_success = Your new E-mail address was successfully added.
email_deletion = Email Deletion
email_deletion_desc = Deleting this email address will remove related information from your account. Do you want to continue?
email_deletion_success = Email has been deleted successfully!
add_new_email = Add new email address
add_email = Add email
add_email_confirmation_sent = A new confirmation email has been sent to '%s', please check your inbox within the next %d hours to complete the confirmation process.
add_email_success = Your new email address was successfully added.
manage_ssh_keys = Manage SSH Keys
add_key = Add Key
@@ -370,7 +370,7 @@ migrate.invalid_local_path = Invalid local path, it does not exist or not a dire
migrate.failed = Migration failed: %v
forked_from = forked from
fork_from_self = You cannot fork repository you already owned!
fork_from_self = You cannot fork a repository you already own!
copy_link = Copy
copy_link_success = Copied!
copy_link_error = Press ⌘-C or Ctrl-C to copy
@@ -388,6 +388,7 @@ create_new_repo_command = Create a new repository on the command line
push_exist_repo = Push an existing repository from the command line
repo_is_empty = This repository is empty, please come back later!
code = Code
branch = Branch
tree = Tree
filter_branch_and_tag = Filter branch or tag
@@ -482,7 +483,7 @@ issues.label_edit = Edit
issues.label_delete = Delete
issues.label_modify = Label Modification
issues.label_deletion = Label Deletion
issues.label_deletion_desc = Delete this label will remove its information in all related issues. Do you want to continue?
issues.label_deletion_desc = Deleting this label will remove its information in all related issues. Do you want to continue?
issues.label_deletion_success = Label has been deleted successfully!
pulls.new = New Pull Request
@@ -527,24 +528,47 @@ milestones.clear = Clear
milestones.invalid_due_date_format = Due date format is invalid, must be 'yyyy-mm-dd'.
milestones.create_success = Milestone '%s' has been created successfully!
milestones.edit = Edit Milestone
milestones.edit_subheader = Use better description for milestones so people won't be confused.
milestones.edit_subheader = Use a better description for milestones so people won't be confused.
milestones.cancel = Cancel
milestones.modify = Modify Milestone
milestones.edit_success = Changes of milestone '%s' has been saved successfully!
milestones.deletion = Milestone Deletion
milestones.deletion_desc = Delete this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_desc = Deleting this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_success = Milestone has been deleted successfully!
wiki = Wiki
wiki.welcome = Welcome to Wiki!
wiki.welcome_desc = Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page = Create the first page
wiki.page = Page
wiki.filter_page = Filter page
wiki.new_page = Create New Page
wiki.default_commit_message = Write a note about this update (optional).
wiki.save_page = Save Page
wiki.last_commit_info = %s edited this page %s
wiki.edit_page_button = Edit
wiki.new_page_button = New Page
wiki.page_already_exists = Wiki page with same name already exists.
wiki.pages = Pages
wiki.last_updated = Last updated %s
settings = Settings
settings.options = Options
settings.collaboration = Collaboration
settings.hooks = Webhooks
settings.githooks = Git Hooks
settings.basic_settings = Basic Settings
settings.danger_zone = Danger Zone
settings.site = Official Site
settings.update_settings = Update Settings
settings.change_reponame_prompt = This change will affect how links relate to the repository.
settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable wiki to allow people write documents
settings.issues_desc = Enable builtin lightweight issue tracker
settings.use_external_issue_tracker = Use external issue tracker
settings.tracker_url_format = External Issue Tracker URL Format
settings.tracker_url_format_desc = You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc = Enable pull requests to accept public contributions
settings.danger_zone = Danger Zone
settings.transfer = Transfer Ownership
settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights.
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
@@ -558,6 +582,7 @@ settings.delete_notices_2 = - This operation will permanently delete the everyth
settings.delete_notices_fork_1 = - If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2 = - If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3 = - If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success = Repository has been deleted successfully!
settings.update_settings_success = Repository options has been updated successfully.
settings.transfer_owner = New Owner
settings.make_transfer = Make Transfer
@@ -573,6 +598,9 @@ settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whe
settings.webhook_deletion = Delete Webhook
settings.webhook_deletion_desc = Delete this webhook will remove its information and all delivery history. Do you want to continue?
settings.webhook_deletion_success = Webhook has been deleted successfully!
settings.webhook.test_delivery = Test Delivery
settings.webhook.test_delivery_desc = Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success = Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request = Request
settings.webhook.response = Response
settings.webhook.headers = Headers
@@ -617,10 +645,10 @@ settings.no_deploy_keys = You haven't added any deploy key.
settings.title = Title
settings.deploy_key_content = Content
settings.key_been_used = Deploy key content has been used.
settings.key_name_used = Deploy key with same name has already existed.
settings.key_name_used = Deploy key with the same name already exists.
settings.add_key_success = New deploy key '%s' has been added successfully!
settings.deploy_key_deletion = Delete Deploy Key
settings.deploy_key_deletion_desc = Delete this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_desc = Deleting this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_success = Deploy key has been deleted successfully!
diff.browse_source = Browse Source
@@ -651,16 +679,16 @@ release.write = Write
release.preview = Preview
release.loading = Loading...
release.prerelease_desc = This is a pre-release
release.prerelease_helper = Well point out that this release is not production-ready.
release.prerelease_helper = We'll point out that this release is not production-ready.
release.cancel = Cancel
release.publish = Publish Release
release.save_draft = Save Draft
release.edit_release = Edit Release
release.delete_release = Delete This Release
release.deletion = Release Deletion
release.deletion_desc = Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_desc = Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success = Release has been deleted successfully!
release.tag_name_already_exist = Release with this tag name has already existed.
release.tag_name_already_exist = Release with this tag name already exists.
release.downloads = Downloads
[org]
@@ -862,9 +890,11 @@ auths.bind_password = Bind Password
auths.bind_password_helper = Warning: This password is stored in plain text. Do not use a high privileged account.
auths.user_base = User Search Base
auths.user_dn = User DN
auths.attribute_username = Username attribute
auths.attribute_username_placeholder = Leave empty to use sign-in form field value for user name.
auths.attribute_name = First name attribute
auths.attribute_surname = Surname attribute
auths.attribute_mail = E-mail attribute
auths.attribute_mail = Email attribute
auths.filter = User Filter
auths.admin_filter = Admin Filter
auths.ms_ad_sa = Ms Ad SA
@@ -912,7 +942,7 @@ config.db_ssl_mode_helper = (for "postgres" only)
config.db_path = Path
config.db_path_helper = (for "sqlite3" and "tidb")
config.service_config = Service Configuration
config.register_email_confirm = Require E-mail Confirmation
config.register_email_confirm = Require Email Confirmation
config.disable_register = Disable Registration
config.show_registration_button = Show Register Button
config.require_sign_in_view = Require Sign In View
@@ -965,11 +995,18 @@ monitor.start = Start Time
monitor.execute_time = Execution Time
notices.system_notice_list = System Notices
notices.view_detail_header = View Notice Detail
notices.actions = Actions
notices.select_all = Select All
notices.deselect_all = Deselect All
notices.inverse_selection = Inverse Selection
notices.delete_selected = Delete Selected
notices.delete_all = Delete All Notices
notices.type = Type
notices.type_1 = Repository
notices.desc = Description
notices.op = Op.
notices.delete_success = System notice has been deleted successfully.
notices.delete_success = System notices have been deleted successfully.
[action]
create_repo = created repository <a href="%s">%s</a>

View File

@@ -192,7 +192,7 @@ min_size_error=` debe contener al menos %s caracteres.`
max_size_error=` debe contener como máximo %s caracteres.`
email_error=` no es una dirección de correo válida.`
url_error=` no es una URL válida.`
include_error='debe contener la subcadena '%s'.'
include_error=` debe contener la subcadena '%s'.`
unknown_error=Error desconocido:
captcha_incorrect=El captcha no es válido.
password_not_match=La contraseña de confirmación no coincide.
@@ -388,6 +388,7 @@ create_new_repo_command=Crear un nuevo repositorio desde línea de comandos
push_exist_repo=Hacer Push de un repositorio existente desde línea de comandos
repo_is_empty=Este repositorio está vacío, por favor, ¡vuelva más tarde!
code=Código
branch=Rama
tree=Árbol
filter_branch_and_tag=Filtrar por rama o etiqueta
@@ -535,16 +536,39 @@ milestones.deletion=Borrar milestone
milestones.deletion_desc=El borrado de este milestone eliminará su información y las incidencias asociadas. ¿Desea continuar?
milestones.deletion_success=¡El milestone ha sido eliminado con éxito!
wiki=Wiki
wiki.welcome=¡Bienvenido a la Wiki!
wiki.welcome_desc=La Wiki es el lugar donde os gustaría documentar juntos vuestro proyecto y hacerlo mejor.
wiki.create_first_page=Crear la primera página
wiki.page=Página
wiki.filter_page=Filtrar página
wiki.new_page=Crear nueva página
wiki.default_commit_message=Escribe una nota sobre esta actualización (opcional).
wiki.save_page=Guardar página
wiki.last_commit_info=%s editó esta página %s
wiki.edit_page_button=Editar
wiki.new_page_button=Nueva página
wiki.page_already_exists=Ya existe una página con el mismo nombre.
wiki.pages=Páginas
wiki.last_updated=Última actualización %s
settings=Configuración
settings.options=Opciones
settings.collaboration=Colaboración
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Configuración Básica
settings.danger_zone=Zona de Peligro
settings.site=Sitio Oficial
settings.update_settings=Actualizar Configuración
settings.change_reponame_prompt=Este cambio afectará a los enlaces al repositorio.
settings.advanced_settings=Ajustes avanzados
settings.wiki_desc=Habilitar a las personas en la Wiki a que puedan escribir documentos
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Zona de Peligro
settings.transfer=Transferir la Propiedad
settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración.
settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con el mismo nombre.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Esta operación eliminará de manera permanente todo
settings.delete_notices_fork_1=- Si este repositorio es público, todos los forks se convertirán en repositorios independientes tras el borrado.
settings.delete_notices_fork_2=- Si este repositorio es privado, todos los forks serán eliminados simultáneamente.
settings.delete_notices_fork_3=- Si desea mantener los forks tras el borrado, por favor convierta este repositorio en público antes de proceder.
settings.deletion_success=¡El respositorio ha sido eliminado satisfactoriamente!
settings.update_settings_success=Las opciones del repositorio se han actualizado correctamente.
settings.transfer_owner=Nuevo Propietario
settings.make_transfer=Transferir
@@ -573,6 +598,9 @@ settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificac
settings.webhook_deletion=Eliminar Webhook
settings.webhook_deletion_desc=Al borrar este webhook se eliminará su información y todo su historial. ¿Desea continuar?
settings.webhook_deletion_success=¡Webhook eliminado con éxito!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Petición
settings.webhook.response=Respuesta
settings.webhook.headers=Encabezado
@@ -612,6 +640,7 @@ settings.slack_domain=Dominio
settings.slack_channel=Canal
settings.deploy_keys=Claves de Despliegue
settings.add_deploy_key=Añadir Clave de Despliegue
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=No has añadido ninguna clave de despliegue.
settings.title=Título
settings.deploy_key_content=Contenido
@@ -861,6 +890,8 @@ auths.bind_password=Contraseña Bind
auths.bind_password_helper=Advertencia: La contraseña se almacena como texto plano. No utilice una cuenta con privilegios elevados.
auths.user_base=Base de Búsqueda de Usuarios
auths.user_dn=DN de Usuario
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Dejar vacío para usar el campo de inicio de sesión como nombre de usuario.
auths.attribute_name=Atributo nombre
auths.attribute_surname=Atributo apellido
auths.attribute_mail=Atributo correo electrónico
@@ -964,11 +995,18 @@ monitor.start=Hora de Inicio
monitor.execute_time=Tiempo de ejecución
notices.system_notice_list=Notificaciones del Sistema
notices.view_detail_header=Ver detalles de la notificación
notices.actions=Acciones
notices.select_all=Sleccionar todo
notices.deselect_all=Deseleccionar todo
notices.inverse_selection=Selección inversa
notices.delete_selected=Eliminar seleccionado
notices.delete_all=Eliminar todas las notificaciones
notices.type=Tipo
notices.type_1=Repositorio
notices.desc=Descripción
notices.op=Op.
notices.delete_success=La notificación del sistema se ha eliminado correctamente.
notices.delete_success=Las notificaciones del sistema han sido eliminadas satisfactoriamente.
[action]
create_repo=repositorio creado <a href="%s">%s</a>
@@ -993,12 +1031,12 @@ now=ahora
1w=%s 1 semana
1mon=%s 1 mes
1y=%s 1 año
seconds=%[2]d %[1]s segundos
minutes=%s %d minutos
hours=%s %d horas
days=%s %d días
weeks=%s %d semanas
months=%s %d meses
seconds=%[2]s %[1]d segundos
minutes=%[2]s %[1]d minutos
hours=%[2]s %[1]d horas
days=%[2]s %[1]d días
weeks=%[2]s %[1]d semanas
months=%[2]s %[1]d meses
years=%s %d años
raw_seconds=segundos
raw_minutes=minutos

View File

@@ -336,11 +336,11 @@ repo_name_helper=Idéalement, le nom d'un dépot devrait être court, mémorable
visibility=Visibilité
visiblity_helper=Ce dépôt est <span class="ui red text"> privé</span>
visiblity_helper_forced=L'administrateur du site a forcé tous les nouveaux dépôts à être <span class="ui red text">privés</span>
visiblity_fork_helper=(Les changement de cette valeur affectera tous les forks)
visiblity_fork_helper=(Les changement de cette valeur affecteront tous les embranchements)
clone_helper=Besoin d'aide pour dupliquer ? Visitez <a target="_blank" href="%s">l'aide</a> !
fork_repo=Scinder le dépôt
fork_from=Embranchement de
fork_visiblity_helper=La visibilité d'un référentiel d'embranchement ne peut pas être modifiée.
fork_from=Scission de
fork_visiblity_helper=Un dépôt scindé ne peut pas changer sa visiblité
repo_desc=Description
repo_lang=Langue
repo_lang_helper=Sélectionnez les fichiers .gitignore
@@ -354,7 +354,7 @@ default_branch=Branche par défaut
mirror_interval=Intervalle du miroir (heure)
watchers=Observateurs
stargazers=Stargazers
forks=Forks
forks=Embranchements
form.name_reserved=Le nom de dépôt '%s' est réservé.
form.name_pattern_not_allowed=Motif '%s' interdit pour les noms de dépôt.
@@ -367,9 +367,9 @@ migrate.clone_address=Adresse du clone
migrate.clone_address_desc=Cela peut être une URL HTTP/HTTPS/GIT ou un chemin d'accès local.
migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts locaux.
migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier.
migrate.failed=Migration failed: %v
migrate.failed=Echec de migration: %v
forked_from=embranché à partir de
forked_from=scindé depuis
fork_from_self=Vous nous ne pouvez pas scinder un dépôt que vous possédez déja !
copy_link=Copier
copy_link_success=Copié!
@@ -388,9 +388,10 @@ create_new_repo_command=Créer un nouveau dépôt en ligne de commande
push_exist_repo=Soumettre un référentiel existant via la ligne de commande
repo_is_empty=Ce référentiel est vide, veuillez revenir plus tard !
code=Code
branch=Branche
tree=Aborescence
filter_branch_and_tag=Filter branch or tag
filter_branch_and_tag=Filtrer une branche ou un tag
branches=Branches
tags=Tags
issues=Problèmes
@@ -404,8 +405,8 @@ file_history=Historique
file_view_raw=Voir le Raw
file_permalink=Lien permanent
commits.commits=Commissions
commits.search=Rechercher des commissions
commits.commits=Commits
commits.search=Rechercher des commits
commits.find=Trouver
commits.author=Auteur
commits.message=Message
@@ -485,7 +486,7 @@ issues.label_deletion=Suppression du Label
issues.label_deletion_desc=Cette opération supprimera également toutes les informations relatives aux problèmes. Voulez-vous continuer ?
issues.label_deletion_success=Label supprimé avec succès !
pulls.new=New Pull Request
pulls.new=Nouvelle Pull Request
pulls.compare_changes=Comparer les changements
pulls.compare_changes_desc=Comparer deux branches et faire une demande de récupération Pull pour les changements.
pulls.compare_base=Base
@@ -503,7 +504,7 @@ pulls.tab_files=Fichiers modifiés
pulls.reopen_to_merge=Veuillez rouvrir cette demande de Pull Request pour effectuer l'opération de fusion.
pulls.merged=Fusionné
pulls.has_merged=Cette Pull Request a été fusionnée avec succès !
pulls.data_broken=Les données de cette Pull Request a été rompues en raison de la suppression d'informations du Fork.
pulls.data_broken=Les données de cette demande de rattachement ont été compromise en raison de la suppression d'informations sur l'embranchement.
pulls.is_checking=La recherche de conflits est toujours en cours, veuillez rafraichir la page dans quelques instants.
pulls.can_auto_merge_desc=Vous pouvez effectuer d'opération de fusion automatique sur cette demande de Pull Request.
pulls.cannot_auto_merge_desc=Vous ne pouvez effectuer des opération de fusion automatique car il y a des conflits entre les Commits.
@@ -535,16 +536,39 @@ milestones.deletion=Supprimer le Jalon
milestones.deletion_desc=Supprimer ce Jalon effacera ses informations dans tous les problèmes relatifs. Voulez-vous continuer ?
milestones.deletion_success=Le Jalon a été supprimé avec succès !
wiki=Wiki
wiki.welcome=Bienvenue sur le Wiki !
wiki.welcome_desc=Le Wiki est l'endroit où vous pouvez documenter votre projet ensemble et l'améliorer.
wiki.create_first_page=Créer la première page
wiki.page=Page
wiki.filter_page=Filtrer la page
wiki.new_page=Créer une nouvelle page
wiki.default_commit_message=Écrire une note concernant cette mise à jour (optionnel).
wiki.save_page=Enregistrer la page
wiki.last_commit_info=%s modifier cette page %s
wiki.edit_page_button=Modifier
wiki.new_page_button=Nouvelle Page
wiki.page_already_exists=Une page de wiki avec le même nom existe déjà.
wiki.pages=Pages
wiki.last_updated=Dernière mise à jour: %s
settings=Paramètres
settings.options=Options
settings.collaboration=Collaboration
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Paramètres de base
settings.danger_zone=Zone de danger
settings.site=Site officiel
settings.update_settings=Valider
settings.change_reponame_prompt=Ce changement affectera comment les liens sont reliés avec le dépôt.
settings.advanced_settings=Paramètres Avancés
settings.wiki_desc=Activer le wiki pour permettre l'écriture de documents
settings.issues_desc=Activer le bug-tracker léger intégré
settings.use_external_issue_tracker=Utiliser un bug-tracker externe
settings.tracker_url_format=Format d'URL du bug tracker
settings.tracker_url_format_desc=Vous pouvez utiliser l'espace réservé <code>{user} {repo} {index}</code> pour le nom d'utilisateur, le nom du dépôt et le numéro de bug.
settings.pulls_desc=Activer les pull requests pour accepter les contributions publiques
settings.danger_zone=Zone de danger
settings.transfer=Transférer les propriétés
settings.transfer_desc=Transfèrer ce dépôt à un autre utilisateur ou une organisation dont vous possédez des droits d'administrateur.
settings.new_owner_has_same_repo=Le nouveau propriétaire a déjà un dépôt nommé ainsi.
@@ -555,9 +579,10 @@ settings.transfer_notices_2=-Vous préserverez l'accès si le nouveau propriéta
settings.transfer_form_title=Veuillez recopier le texte suivant afin de confirmer votre opération :
settings.delete_notices_1=- Cette opération <strong>ne peut pas </strong> être annulée.
settings.delete_notices_2=-Cette opération supprimera définitivement le dépôt, y compris les données Git, problèmes, commentaires et accès des collaborateurs.
settings.delete_notices_fork_1=-Si ce dépôt est public, tous les Forks vont devenir indépendants après la suppression.
settings.delete_notices_fork_2=-Si ce dépôt est privé, tous les Forks seront supprimés en même temps.
settings.delete_notices_fork_3=-Si vous souhaitez conserver tous les forks après suppression, veuillez tout d'abord modifier la visibilité de ce dépôt en public.
settings.delete_notices_fork_1=-Si ce dépôt est public, tous les embranchements vont devenir indépendants après la suppression.
settings.delete_notices_fork_2=-Si ce dépôt est privé, tous les embranchements seront supprimés en même temps.
settings.delete_notices_fork_3=-Si vous souhaitez conserver tous les embranchements après suppression, veuillez tout d'abord modifier la visibilité de ce dépôt en public.
settings.deletion_success=Le dépôt a été supprimé avec succès!
settings.update_settings_success=Options mises à jour avec succès.
settings.transfer_owner=Nouveau propriétaire
settings.make_transfer=Transférer
@@ -573,6 +598,9 @@ settings.hooks_desc=Les Webhooks sont des déclencheurs de POST HTTP . Lorsque q
settings.webhook_deletion=Supprimer le Webhook
settings.webhook_deletion_desc=Supprimer ce webhook va supprimer ses informations et l'historique de livraison. Voulez-vous continuer ?
settings.webhook_deletion_success=Le webhook a été supprimé avec succès !
settings.webhook.test_delivery=Tester la publication
settings.webhook.test_delivery_desc=Envoyer un faux push pour tester la configuration des webhooks
settings.webhook.test_delivery_success=Le webhook de test a été ajouté à la file d'attente de livraison. L'affichage dans l'historique de livraison peut prendre quelques secondes.
settings.webhook.request=Requête
settings.webhook.response=Réponse
settings.webhook.headers=Entêtes 
@@ -612,6 +640,7 @@ settings.slack_domain=Domaine
settings.slack_channel=Canal
settings.deploy_keys=Clés de déploiement
settings.add_deploy_key=Ajouter une Clé de Déploiement
settings.deploy_key_desc=Déployer une clé uniquement en lecture seule. Il ne s'agit pas des clés ssh de compte personnel.
settings.no_deploy_keys=Vous n'avez ajouté aucune clé de déploiement.
settings.title=Titre
settings.deploy_key_content=Contenu
@@ -624,7 +653,7 @@ settings.deploy_key_deletion_success=La clé de déploiement a été supprimée
diff.browse_source=Parcourir la Source
diff.parent=Parent
diff.commit=Commettre
diff.commit=commit
diff.data_not_available=Données Diff indisponibles.
diff.show_diff_stats=Afficher les stats Diff
diff.stats_desc=<strong> %d fichiers modifiés</strong> avec <strong>%d ajouts</strong> et <strong>%d suppressions</strong>
@@ -637,10 +666,10 @@ release.draft=Brouillon
release.prerelease=Pré-publication
release.stable=Stable
release.edit=Éditer
release.ahead=<strong>%d</strong> commissions à %s depuis cette publication
release.ahead=<strong>%d</strong> commits jusqu'à %s depuis cette publication
release.source_code=Code Source
release.new_subheader=Publish releases to iterate product.
release.edit_subheader=Detailed change log can help users understand what has been improved.
release.new_subheader=Publier une version pour itérer sur le produit.
release.edit_subheader=Un changelog détaillé peut aider les utilisateurs à comprendre ce qui a été amélioré.
release.tag_name=Nom du tag
release.target=Cible 
release.tag_helper=Choisissez un tag existant ou créez-en un nouveau à publier.
@@ -655,10 +684,10 @@ release.cancel=Annuler
release.publish=Publier
release.save_draft=Sauvegarder le Brouillon
release.edit_release=Éditer la publication
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.delete_release=Supprimer Cette Version
release.deletion=Suppression de la Version
release.deletion_desc=Supprimer cette version supprimera le tag Git correspondant. Voulez-vous continuer ?
release.deletion_success=La version à été supprimée avec succès !
release.tag_name_already_exist=Une publication avec ce nom de tag existe déjà.
release.downloads=Téléchargements
@@ -701,17 +730,17 @@ settings.delete_org_title=Suppression d'organisation
settings.delete_org_desc=Cette organisation sera définitivement supprimée. Continuer ?
settings.hooks_desc=Ajoute des Webhooks qui seront activés pour <strong>tous les Référentiels</strong> de cette organisation.
members.membership_visibility=Membership Visibility:
members.membership_visibility=Visibilité des membres:
members.public=Public
members.public_helper=Rendre privé
members.private=Privé
members.private_helper=Rendre public
members.member_role=Member Role:
members.member_role=Rôle du membre :
members.owner=Propriétaire
members.member=Membre
members.remove=Exclure
members.leave=Quitter
members.invite_desc=Add a new member to %s:
members.invite_desc=Ajouter un nouveau membre à %s :
members.invite_now=Envoyer une invitation
teams.join=Rejoindre
@@ -736,7 +765,7 @@ teams.read_permission_desc=Cette équipe permet l'accès en <strong>lecture</str
teams.write_permission_desc=Cette équipe permet l'accès en <strong>écriture</strong> : les membres peuvent participer à ses Référentiels.
teams.admin_permission_desc=Cette équipe permet l'accès en <strong>administrateur</strong> : les membres peuvent voir, participer et ajouter des collaborateurs à ses Référentiels.
teams.repositories=Référentiels de l'Équipe
teams.search_repo_placeholder=Search repository...
teams.search_repo_placeholder=Rechercher dans le dépôt...
teams.add_team_repository=Ajouter un Dépôt à l'Équipe
teams.remove_repo=Supprimer
teams.add_nonexistent_repo=Dépôt inexistant, veuillez d'abord le créer.
@@ -767,8 +796,8 @@ dashboard.delete_inactivate_accounts=Supprimer tous les comptes inactifs
dashboard.delete_inactivate_accounts_success=Tous les comptes inactifs ont été supprimés avec succès.
dashboard.delete_repo_archives=Supprimer toutes les archives de référentiels
dashboard.delete_repo_archives_success=Toutes les archives des référentiels ont été supprimées avec succès.
dashboard.delete_missing_repos=Delete all repository records that lost Git files
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
dashboard.delete_missing_repos=Supprimer tous les dépôts ayant perdu leurs fichiers Git
dashboard.delete_missing_repos_success=Tous les dépôts ayant perdu leurs fichiers Git ont été supprimés avec succès.
dashboard.git_gc_repos=Collecter les déchets des référentiels
dashboard.git_gc_repos_success=Tous les dépôts ont effectué la collecte avec succès.
dashboard.resync_all_sshkeys=Ré-écrire le fichier '.ssh/authorized_keys' (attention : les clés hors-Gogs vont être perdues)
@@ -861,6 +890,8 @@ auths.bind_password=Bind mot de passe
auths.bind_password_helper=Avertissement : Ce mot de passe est stocké en clair. N'utilisez pas le mot de passe d'un compte doté de privilèges élevés.
auths.user_base=Utilisateur Search Base
auths.user_dn=Utilisateur DN
auths.attribute_username=Attribut nom d'utilisateur
auths.attribute_username_placeholder=Laisser vide pour utiliser la valeur du formulaire d'authentification comme nom d'utilisateur.
auths.attribute_name=Attribut du prénom
auths.attribute_surname=Attribut du nom de famille
auths.attribute_mail=Attribut de l'e-mail
@@ -964,11 +995,18 @@ monitor.start=Heure de Démarrage
monitor.execute_time=Heure d'Éxécution
notices.system_notice_list=Notes Systèmes
notices.view_detail_header=Voir les détails de la notification
notices.actions=Actions
notices.select_all=Tout Sélectionner
notices.deselect_all=Tous déselectionner
notices.inverse_selection=Inverser la sélection
notices.delete_selected=Supprimé les éléments sélectionnés
notices.delete_all=Supprimer toutes les notifications
notices.type=Type
notices.type_1=Dépôt
notices.desc=Description
notices.op=Opération
notices.delete_success=Note système supprimée avec succès.
notices.delete_success=Notifications système supprimées avec succès.
[action]
create_repo=a crée le dépôt <a href="%s">%s</a>
@@ -980,7 +1018,7 @@ comment_issue=`a commenté le problème <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`pull request fusionné le <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=a transféré le dépôt <code>%s</code> à <a href="%s">%s</a>
push_tag=a soumis le tag <a href="%s/src/%s">%[2]s</a> à <a href="%[1]s">%[3]s</a>
compare_2_commits=Comparer ces 2 commissions
compare_2_commits=Comparer ces 2 commits
[tool]
ago=auparavant

View File

@@ -15,7 +15,7 @@ template=Template
language=Lingua
create_new=Crea...
user_profile_and_more=Profilo utente e altro
signed_in_as=Signed in as
signed_in_as=Accesso effettuato come
username=Nome utente
email=E-mail
@@ -64,9 +64,9 @@ db_name=Nome del database
db_helper=Utilizza il motore INNODB con codifica utf8_general_ci per MySQL.
ssl_mode=Modalità SSL
path=Percorso
sqlite_helper=The file path of SQLite3 or TiDB database.
err_empty_db_path=SQLite3 or TiDB database path cannot be empty.
err_invalid_tidb_name=TiDB database name does not allow characters "." and "-".
sqlite_helper=Il percorso file del database SQLite3 o TiDB.
err_empty_db_path=Il percorso file del database SQLite3 o TiDB non può essere vuoto.
err_invalid_tidb_name=Il nome del database TiDB non ammette caratteri "." e "-".
no_admin_and_disable_registration=Non puoi disabilitare la registrazione senza aver creato un amministratore.
err_empty_admin_password=La password dell'amministratore non puo' essere vuota.
@@ -80,7 +80,7 @@ run_user_helper=L'utente deve avere accesso al percorso root del repository e av
domain=Dominio
domain_helper=Questo modifica lo SSH clone URLs.
ssh_port=Porta SSH
ssh_port_helper=Port number which your SSH server is using, leave it empty to disable SSH feature.
ssh_port_helper=Numero di porta utilizzato dal server SSH, lasciare vuoto per disabilitare l'integrazione SSH.
http_port=Porta HTTP
http_port_helper=Porta di ascolto dell'applicazione.
app_url=URL Applicazione
@@ -98,12 +98,12 @@ mail_notify=Abilita Notifiche via Email
server_service_title=Impostazioni del Server e Altri Servizi
offline_mode=Abilita Modalità Offline
offline_mode_popup=Disabilita il CDN anche in modalità produttiva, tutte le risorse saranno servite localmente.
disable_gravatar=Disable Gravatar Service
disable_gravatar_popup=Disable Gravatar and custom sources, all avatars are uploaded by users or default.
disable_gravatar=Disattiva il servizio Gravatar
disable_gravatar_popup=Disabilita Gravatar e sorgenti customizzate, tutti gli avatar vengono caricati dagli utenti o come predefinito.
disable_registration=Disabilita Registrazione Manuale
disable_registration_popup=Disabilita la registrazione manuale degli utenti, solo gli amministratori possono creare account.
enable_captcha=Abilita Captcha
enable_captcha_popup=Require validate captcha for user self-registration.
enable_captcha_popup=Richiedi convalida captcha per i nuovi utenti.
require_sign_in_view=Abilita Richiesta di Accesso per Vedere le Pagine
require_sign_in_view_popup=Solo gli utenti loggati possono vedere le pagine, i visitatori potranno vedere solo le pagine di accesso e registrazione.
admin_setting_desc=Non devi per forza creare un account admin proprio adesso, ma comunque l'utente ID=1 otterrà l'accesso da amministratore automaticamente.
@@ -111,7 +111,7 @@ admin_title=Impostazioni Account Amministratore
admin_name=Nome utente
admin_password=Password
confirm_password=Conferma Password
admin_email=Admin E-mail
admin_email=E-mail dell'Admin
install_gogs=Installare Gogs
test_git_failed=Fallito il test del comando git: %v
sqlite3_not_available=Questa versione non supporta SQLite3, si prega di scaricare la versione binaria ufficiale da %s, NON la versione gobuild.
@@ -164,7 +164,7 @@ activate_account=Per favore attiva il tuo account
activate_email=Verifica il tuo indirizzo e-mail
reset_password=Reimposta la tua password
register_success=Registrazione completata con successo, Benvenuto
register_notify=Welcome on board
register_notify=Benvenuti a bordo
[modal]
yes=
@@ -253,7 +253,7 @@ location=Posizione
update_profile=Aggiorna Profilo
update_profile_success=Il tuo profilo è stato aggiornato con successo.
change_username=Username Cambiato
change_username_prompt=This change will affect the way how links relate to your account.
change_username_prompt=Questa modifica influenzerà il modo in cui i link si riferiscono al tuo account.
continue=Continua
cancel=Annulla
@@ -278,9 +278,9 @@ email_desc=Il tuo indirizzo e-mail primario sarà usato per le notifiche e altre
primary=Primario
primary_email=Imposta come primario
delete_email=Elimina
email_deletion=E-mail Deletion
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
email_deletion_success=E-mail has been deleted successfully!
email_deletion=Eliminazione e-mail
email_deletion_desc=La procedura di rimozione indirizzo email eliminerà tutte le informazioni correlate dal tuo account. Si desidera continuare?
email_deletion_success=Indirizzo e-mail eliminato con successo!
add_new_email=Aggiungi un nuovo indirizzo E-mail
add_email=Aggiungi E-mail
add_email_confirmation_sent=Una nuova email di conferma è stata inviata a '%s', per favore controlla la tua posta in arrivo nelle prossime %d ore per completare il processo di registrazione.
@@ -291,13 +291,13 @@ add_key=Aggiungi Chiave
ssh_desc=Questa è una lista di chiavi SSH associate al tuo account. Poiché queste chiavi consentono a chiunque di ottenere accesso alle tue repository, è molto importante che tu le riconosca.
ssh_helper=<strong>Non sai come?</strong> Controlla la guida di GitHub sul <a href="%s">creare le tue chiavi SSH</a> o sul risolvere <a href="%s">problemi frequenti</a> che potresti incontrare usando SSH.
add_new_key=Aggiungi Chiave SSH
ssh_key_been_used=Public key content has been used.
ssh_key_name_used=Public key with same name has already existed.
ssh_key_been_used=È stato utilizzato il contenuto della chiave pubblica.
ssh_key_name_used=Chiave pubblica con lo stesso nome esiste già.
key_name=Nome della Chiave
key_content=Contenuto
add_key_success=New SSH key '%s' has been added successfully!
add_key_success=La nuova chiave SSH '%s' è stata aggiunta con successo!
delete_key=Elimina
ssh_key_deletion=SSH Key Deletion
ssh_key_deletion=Eliminazione chiave SSH
ssh_key_deletion_desc=Delete this SSH key will remove all related accesses for your account. Do you want to continue?
ssh_key_deletion_success=La chiave SSH e' stata cancellata con successo!
add_on=Aggiunto il
@@ -319,7 +319,7 @@ token_name=Nome Token
generate_token=Genera Token
generate_token_succees=Nuovo token di accesso generato con successo! Assicurarsi di copiare il nuovo token di accesso personale ora: non sarà possibile visualizzarlo nuovamente!
delete_token=Elimina
access_token_deletion=Personal Access Token Deletion
access_token_deletion=Eliminazione Token di accesso personale
access_token_deletion_desc=Delete this personal access token will remove all related accesses of application. Do you want to continue?
delete_token_success=Personal access token has been removed successfully! Don't forget to update your application as well.
@@ -388,6 +388,7 @@ create_new_repo_command=Crea nuovo repository da riga di comando
push_exist_repo=Push un repo esistente dalla riga di comando
repo_is_empty=This repository is empty, please come back later!
code=Code
branch=Ramo (Branch)
tree=Albero (Tree)
filter_branch_and_tag=Filter branch or tag
@@ -527,24 +528,47 @@ milestones.clear=Clear
milestones.invalid_due_date_format=Due date format is invalid, must be 'yyyy-mm-dd'.
milestones.create_success=Milestone '%s' has been created successfully!
milestones.edit=Edit Milestone
milestones.edit_subheader=Use better description for milestones so people won't be confused.
milestones.edit_subheader=Use a better description for milestones so people won't be confused.
milestones.cancel=Cancel
milestones.modify=Modify Milestone
milestones.edit_success=Changes of milestone '%s' has been saved successfully!
milestones.deletion=Milestone Deletion
milestones.deletion_desc=Delete this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_desc=Deleting this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_success=Milestone has been deleted successfully!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=Impostazioni
settings.options=Opzioni
settings.collaboration=Collaborazione
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Impostazioni di Base
settings.danger_zone=Zona Pericolosa
settings.site=Sito Ufficiale
settings.update_settings=Aggiorna Impostazioni
settings.change_reponame_prompt=This change will affect how links relate to the repository.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Zona Pericolosa
settings.transfer=Trasferisci proprietà
settings.transfer_desc=Trasferisci questa repository a un altro utente o a un'organizzazione nella quale hai diritti d'amministratore.
settings.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- This operation will permanently delete the everythin
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Le opzioni repository sono state aggiornate con successo.
settings.transfer_owner=Nuovo Proprietario
settings.make_transfer=Trasferisci
@@ -573,6 +598,9 @@ settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HT
settings.webhook_deletion=Delete Webhook
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
settings.webhook_deletion_success=Webhook has been deleted successfully!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Request
settings.webhook.response=Response
settings.webhook.headers=Headers
@@ -612,14 +640,15 @@ settings.slack_domain=Dominio
settings.slack_channel=Canale
settings.deploy_keys=Dispiega Chiavi
settings.add_deploy_key=Add Deploy Key
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=You haven't added any deploy key.
settings.title=Title
settings.deploy_key_content=Content
settings.key_been_used=Deploy key content has been used.
settings.key_name_used=Deploy key with same name has already existed.
settings.key_name_used=Deploy key with the same name already exists.
settings.add_key_success=New deploy key '%s' has been added successfully!
settings.deploy_key_deletion=Delete Deploy Key
settings.deploy_key_deletion_desc=Delete this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_desc=Deleting this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_success=Deploy key has been deleted successfully!
diff.browse_source=Sfoglia il codice sorgente
@@ -657,7 +686,7 @@ release.save_draft=Salva Bozza
release.edit_release=Modifica Rilascio
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.tag_name_already_exist=Un rilascio con questo tag esiste già.
release.downloads=Downloads
@@ -861,6 +890,8 @@ auths.bind_password=Bind Password
auths.bind_password_helper=Warning: This password is stored in plain text. Do not use a high privileged account.
auths.user_base=User Search Base
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=Attributo Nome
auths.attribute_surname=Attributo Cognome
auths.attribute_mail=Attributo Email
@@ -964,11 +995,18 @@ monitor.start=Orario Avvio
monitor.execute_time=Tempo di Esecuzione
notices.system_notice_list=Avvisi di Sistema
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Tipo
notices.type_1=Repository
notices.desc=Descrizione
notices.op=Op.
notices.delete_success=Avviso di sistema cancellato con successo.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=ha creato il repository <a href="%s">%s</a>

View File

@@ -352,9 +352,9 @@ auto_init=選択されたファイルおよびテンプレートでリポジト
create_repo=リポジトリを作成
default_branch=デフォルトのブランチ
mirror_interval=ミラー 間隔(時)
watchers=Watchers
watchers=ウォッチャー
stargazers=Stargazers
forks=Forks
forks=フォーク
form.name_reserved=リポジトリ名 '%s' は予約されています。
form.name_pattern_not_allowed=リポジトリ名のパターン '%s' は許可されていません。
@@ -365,7 +365,7 @@ migrate_type_helper=このリポジトリは、<span class="text blue"> ミラ
migrate_repo=リポジトリを移行
migrate.clone_address=クローンアドレス
migrate.clone_address_desc=これは、HTTP/HTTPS/GIT URL またはローカル サーバー パスを設定できます。
migrate.permission_denied=You are not allowed to import local repositories.
migrate.permission_denied=ローカル リポジトリをインポートすることはできません。
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
migrate.failed=Migration failed: %v
@@ -388,9 +388,10 @@ create_new_repo_command=コマンドラインで新しいリポジトリを作
push_exist_repo=コマンド ・ ラインから既存のリポジトリをプッシュ
repo_is_empty=このリポジトリは空です、後で戻って来て下さい!
code=Code
branch=ブランチ
tree=ツリー
filter_branch_and_tag=Filter branch or tag
filter_branch_and_tag=ブランチまたはタグをフィルタリング
branches=ブランチ
tags=タグ
issues=課題
@@ -485,7 +486,7 @@ issues.label_deletion=ラベルの削除
issues.label_deletion_desc=ラベルを削除すると、関連するすべての問題の情報が削除されます。続行しますか。
issues.label_deletion_success=ラベルは正常に削除されました。
pulls.new=New Pull Request
pulls.new=新しいプルリクエスト
pulls.compare_changes=変更を比較
pulls.compare_changes_desc=2つのブランチを比較し、プルリクエストを作成します。
pulls.compare_base=ベース
@@ -535,16 +536,39 @@ milestones.deletion=マイルス トーンの削除
milestones.deletion_desc=このマイルス トーンを削除すると、関連課題に該当情報が削除されます。続行しますか。
milestones.deletion_success=マイルス トーンは正常に削除されました。
wiki=Wiki
wiki.welcome=Wiki へようこそ!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=最初のページを作成する。
wiki.page=ページ
wiki.filter_page=Filter page
wiki.new_page=新しいページを作成
wiki.default_commit_message=このアップデートについてメモを書く(オプション)
wiki.save_page=ページを保存
wiki.last_commit_info=%s このページを編集 %s
wiki.edit_page_button=編集
wiki.new_page_button=新規ページ
wiki.page_already_exists=既に同じ名前のWiki ページが存在します。
wiki.pages=ページ
wiki.last_updated=最終更新 %s
settings=設定
settings.options=オプション
settings.collaboration=コラボレーション
settings.hooks=Webhooks
settings.githooks=Git のフック
settings.basic_settings=基本設定
settings.danger_zone=危険地帯
settings.site=公式サイト
settings.update_settings=設定の更新
settings.change_reponame_prompt=この変更はリンクがリポジトリに関連付ける方法に影響します。
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=危険地帯
settings.transfer=オーナー移転
settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
@@ -558,6 +582,7 @@ settings.delete_notices_2=- This operation will permanently delete the everythin
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=リポジトリ オプションが更新されました。
settings.transfer_owner=新しいオーナー
settings.make_transfer=転送
@@ -566,13 +591,16 @@ settings.confirm_delete=削除の確認
settings.add_collaborator=新しい共同編集者を追加
settings.add_collaborator_success=新しい共同編集者が追加されました。
settings.remove_collaborator_success=共同編集者が削除されました。
settings.search_user_placeholder=Search user...
settings.search_user_placeholder=Search users
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
settings.add_webhook=Webhook を追加
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
settings.webhook_deletion=Webhook を削除
settings.webhook_deletion_desc=このwebhookを削除すると、すべての情報と配信履歴が削除されます。続行しますか
settings.webhook_deletion_success=Webhook が正常に削除されました。
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=リクエスト
settings.webhook.response=レスポンス
settings.webhook.headers=ヘッダ
@@ -612,6 +640,7 @@ settings.slack_domain=ドメイン
settings.slack_channel=チャンネル
settings.deploy_keys=デプロイキー
settings.add_deploy_key=デプロイキーを追加
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=でプロキーは1つも追加されていません。
settings.title=タイトル
settings.deploy_key_content=コンテント
@@ -644,21 +673,21 @@ release.edit_subheader=Detailed change log can help users understand what has be
release.tag_name=タグ名
release.target=ターゲット
release.tag_helper=既存のタグを選択するか、新しいタグを作成し発行します。
release.title=Title
release.content=Content
release.title=タイトル
release.content=コンテント
release.write=書込み
release.preview=プレビュー
release.loading=読み込み中…
release.prerelease_desc=これはリリース前のものです
release.prerelease_helper=このリリースは非プロダクション利用として識別します。
release.cancel=Cancel
release.cancel=キャンセル
release.publish=リリースを発行
release.save_draft=下書きを保存
release.edit_release=リリースを編集
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.delete_release=このリリースを削除
release.deletion=リリースの削除
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success=リリースが正常に削除されました。
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
release.downloads=Downloads
@@ -706,12 +735,12 @@ members.public=パブリック
members.public_helper=プライベートにする
members.private=プライベート
members.private_helper=公開する
members.member_role=Member Role:
members.member_role=メンバーの役割:
members.owner=オーナー
members.member=メンバー
members.remove=削除
members.leave=退出
members.invite_desc=Add a new member to %s:
members.invite_desc=%s に新しいメンバーを追加
members.invite_now=今すぐ招待
teams.join=参加
@@ -736,7 +765,7 @@ teams.read_permission_desc=このチームは<strong>読み取り</strong>権限
teams.write_permission_desc=このチームは<strong>書き込み</strong>権限を持ち: メンバーはリポジトリの表示及リポジトリへのプッシュができます。
teams.admin_permission_desc=このチームは<strong>管理者</strong>の権限を持ち: メンバーはチームのリポジトリに対して、読み取り、プッシュや共同編集者の追加ができます。
teams.repositories=チームのリポジトリ
teams.search_repo_placeholder=Search repository...
teams.search_repo_placeholder=リポジトリを検索
teams.add_team_repository=チームのリポジトリを追加
teams.remove_repo=削除(Remove)
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。まずはじめに作成してください。
@@ -861,6 +890,8 @@ auths.bind_password=バインド パスワード
auths.bind_password_helper=警告: このパスワードは暗号化されずに格納されます。特権を持つアカウントに使用しないでください。
auths.user_base=ユーザ検索ベース
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=名前属性
auths.attribute_surname=名字属性
auths.attribute_mail=Eメール属性
@@ -964,11 +995,18 @@ monitor.start=開始日時
monitor.execute_time=実行時間:
notices.system_notice_list=システム通知
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=タイプ
notices.type_1=リポジトリ
notices.desc=説明
notices.op=Op。
notices.delete_success=システム通知が正常に削除されました。
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=リポジトリ <a href="%s"> %s</a>を作成しました

View File

@@ -164,7 +164,7 @@ activate_account=Lūdzu, aktivizējiet savu kontu
activate_email=Apstipriniet savu e-pasta adresi
reset_password=Atiestatīt savu paroli
register_success=Reģistrācija notikusi veiksmīgi
register_notify=Welcome on board
register_notify=Laipni lūgti uz klāja
[modal]
yes=
@@ -352,9 +352,9 @@ auto_init=Inicializēt šo repozitoriju ar izvēlētajiem failiem un sagatavi
create_repo=Izveidot repozitoriju
default_branch=Noklusējuma atzars
mirror_interval=Spoguļošanas intervāls (stundās)
watchers=Watchers
stargazers=Stargazers
forks=Forks
watchers=Novērotāji
stargazers=Zvaigžņdevēji
forks=Atdalītie repozitoriji
form.name_reserved=Repozitorija nosaukums '%s' ir rezervēts.
form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts.
@@ -367,7 +367,7 @@ migrate.clone_address=Klonēšanas adrese
migrate.clone_address_desc=Tas var būt HTTP/HTTPS/GIT URL vai ceļš uz lokālā servera.
migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju.
migrate.invalid_local_path=Nekorents lokālais ceļš, tas neeksistē vai nav direktorijs.
migrate.failed=Migration failed: %v
migrate.failed=Migrācija neizdevās: %v
forked_from=atdalīts no
fork_from_self=Nav iespējams atdalīt repozitoriju, kuram esat īpašnieks!
@@ -388,9 +388,10 @@ create_new_repo_command=Izveidot jaunu repozitoriju komandrindā
push_exist_repo=Nosūtīt izmaiņas no komandrindas eksistējošam repozitorijam
repo_is_empty=Šis repozitorijs ir tukšs, apskatiet atkal vēlāk!
code=Code
branch=Atzars
tree=Koks
filter_branch_and_tag=Filter branch or tag
filter_branch_and_tag=Filtrēt atzarus vai tagus
branches=Atzari
tags=Tagi
issues=Problēmas
@@ -485,7 +486,7 @@ issues.label_deletion=Etiķetes dzēšana
issues.label_deletion_desc=Dzēšot šo etiķeti, tā tiks noņemta no visām saistītajām problēmām. Vai vēlaties turpināt?
issues.label_deletion_success=Etiķete tika veiksmīgi izdzēsta!
pulls.new=New Pull Request
pulls.new=Jauns izmaiņu pieprasījums
pulls.compare_changes=Salīdzināt izmaiņas
pulls.compare_changes_desc=Salīdzināt divus atzarus un izveidot izmaiņu pieprasījumu.
pulls.compare_base=pamata
@@ -535,16 +536,39 @@ milestones.deletion=Atskaites punkta dzēšana
milestones.deletion_desc=Dzēšot šo atskaites punktu tiks noņemta arī saistītā informācija no problēmu ziņojumiem. Vai vēlaties turpināt?
milestones.deletion_success=Atskaites punkts tika veiksmīgi izdzēsts!
wiki=Vikivietne
wiki.welcome=Laipni lūgti vikivietnē!
wiki.welcome_desc=Vikivietne ir vieta, kur Jūs varat dokumentēt savu projektu, lai padarīto to labāku.
wiki.create_first_page=Izveidot pirmo lapu
wiki.page=Lapa
wiki.filter_page=Meklēt lapu
wiki.new_page=Izveidot jaunu lapu
wiki.default_commit_message=Uzrakstiet piezīmes par šīm izmaiņām (neobligāti).
wiki.save_page=Saglabāt lapu
wiki.last_commit_info=%s laboja lapu %s
wiki.edit_page_button=Labot
wiki.new_page_button=Jauna lapa
wiki.page_already_exists=Vikivietnes lapa ar šādu nosaukumu jau eksistē.
wiki.pages=Lapas
wiki.last_updated=Pēdējo reizi labota %s
settings=Iestatījumi
settings.options=Opcijas
settings.collaboration=Sadarbība
settings.hooks=Tīmekļa āķi
settings.githooks=Git āķi
settings.basic_settings=Pamatiestatījumi
settings.danger_zone=Bīstamā zona
settings.site=Oficiālā mājas lapa
settings.update_settings=Mainīt iestatījumus
settings.change_reponame_prompt=Šī izmaiņa ietekmēs saites, kas ir saistītas ar šo repozitoriju.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Bīstamā zona
settings.transfer=Mainīt īpašnieku
settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs.
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Šī darbība neatgriezeniski izdzēsīs visus šī
settings.delete_notices_fork_1=- Ja repozitorijs ir publisks, visi atdalītie repozitoriji kļūs neatkarīgi.
settings.delete_notices_fork_2=- Ja repozitorijs ir privāts, tiks dzēsti arī visi atdalītie repozitoriji.
settings.delete_notices_fork_3=- Ja vēlaties saglabāt atdalīts repozitorijus pēc dzēšanas, sākumā nomainiet repozitorija redzamību uz publisku.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Repozitorija opcijas ir veiksmīgi saglabātas.
settings.transfer_owner=Jaunais īpašnieks
settings.make_transfer=Mainīt
@@ -566,13 +591,16 @@ settings.confirm_delete=Apstiprināt dzēšanu
settings.add_collaborator=Pievienot jaunu līdzstrādnieku
settings.add_collaborator_success=Jauns līdzstrādnieks ir pievienots.
settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
settings.search_user_placeholder=Search user...
settings.search_user_placeholder=Meklēt lietotāju...
settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks.
settings.add_webhook=Pievienot tīmekļa āķi
settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
settings.webhook_deletion=Dzēst tīmekļa āķi
settings.webhook_deletion_desc=Dzēšot tīmekļa āķi tiks dzēsta visa ar to saistītā informācija un izpildes vēsture. Vai vēlaties turpināt?
settings.webhook_deletion_success=Tīmekļa āķis tika veiksmīgi izdzēsts!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Pieprasījums
settings.webhook.response=Atbilde
settings.webhook.headers=Galvenes
@@ -612,6 +640,7 @@ settings.slack_domain=Domēns
settings.slack_channel=Kanāls
settings.deploy_keys=Izvietot atslēgas
settings.add_deploy_key=Pievienot izvietošanas atslēgu
settings.deploy_key_desc=Izvietošanas atslēgai ir tikai lasīšanas piekļuve. Tā nav tā pati kā Jūsu personīgā konta SSH atslēga.
settings.no_deploy_keys=Nav pievienota neviena izvietošanas atslēga.
settings.title=Virsraksts
settings.deploy_key_content=Saturs
@@ -639,28 +668,28 @@ release.stable=Stabila
release.edit=labot
release.ahead=<strong>%d</strong> revīzijas atzarā %s kopš šī laidiena
release.source_code=Izejas kods
release.new_subheader=Publish releases to iterate product.
release.edit_subheader=Detailed change log can help users understand what has been improved.
release.new_subheader=Publicējiet laidienus, lai veiktu produkta iterācijas.
release.edit_subheader=Detalizēts žurnāls var palīdzēt lietotājiem saprast, kas tika uzlabots.
release.tag_name=Taga nosaukums
release.target=Mērķis
release.tag_helper=Publicējot, izvēlieties esošu vai izveidojiet jaunu tagu.
release.title=Title
release.content=Content
release.title=Virsraksts
release.content=Saturs
release.write=Rakstīt
release.preview=Priekšskatītījums
release.loading=Notiek ielāde...
release.prerelease_desc=Šī ir pirmslaidiena versija
release.prerelease_helper=Tiks norādīts, ka šis laidiens nav gatavs lietošanai produkcijas režīmā.
release.cancel=Cancel
release.cancel=Atcelt
release.publish=Publicēt laidienu
release.save_draft=Saglabāt melnrakstu
release.edit_release=Labot laidienu
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.delete_release=Dzēst šo laidienu
release.deletion=Laidiena dzēšana
release.deletion_desc=Dzēšot šo laidienu tiks dzēsts arī atbilstošs Git tags. Vai vēlaties turpināt?
release.deletion_success=Laidiens tika veiksmīgi dzēsts!
release.tag_name_already_exist=Laidiens ar šādu taga nosaukumu jau eksistē.
release.downloads=Downloads
release.downloads=Lejupielādes
[org]
org_name_holder=Organizācijas nosaukums
@@ -701,17 +730,17 @@ settings.delete_org_title=Organizācijas dzēšana
settings.delete_org_desc=Šī organizācija tiks pilnībā izdzēsta, vai vēlaties turpināt?
settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā.
members.membership_visibility=Membership Visibility:
members.membership_visibility=Dalībnieka redzamība:
members.public=Publisks
members.public_helper=padarīt privātu
members.private=Privāts
members.private_helper=padarīt publisku
members.member_role=Member Role:
members.member_role=Dalībnieka loma:
members.owner=Īpašnieks
members.member=Biedri
members.remove=Noņemt
members.leave=Atstāt
members.invite_desc=Add a new member to %s:
members.invite_desc=Pievienot jaunu dalībnieku pie %s:
members.invite_now=Uzaicināt tagad
teams.join=Pievienoties
@@ -736,7 +765,7 @@ teams.read_permission_desc=Šai komandai ir <strong>lasīšanas</strong> tiesīb
teams.write_permission_desc=Šai komandai ir <strong>rakstīšanas</strong> tiesības: dalībnieki var lasīt un nosūtīt izmaiņas repozitorijiem.
teams.admin_permission_desc=Šai komandai ir <strong>administratora</strong> tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem.
teams.repositories=Komandas repozitoriji
teams.search_repo_placeholder=Search repository...
teams.search_repo_placeholder=Meklēt repozitorijā...
teams.add_team_repository=Pievienot komandas repozitoriju
teams.remove_repo=Noņemt
teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to.
@@ -767,8 +796,8 @@ dashboard.delete_inactivate_accounts=Dzēst visus neaktīvos kontus
dashboard.delete_inactivate_accounts_success=Visi neaktīvie kotni tika veiksmīgi izdzēsti.
dashboard.delete_repo_archives=Dzēst visu repozitoriju arhīvus
dashboard.delete_repo_archives_success=Visu repozitoriju arhīvi tika veiksmīgi izdzēsti.
dashboard.delete_missing_repos=Delete all repository records that lost Git files
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
dashboard.delete_missing_repos=Dzēst visus repozitorija ierakstus, kas zaudēja Git failus
dashboard.delete_missing_repos_success=Visi repozitorija ieraksti, kas zaudēja Git failus tika veiksmīgi dzēsti.
dashboard.git_gc_repos=Veikt repozitoriju datu sakārtošānu (git gc)
dashboard.git_gc_repos_success=Datu sakārtošana visiem repozitorijiem veiksmīgi pabeigta.
dashboard.resync_all_sshkeys=Pārrakstīt '.ssh/authorized_keys' failu (brīdinājums: ne-Git atslēgas tiks pazaudētas)
@@ -861,6 +890,8 @@ auths.bind_password=Saistīšanas parole
auths.bind_password_helper=Brīdinājums: Šī parole tiks saglabāta nešifrētā veidā. Neizmantojiet kontu ar augstām privilēģijām.
auths.user_base=Lietotāja pamatnosacījumi
auths.user_dn=Lietotāja DN
auths.attribute_username=Lietotājvārda atribūts
auths.attribute_username_placeholder=Atstājiet tukšu, lai izmantotu lietotājvārdu ar kuru autorizējaties.
auths.attribute_name=Vārda atribūts
auths.attribute_surname=Uzvārda atribūts
auths.attribute_mail=E-pasta atribūts
@@ -964,11 +995,18 @@ monitor.start=Sākuma laiks
monitor.execute_time=Izpildes laiks
notices.system_notice_list=Sistēmas paziņojumi
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Veids
notices.type_1=Repozitorijs
notices.desc=Apraksts
notices.op=Op.
notices.delete_success=Sistēmas paziņojums tika veiksmīgi izdzēsts.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=izveidoja repozitoriju <a href="%s">%s</a>

View File

@@ -111,7 +111,7 @@ admin_title=Instellingen beheerdersaccount
admin_name=Gebruikersnaam
admin_password=Wachtwoord
confirm_password=Verifieer wachtwoord
admin_email=Admin E-mail
admin_email=Admin Email
install_gogs=Installeer Gogs
test_git_failed=Git test niet gelukt: 'git' commando %v
sqlite3_not_available=Uw versie biedt geen ondersteuning voor SQLite3, download de officiële binaire versie van %s, niet de gobuild versie.
@@ -161,9 +161,9 @@ password_too_short=De lengte van uw wachtwoord moet minimaal zes karakters zijn.
[mail]
activate_account=Please activate your account
activate_email=Verify your e-mail address
activate_email=Verify your email address
reset_password=Reset your password
register_success=Register success, Welcome
register_success=Registration successful, welcome
register_notify=Welcome on board
[modal]
@@ -278,9 +278,9 @@ email_desc=Uw primaire e-mailadres zal worden gebruikt voor meldingen en andere
primary=Primair
primary_email=Instellen als primair
delete_email=Verwijder
email_deletion=E-mail Deletion
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
email_deletion_success=E-mail has been deleted successfully!
email_deletion=Email Deletion
email_deletion_desc=Deleting this email address will remove related information from your account. Do you want to continue?
email_deletion_success=Email has been deleted successfully!
add_new_email=Nieuw e-mailadres toevoegen
add_email=E-mailadres toevoegen
add_email_confirmation_sent=Een nieuwe bevestiging e-mail werd verstuurd naar '%s', gelieve uw inbox in de komende %d uren te controleren om het bevestigingsproces te voltooien.
@@ -388,6 +388,7 @@ create_new_repo_command=Maak een nieuwe repositorie aan vanaf de console
push_exist_repo=Push een bestaande repositorie vanaf de console
repo_is_empty=This repository is empty, please come back later!
code=Code
branch=Aftakking
tree=Boom
filter_branch_and_tag=Filter branch or tag
@@ -535,16 +536,39 @@ milestones.deletion=Mijlpaal verwijderen
milestones.deletion_desc=Het verwijderen van dit label zal alle informatie in de gerelateerde problemen verwijderen. Wilt u doorgaan?
milestones.deletion_success=Mijlpaal is met succes verwijderd!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=Instellingen
settings.options=Opties
settings.collaboration=Samenwerking
settings.hooks=Webhooks
settings.githooks=Git haken
settings.basic_settings=Basis instellingen
settings.danger_zone=Gevaren zone
settings.site=Officiële site
settings.update_settings=Instellingen bewerken
settings.change_reponame_prompt=This change will affect how links relate to the repository.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Gevaren zone
settings.transfer=Eigendom overdragen
settings.transfer_desc=Draag deze repo over aan een andere gebruiker of een organisatie waar u beheerders rechten heeft.
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
@@ -558,6 +582,7 @@ settings.delete_notices_2=- This operation will permanently delete the everythin
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Repositorie instellingen zijn succesvol bijgewerkt.
settings.transfer_owner=Nieuwe eigenaar
settings.make_transfer=Maak overdracht
@@ -573,6 +598,9 @@ settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvan
settings.webhook_deletion=Webhook verwijderen
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
settings.webhook_deletion_success=Webhook has been deleted successfully!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Verzoek
settings.webhook.response=Antwoord
settings.webhook.headers=Headers
@@ -612,6 +640,7 @@ settings.slack_domain=Slack domein
settings.slack_channel=Slack kanaal
settings.deploy_keys=Installeer sleutels
settings.add_deploy_key=Toevoegen deploy sleutel
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=U hebt nog geen deploy sleutels toegevoegd.
settings.title=Titel
settings.deploy_key_content=Inhoud
@@ -657,7 +686,7 @@ release.save_draft=Concept opslaan
release.edit_release=Release bewerken
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.tag_name_already_exist=Versie met deze naam bestaat al.
release.downloads=Downloads
@@ -861,6 +890,8 @@ auths.bind_password=Bind Password
auths.bind_password_helper=Warning: This password is stored in plain text. Do not use a high privileged account.
auths.user_base=User Search Base
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=Voornaam attribuut
auths.attribute_surname=Achternaam attribuut
auths.attribute_mail=E-mail attribuut
@@ -964,11 +995,18 @@ monitor.start=Starttijd
monitor.execute_time=Uitvoertijd
notices.system_notice_list=Systeem aankondigingen
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Type
notices.type_1=Opslagplaats
notices.desc=Beschrijving
notices.op=Op.
notices.delete_success=Systeem bericht is met succes verwijderd.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=repositorie aangemaakt in <a href="%s">%s</a>

View File

@@ -111,7 +111,7 @@ admin_title=Ustawienia konta administratora
admin_name=Nazwa Użytkownika
admin_password=Hasło
confirm_password=Potwierdź hasło
admin_email=Admin E-mail
admin_email=Admin Email
install_gogs=Zainstaluj Gogs
test_git_failed=Nie udało się przetestować polecenia "git": %v
sqlite3_not_available=Twoje wydanie nie obsługuje SQLite3, proszę pobrać oficjalne wydanie z %s, a NIE wersję z gobuild.
@@ -279,7 +279,7 @@ primary=Podstawowy
primary_email=Ustaw jako podstawowy
delete_email=Usuń
email_deletion=Usunięcie wiadomości e-mail
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
email_deletion_desc=Deleting this email address will remove related information from your account. Do you want to continue?
email_deletion_success=E-mail został usunięty pomyślnie!
add_new_email=Dodaj nowy e-mail
add_email=Dodaj e-mail
@@ -370,7 +370,7 @@ migrate.invalid_local_path=Ścieżka jest niepoprawna. Nie istnieje lub nie jest
migrate.failed=Migration failed: %v
forked_from=sklonowany z
fork_from_self=You cannot fork repository you already owned!
fork_from_self=You cannot fork a repository you already own!
copy_link=Kopiuj
copy_link_success=Skopiowane!
copy_link_error=Naciśnij klawisze ⌘-C i Ctrl-C, aby skopiować
@@ -388,6 +388,7 @@ create_new_repo_command=Utwórz nowe repozytorium z wiersza poleceń
push_exist_repo=Wyślij istniejące repozytorium z wiersza poleceń
repo_is_empty=To repozytorium jest puste, proszę wrócić później!
code=Code
branch=Gałąź
tree=Drzewo
filter_branch_and_tag=Filter branch or tag
@@ -482,7 +483,7 @@ issues.label_edit=Edytuj
issues.label_delete=Usuń
issues.label_modify=Modyfikacja etykiety
issues.label_deletion=Usunięcie etykiety
issues.label_deletion_desc=Delete this label will remove its information in all related issues. Do you want to continue?
issues.label_deletion_desc=Deleting this label will remove its information in all related issues. Do you want to continue?
issues.label_deletion_success=Etykieta została usunięta pomyślnie!
pulls.new=New Pull Request
@@ -527,24 +528,47 @@ milestones.clear=Wyczyść
milestones.invalid_due_date_format=Format daty realizacji jest nieprawidłowy, musi być "rrrr-mm-dd".
milestones.create_success=Kamień milowy "%s" został utworzony pomyślnie!
milestones.edit=Edytuj kamień milowy
milestones.edit_subheader=Use better description for milestones so people won't be confused.
milestones.edit_subheader=Use a better description for milestones so people won't be confused.
milestones.cancel=Anuluj
milestones.modify=Modyfikuj kamień milowy
milestones.edit_success=Changes of milestone '%s' has been saved successfully!
milestones.deletion=Milestone Deletion
milestones.deletion_desc=Delete this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_desc=Deleting this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_success=Kamień milowy został usunięty pomyślnie!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=Ustawienia
settings.options=Opcje
settings.collaboration=Współpraca
settings.hooks=Webhooks
settings.githooks=Skrypty Git
settings.basic_settings=Ustawienia podstawowe
settings.danger_zone=Strefa niebezpieczeństwa
settings.site=Oficjalna Strona
settings.update_settings=Aktualizuj ustawienia
settings.change_reponame_prompt=Zmiana nazwy repozytorium wpłynie na linki do niego.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Strefa niebezpieczeństwa
settings.transfer=Przeniesienie własności
settings.transfer_desc=Przenieś to repozytorium do innego użytkownika lub organizacji gdzie masz uprawnienia administratora.
settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- This operation will permanently delete the everythin
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Opcje repozytorium zostały pomyślnie zaktualizowane.
settings.transfer_owner=Nowy właściciel
settings.make_transfer=Przenieś
@@ -573,6 +598,9 @@ settings.hooks_desc=Webhooks are much like basic HTTP POST event triggers. Whene
settings.webhook_deletion=Usuń Webhook
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
settings.webhook_deletion_success=Webhook has been deleted successfully!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Żądanie
settings.webhook.response=Response
settings.webhook.headers=Headers
@@ -612,14 +640,15 @@ settings.slack_domain=Domena
settings.slack_channel=Kanał
settings.deploy_keys=Klucze wdrożeniowe
settings.add_deploy_key=Add Deploy Key
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=You haven't added any deploy key.
settings.title=Tytuł
settings.deploy_key_content=Treść
settings.key_been_used=Deploy key content has been used.
settings.key_name_used=Deploy key with same name has already existed.
settings.key_name_used=Deploy key with the same name already exists.
settings.add_key_success=New deploy key '%s' has been added successfully!
settings.deploy_key_deletion=Delete Deploy Key
settings.deploy_key_deletion_desc=Delete this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_desc=Deleting this deploy key will remove all related accesses for this repository. Do you want to continue?
settings.deploy_key_deletion_success=Deploy key has been deleted successfully!
diff.browse_source=Przeglądaj źródła
@@ -657,7 +686,7 @@ release.save_draft=Zapisz szkic
release.edit_release=Edytuj wydanie
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.tag_name_already_exist=Wersja o tej nazwie tagu już istnieje.
release.downloads=Downloads
@@ -861,6 +890,8 @@ auths.bind_password=Bind Password
auths.bind_password_helper=Warning: This password is stored in plain text. Do not use a high privileged account.
auths.user_base=User Search Base
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=Atrybut imienia
auths.attribute_surname=Atrybut nazwiska
auths.attribute_mail=Atrybut email
@@ -964,11 +995,18 @@ monitor.start=Czas rozpoczęcia
monitor.execute_time=Czas wykonania
notices.system_notice_list=Powiadomienia systemu
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Typ
notices.type_1=Repozytorium
notices.desc=Opis
notices.op=Op.
notices.delete_success=Powiadomienia systemowe zostały usunięte pomyślnie.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=utworzono repozytorium <a href="%s"> %s</a>

View File

@@ -1,7 +1,7 @@
app_desc=Um serviço de Git auto-hospedado e amigável escrito em Go
home=Página Inicial
dashboard=Painel de controle
dashboard=Página Inicial
explore=Explorar
help=Ajuda
sign_in=Entrar
@@ -164,7 +164,7 @@ activate_account=Por favor, ative sua conta
activate_email=Verifique seu endereço de e-mail
reset_password=Resetar sua senha
register_success=Registrado com sucesso. Bem vindo
register_notify=Welcome on board
register_notify=Bem-vindo a bordo
[modal]
yes=Sim
@@ -352,8 +352,8 @@ auto_init=Inicializar este repositório com os arquivos selecionados e modelo
create_repo=Criar Repositório
default_branch=Branch padrão
mirror_interval=Intervalo de Espelho (hora)
watchers=Watchers
stargazers=Stargazers
watchers=Observadores
stargazers=Usuários que estrelaram
forks=Forks
form.name_reserved=O nome de repositório '%s' não pode ser usado.
@@ -367,7 +367,7 @@ migrate.clone_address=Endereço de Clone
migrate.clone_address_desc=Isto pode ser uma URL de HTTP/HTTPS/GIT ou um caminho de diretório local.
migrate.permission_denied=Você não pode importar repositórios locais.
migrate.invalid_local_path=Caminho local inválido, não existe ou não é um diretório.
migrate.failed=Migration failed: %v
migrate.failed=Migração falhou: %v
forked_from=forkado de
fork_from_self=Você não pode criar fork de um repositório que já é seu!
@@ -388,9 +388,10 @@ create_new_repo_command=Criar um novo repositório na linha de comando
push_exist_repo=Push um repositório existente na linha de comando
repo_is_empty=Este repositório está vazio, por favor volte mais tarde!
code=Code
branch=Branch
tree=Árvore
filter_branch_and_tag=Filter branch or tag
filter_branch_and_tag=Filtrar branch ou tag
branches=Branches
tags=Tags
issues=Problemas
@@ -485,7 +486,7 @@ issues.label_deletion=Exclusão de etiqueta
issues.label_deletion_desc=Excluir uma etiqueta a retirará de todos os problemas que ela estiver marcando. Quer mesmo continuar?
issues.label_deletion_success=A etiqueta foi excluída com sucesso!
pulls.new=New Pull Request
pulls.new=Novo Pull Request
pulls.compare_changes=Comparar mudanças
pulls.compare_changes_desc=Comparar os dois branches e criar pull request com as mudanças.
pulls.compare_base=base
@@ -535,16 +536,39 @@ milestones.deletion=Exclusão de marco
milestones.deletion_desc=Excluir este marco removerá a informação dele em todos os problemas aos quais estiver associado. Você quer mesmo continuar?
milestones.deletion_success=Marco excluído com sucesso!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=Configurações
settings.options=Opções
settings.collaboration=Colaboração
settings.hooks=Webhooks
settings.githooks=Hooks do Git
settings.basic_settings=Configurações Básicas
settings.danger_zone=Zona de Perigo
settings.site=Site Oficial
settings.update_settings=Configurações de Atualização
settings.change_reponame_prompt=Este mudanças vai afetar os links para este repositório.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Zona de Perigo
settings.transfer=Transferir Propriedade
settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador.
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Esta operação irá apagar permanentemente o tudo d
settings.delete_notices_fork_1=- Se este repositório é público, todos os forks se tornarão independentes após a deleção.
settings.delete_notices_fork_2=- Se este repositório é privado, todos os forks serão removidos imediatamente.
settings.delete_notices_fork_3=- Se você deseja manter todos os forks, por favor muda a visibilidade do repositório para pública primeiro.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=As opções do repositório foram atualizadas com sucesso.
settings.transfer_owner=Novo Dono
settings.make_transfer=Fazer Transferência
@@ -566,13 +591,16 @@ settings.confirm_delete=Confirmar Deleção
settings.add_collaborator=Adicionar um Novo Colaborador
settings.add_collaborator_success=O novo colaborador foi adicionado.
settings.remove_collaborator_success=O colaborador foi removido.
settings.search_user_placeholder=Search user...
settings.search_user_placeholder=Pesquisar usuário...
settings.user_is_org_member=O usuário é um membro da organização que não pode ser adicionado como um colaborador.
settings.add_webhook=Adicionar Webhook
settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no Gogs. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
settings.webhook_deletion=Deletar Webhook
settings.webhook_deletion_desc=Deletar este Webhook vai remover sua informação e todo o histórico de entrega. Deseja continuar?
settings.webhook_deletion_success=Webhook deletado com sucesso!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Solicitação
settings.webhook.response=Resposta
settings.webhook.headers=Cabeçalhos
@@ -612,6 +640,7 @@ settings.slack_domain=Domínio
settings.slack_channel=Canal
settings.deploy_keys=Chaves de Deploy
settings.add_deploy_key=Nova chave
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=Você ainda não adicionou chaves para implantação de software.
settings.title=Título
settings.deploy_key_content=Conteúdo da chave
@@ -639,26 +668,26 @@ release.stable=Estável
release.edit=editar
release.ahead=<strong>%d</strong> commits para %s depois desta versão
release.source_code=Código fonte
release.new_subheader=Publish releases to iterate product.
release.edit_subheader=Detailed change log can help users understand what has been improved.
release.new_subheader=Publicar versões para iterar o produto.
release.edit_subheader=Um changelog detalhado ajuda os usuários a entenderem o que foi melhorado.
release.tag_name=Nome da tag
release.target=Destino
release.tag_helper=Escolha uma tag existente, ou crie uma nova tag em publicar.
release.title=Title
release.content=Content
release.title=Título
release.content=Conteúdo
release.write=Escrever
release.preview=Visualizar
release.loading=Carregando...
release.prerelease_desc=Esta é uma versão prévia
release.prerelease_helper=Vou salientar que esta versão é identificada como não pronta para produção.
release.cancel=Cancel
release.cancel=Cancelar
release.publish=Publicar Versão
release.save_draft=Salvar Rascunho
release.edit_release=Editar Versão
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.delete_release=Deletar esta versão
release.deletion=Deleção de versão
release.deletion_desc=Deletar esta versão vai deletar a tag do git correspondente. Você deseja continuar?
release.deletion_success=A versão foi deletada com sucesso!
release.tag_name_already_exist=Já existiu versão com esse nome de tag.
release.downloads=Downloads
@@ -701,17 +730,17 @@ settings.delete_org_title=Deleção da Organização
settings.delete_org_desc=Esta organização será deletada permanentemente, você quer continuar?
settings.hooks_desc=Adicionar Webhooks que serão acionados para <strong>todos os repositórios</strong> dessa organização.
members.membership_visibility=Membership Visibility:
members.membership_visibility=Visibilidade da associação:
members.public=Público
members.public_helper=tornar privado
members.private=Privado
members.private_helper=torar público
members.member_role=Member Role:
members.member_role=Categoria de membro:
members.owner=Dono
members.member=Membro
members.remove=Remover
members.leave=Sair
members.invite_desc=Add a new member to %s:
members.invite_desc=Adicionar novo membro em %s:
members.invite_now=Convidar Agora
teams.join=Juntar-se
@@ -736,7 +765,7 @@ teams.read_permission_desc=Essa equipe concede acesso para <strong>Leitura</stro
teams.write_permission_desc=Esta equipe concede acesso para <strong>escrita</strong>: Membros podem ler e fazer push para os repositórios da equipe.
teams.admin_permission_desc=Esta equipe concede acesso de <strong>Administrador</strong>: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe.
teams.repositories=Repositórios da Equipe
teams.search_repo_placeholder=Search repository...
teams.search_repo_placeholder=Pesquisar repositório...
teams.add_team_repository=Adicionar Repositório da Equipe
teams.remove_repo=Remover
teams.add_nonexistent_repo=O repositório que você está tentando adicionar não existe, por favor, crie-o primeiro.
@@ -767,8 +796,8 @@ dashboard.delete_inactivate_accounts=Excluir todas as contas inativas
dashboard.delete_inactivate_accounts_success=Todas as contas inativas foram excluídas com sucesso.
dashboard.delete_repo_archives=Excluir todos os arquivos dos repositórios
dashboard.delete_repo_archives_success=Todos os arquivos dos repositórios foram excluídos com sucesso.
dashboard.delete_missing_repos=Delete all repository records that lost Git files
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
dashboard.delete_missing_repos=Deletar todos os repositórios que perderam arquivos do git
dashboard.delete_missing_repos_success=Todos os registros de repositórios que perderam arquivos do git foram deletados com sucesso.
dashboard.git_gc_repos=Fazer coleta de lixo nos repositórios
dashboard.git_gc_repos_success=Em todos repositórios, a coleta de lixo foi realizada com sucesso.
dashboard.resync_all_sshkeys=Reescrever o arquivo '.ssh/authorized_keys' (atenção: chaves que não sejam do Gogs serão perdidas)
@@ -861,6 +890,8 @@ auths.bind_password=Vincular senha
auths.bind_password_helper=Atenção: Esta senha é armazenada em texto plano. Não use uma conta com muitos privilégios.
auths.user_base=Base de pesquisa do usuário
auths.user_dn=Usuário do DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=Atributo primeiro nome
auths.attribute_surname=Atributo sobrenome
auths.attribute_mail=Atributo e-mail
@@ -964,11 +995,18 @@ monitor.start=Hora de Início
monitor.execute_time=Tempo de Execução
notices.system_notice_list=Sistema de Notificações
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Tipo
notices.type_1=Repositório
notices.desc=Descrição
notices.op=Op.
notices.delete_success=Aviso do sistema foi deletado com sucesso.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=repositório criado <a href="%s"> %s</a>

View File

@@ -353,7 +353,7 @@ create_repo=Создать репозиторий
default_branch=Ветка по умолчанию
mirror_interval=Интервал зеркалирования (час)
watchers=Наблюдатели
stargazers=Stargazers
stargazers=Звездочеты
forks=Форки
form.name_reserved=Имя репозитория '%s' зарезервировано.
@@ -367,7 +367,7 @@ migrate.clone_address=Скопировать адрес
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь на сервере.
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
migrate.failed=Migration failed: %v
migrate.failed=Миграция не удалась: %v
forked_from=форк от
fork_from_self=Вы не можете форкнуть репозитарий, так как Вы уже его владелец!
@@ -388,9 +388,10 @@ create_new_repo_command=Создать новый репозиторий из к
push_exist_repo=Отправить существующий репозиторий из командной строки
repo_is_empty=Этот репозиторий пуст, пожалуйста, возвращайтесь позже!
code=Code
branch=Ветка
tree=Дерево
filter_branch_and_tag=Filter branch or tag
filter_branch_and_tag=Фильтр по ветке или тегу
branches=Ветки
tags=Метки
issues=Обсуждения
@@ -535,16 +536,39 @@ milestones.deletion=Удаление контрольной точки
milestones.deletion_desc=Удаление этой контрольной точки приведет с удалению всей информации, во всех вопросах (Issues). Вы действительно хотите продолжить?
milestones.deletion_success=Контрольная точка успешно удалена!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=Настройки
settings.options=Опции
settings.collaboration=Сотрудничество
settings.hooks=Автоматическое обновление
settings.githooks=Git хуки
settings.basic_settings=Основные параметры
settings.danger_zone=Опасная зона
settings.site=Официальный сайт
settings.update_settings=Обновить настройки
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=Опасная зона
settings.transfer=Передать права собственности
settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора.
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
@@ -558,6 +582,7 @@ settings.delete_notices_2=- Эта операция перманентно уд
settings.delete_notices_fork_1=- Если данный репозиторий является публичным, все склонированные репозитории останутся независимыми, после его удаления.
settings.delete_notices_fork_2=- Если данный репозиторий является приватным, все его форки будут удалены вместе с ним.
settings.delete_notices_fork_3=- Если вы хотите сохранить все форки после удаления репозитория, то сначала сделайте его публичным.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=Настройка репозитория обновлена успешно.
settings.transfer_owner=Новый владелец
settings.make_transfer=Выполнить передачу
@@ -573,6 +598,9 @@ settings.hooks_desc=Webhooks позволяют внешним службам п
settings.webhook_deletion=Удалить веб-хук
settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей, связанной с ним, информации, включая историю. Хотите продолжить?
settings.webhook_deletion_success=Веб-хук успешно удален!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Запрос
settings.webhook.response=Ответ
settings.webhook.headers=Заголовки
@@ -612,6 +640,7 @@ settings.slack_domain=Домен
settings.slack_channel=Канал
settings.deploy_keys=Ключи развертывания
settings.add_deploy_key=Добавить ключ развертывания
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=Вы не добавляли ключи развертывания.
settings.title=Заголовок
settings.deploy_key_content=Содержимое
@@ -639,13 +668,13 @@ release.stable=Стабильный
release.edit=Редактировать
release.ahead=<strong>%d</strong> коммитов %s начиная с этого релиза
release.source_code=Исходный код
release.new_subheader=Publish releases to iterate product.
release.edit_subheader=Detailed change log can help users understand what has been improved.
release.new_subheader=Публикуйте релизы для итерации продукта.
release.edit_subheader=Подробный журнал изменений может помочь пользователям понять, что было улучшено.
release.tag_name=Имя тега
release.target=Цель
release.tag_helper=Выберите существующий тег, или создайте новый.
release.title=Title
release.content=Content
release.title=Заголовок
release.content=Содержимое
release.write=Запись
release.preview=Предварительный просмотр
release.loading=Загрузка...
@@ -655,10 +684,10 @@ release.cancel=Отменить
release.publish=Опубликовать релиз
release.save_draft=Сохранить черновик
release.edit_release=Редактировать релиз
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.delete_release=Удалить этот релиз
release.deletion=Удаление релиза
release.deletion_desc=Удаление данного релиза так же удалит все относящиеся к нему Git теги. Продолжить?
release.deletion_success=Релиз был успешно удален!
release.tag_name_already_exist=Релиз с этим именем тега уже существует.
release.downloads=Загрузки
@@ -861,6 +890,8 @@ auths.bind_password=Привязать пароль
auths.bind_password_helper=Внимание: Этот пароль сохранен в небезопасном виде. Не используйте высоко-привилегированную учетную запись.
auths.user_base=База для поиска пользователя
auths.user_dn=DN пользователя
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=Имя аттрибута
auths.attribute_surname=Фамилия аттрибута
auths.attribute_mail=Электронная почта аттрибута
@@ -964,11 +995,18 @@ monitor.start=Момент начала
monitor.execute_time=Время выполнения
notices.system_notice_list=Система уведомлений
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=Тип
notices.type_1=Репозиторий
notices.desc=Описание
notices.op=Op.
notices.delete_success=Системное уведомление успешно удалено.
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=создан репозиторий <a href="%s"> %s</a>
@@ -993,13 +1031,13 @@ now=сейчас
1w=1 неделя %s
1mon=1 месяц %s
1y=1 год %s
seconds=%d секунд %s
minutes=%d минут %s
seconds=секунд %[2]s: %[1]d
minutes=минут %[2]s: %[1]d
hours=%d часов %s
days=%d дней %s
weeks=недель %s: %d
months=месяцев %s: %d
years=лет %s: %d
days=дней %[2]s: %[1]d
weeks=недель %[2]s: %[1]d
months=месяцев %[2]s: %[1]d
years=лет %[2]s: %[1]d
raw_seconds=секунд
raw_minutes=минут

View File

@@ -388,6 +388,7 @@ create_new_repo_command=从命令行创建一个新的仓库
push_exist_repo=从命令行推送已经创建的仓库
repo_is_empty=该仓库不包含任何内容,请稍后再进行访问!
code=代码
branch=分支
tree=目录树
filter_branch_and_tag=过滤分支或标签
@@ -535,16 +536,39 @@ milestones.deletion=删除里程碑操作
milestones.deletion_desc=删除该里程碑将会移除所有工单中相关的信息。是否继续?
milestones.deletion_success=里程碑删除成功!
wiki=Wiki
wiki.welcome=欢迎使用 Wiki
wiki.welcome_desc=Wiki 是用于共同协作文档的地方,清晰的文档可以帮助其他人深入了解您的项目。
wiki.create_first_page=创建第一个页面
wiki.page=页面
wiki.filter_page=过滤页面
wiki.new_page=创建新的页面
wiki.default_commit_message=关于此次修改的说明(可选)。
wiki.save_page=保存页面
wiki.last_commit_info=%s 于 %s 修改了此页面
wiki.edit_page_button=修改
wiki.new_page_button=新的页面
wiki.page_already_exists=相同名称的 Wiki 页面已经存在。
wiki.pages=所有页面
wiki.last_updated=最后更新于 %s
settings=仓库设置
settings.options=基本设置
settings.collaboration=管理协作者
settings.hooks=管理 Web 钩子
settings.githooks=管理 Git 钩子
settings.basic_settings=基本设置
settings.danger_zone=危险操作区
settings.site=官方网站
settings.update_settings=更新仓库设置
settings.change_reponame_prompt=该操作将会影响到所有与该仓库有关的链接
settings.advanced_settings=高级设置
settings.wiki_desc=启用 Wiki 以允许用户协作文档
settings.issues_desc=启用内置的轻量级工单管理系统
settings.use_external_issue_tracker=使用外部的工单管理系统
settings.tracker_url_format=外部工单管理系统的 URL 格式
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
settings.pulls_desc=启用合并请求以接受社区贡献
settings.danger_zone=危险操作区
settings.transfer=转移仓库所有权
settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐户或组织。
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
@@ -558,6 +582,7 @@ settings.delete_notices_2=- 此操作将永久删除该仓库,包括 Git 数
settings.delete_notices_fork_1=- 如果该仓库为公开的,则在删除仓库后所有的派生仓库都将转换成独立的仓库。
settings.delete_notices_fork_2=- 如果该仓库为私有,则会同时删除所有的派生仓库。
settings.delete_notices_fork_3=- 如果您想要保留派生仓库,请先将可见性修改为公开的后再进行删除操作。
settings.deletion_success=仓库删除成功!
settings.update_settings_success=仓库设置更新成功!
settings.transfer_owner=新拥有者
settings.make_transfer=确认转移仓库
@@ -573,6 +598,9 @@ settings.hooks_desc=Web 钩子允许您设定在 Gogs 上发生指定事件时
settings.webhook_deletion=删除 Web 钩子
settings.webhook_deletion_desc=删除该 Web 钩子将会删除与其有关的信息和推送历史。是否继续?
settings.webhook_deletion_success=Web 钩子删除成功!
settings.webhook.test_delivery=测试推送
settings.webhook.test_delivery_desc=生成并推送一个模拟的 Push 事件
settings.webhook.test_delivery_success=测试推送已经加入到队列,请耐心等待数秒再刷新推送记录。
settings.webhook.request=请求内容
settings.webhook.response=响应内容
settings.webhook.headers=头信息
@@ -612,6 +640,7 @@ settings.slack_domain=域名
settings.slack_channel=频道
settings.deploy_keys=管理部署密钥
settings.add_deploy_key=添加部署密钥
settings.deploy_key_desc=部署密钥仅具有只读权限,它在功能上和个人用户的公开密钥有本质区别。
settings.no_deploy_keys=您还没有添加任何部署密钥。
settings.title=标题
settings.deploy_key_content=密钥文本
@@ -861,6 +890,8 @@ auths.bind_password=绑定密码
auths.bind_password_helper=警告:该密码将会以明文的形式保存在数据库中。请不要使用拥有高权限的帐户!
auths.user_base=用户搜索基准
auths.user_dn=User DN
auths.attribute_username=用户名属性
auths.attribute_username_placeholder=留空表示使用用户登录时所使用的用户名
auths.attribute_name=名字属性
auths.attribute_surname=姓氏属性
auths.attribute_mail=邮箱属性
@@ -964,6 +995,13 @@ monitor.start=开始时间
monitor.execute_time=已执行时间
notices.system_notice_list=系统提示管理
notices.view_detail_header=查看提示详情
notices.actions=操作
notices.select_all=选中全部
notices.deselect_all=取消所有选中
notices.inverse_selection=反向选中
notices.delete_selected=删除选中项
notices.delete_all=删除所有提示
notices.type=提示类型
notices.type_1=仓库
notices.desc=描述

View File

@@ -111,7 +111,7 @@ admin_title=管理員帳號設置
admin_name=管理員用戶名
admin_password=管理員密碼
confirm_password=確認密碼
admin_email=Admin E-mail
admin_email=Admin Email
install_gogs=立即安裝
test_git_failed=無法識別 'git' 命令:%v
sqlite3_not_available=您所使用的發行版本不支持 SQLite3請從 %s 下載官方構建版,而不是 gobuild 版本。
@@ -161,9 +161,9 @@ password_too_short=密碼長度不能少於 6 位!
[mail]
activate_account=Please activate your account
activate_email=Verify your e-mail address
activate_email=Verify your email address
reset_password=Reset your password
register_success=Register success, Welcome
register_success=Registration successful, welcome
register_notify=Welcome on board
[modal]
@@ -278,9 +278,9 @@ email_desc=您的主要邮箱地址将被用于通知提醒和其它操作。
primary=主要
primary_email=设为主要
delete_email=刪除
email_deletion=E-mail Deletion
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
email_deletion_success=E-mail has been deleted successfully!
email_deletion=Email Deletion
email_deletion_desc=Deleting this email address will remove related information from your account. Do you want to continue?
email_deletion_success=Email has been deleted successfully!
add_new_email=添加新的電子郵件地址
add_email=添加電子郵件
add_email_confirmation_sent=一封待確認的電子郵件已發送到 '%s',請在%d 小時內檢查您的收件箱,並完成確認過程。
@@ -388,6 +388,7 @@ create_new_repo_command=從命令行創建一個新的倉庫
push_exist_repo=從命令行推送已經創建的倉庫
repo_is_empty=This repository is empty, please come back later!
code=Code
branch=分支
tree=目錄樹
filter_branch_and_tag=Filter branch or tag
@@ -535,16 +536,39 @@ milestones.deletion=刪除里程碑
milestones.deletion_desc=刪除該里程碑將會移除所有問題中相關信息。是否繼續?
milestones.deletion_success=里程碑刪除成功!
wiki=Wiki
wiki.welcome=Welcome to Wiki!
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page=Create the first page
wiki.page=Page
wiki.filter_page=Filter page
wiki.new_page=Create New Page
wiki.default_commit_message=Write a note about this update (optional).
wiki.save_page=Save Page
wiki.last_commit_info=%s edited this page %s
wiki.edit_page_button=Edit
wiki.new_page_button=New Page
wiki.page_already_exists=Wiki page with same name already exists.
wiki.pages=Pages
wiki.last_updated=Last updated %s
settings=倉庫設置
settings.options=基本設置
settings.collaboration=管理協作者
settings.hooks=管理 Web 鉤子
settings.githooks=管理 Git 鉤子
settings.basic_settings=基本設置
settings.danger_zone=危險操作區
settings.site=官方網站
settings.update_settings=更新倉庫設置
settings.change_reponame_prompt=This change will affect how links relate to the repository.
settings.advanced_settings=Advanced Settings
settings.wiki_desc=Enable wiki to allow people write documents
settings.issues_desc=Enable builtin lightweight issue tracker
settings.use_external_issue_tracker=Use external issue tracker
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=危險操作區
settings.transfer=轉移倉庫所有權
settings.transfer_desc=您可以將倉庫轉移至您擁有管理員權限的帳戶或組織。
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
@@ -558,6 +582,7 @@ settings.delete_notices_2=- This operation will permanently delete the everythin
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=倉庫設置更新成功!
settings.transfer_owner=新擁有者
settings.make_transfer=確認轉移倉庫
@@ -573,6 +598,9 @@ settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時
settings.webhook_deletion=Delete Webhook
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
settings.webhook_deletion_success=Webhook has been deleted successfully!
settings.webhook.test_delivery=Test Delivery
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
settings.webhook.request=Request
settings.webhook.response=Response
settings.webhook.headers=Headers
@@ -612,6 +640,7 @@ settings.slack_domain=域名
settings.slack_channel=頻道
settings.deploy_keys=管理部署密鑰
settings.add_deploy_key=添加部署密鑰
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
settings.no_deploy_keys=您還沒有添加任何部署密鑰。
settings.title=標題
settings.deploy_key_content=密鑰文本
@@ -657,7 +686,7 @@ release.save_draft=保在草稿
release.edit_release=編輯發佈信息
release.delete_release=Delete This Release
release.deletion=Release Deletion
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success=Release has been deleted successfully!
release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
release.downloads=Downloads
@@ -861,6 +890,8 @@ auths.bind_password=綁定密碼
auths.bind_password_helper=Warning: This password is stored in plain text. Do not use a high privileged account.
auths.user_base=User Search Base
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
auths.attribute_name=名子屬性
auths.attribute_surname=姓氏屬性
auths.attribute_mail=電子郵箱屬性
@@ -964,11 +995,18 @@ monitor.start=開始時間
monitor.execute_time=已執行時間
notices.system_notice_list=系統提示管理
notices.view_detail_header=View Notice Detail
notices.actions=Actions
notices.select_all=Select All
notices.deselect_all=Deselect All
notices.inverse_selection=Inverse Selection
notices.delete_selected=Delete Selected
notices.delete_all=Delete All Notices
notices.type=提示類型
notices.type_1=倉庫
notices.desc=描述
notices.op=操作
notices.delete_success=系統提示刪除成功!
notices.delete_success=System notices have been deleted successfully.
[action]
create_repo=創建了倉庫 <a href="%s">%s</a>

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,6 @@ Directory `/var/gogs` keeps Git repositories and Gogs data:
|-- conf
|-- data
|-- log
|-- templates
### Volume with data container

View File

@@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.7.22.1125 Beta"
const APP_VER = "0.7.33.1205 Beta"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())

View File

@@ -451,24 +451,9 @@ func CommitRepoAction(
IsPrivate: repo.IsPrivate,
}); err != nil {
return fmt.Errorf("NotifyWatchers: %v", err)
}
repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
payloadRepo := &api.PayloadRepo{
ID: repo.ID,
Name: repo.LowerName,
URL: repoLink,
Description: repo.Description,
Website: repo.Website,
Watchers: repo.NumWatches,
Owner: &api.PayloadAuthor{
Name: repo.Owner.DisplayName(),
Email: repo.Owner.Email,
UserName: repo.Owner.Name,
},
Private: repo.IsPrivate,
}
payloadRepo := repo.ComposePayload()
pusher_email, pusher_name := "", ""
pusher, err := GetUserByName(userName)
@@ -494,7 +479,7 @@ func CommitRepoAction(
commits[i] = &api.PayloadCommit{
ID: cmt.Sha1,
Message: cmt.Message,
URL: fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1),
URL: fmt.Sprintf("%s/commit/%s", repo.RepoLink(), cmt.Sha1),
Author: &api.PayloadAuthor{
Name: cmt.AuthorName,
Email: cmt.AuthorEmail,

View File

@@ -5,9 +5,12 @@
package models
import (
"strings"
"time"
"github.com/Unknwon/com"
"github.com/gogits/gogs/modules/base"
)
type NoticeType int
@@ -18,7 +21,7 @@ const (
// Notice represents a system notice for admin.
type Notice struct {
Id int64
ID int64 `xorm:"pk autoincr"`
Type NoticeType
Description string `xorm:"TEXT"`
Created time.Time `xorm:"CREATED"`
@@ -61,3 +64,22 @@ func DeleteNotice(id int64) error {
_, err := x.Id(id).Delete(new(Notice))
return err
}
// DeleteNotices deletes all notices with ID from start to end (inclusive).
func DeleteNotices(start, end int64) error {
sess := x.Where("id >= ?", start)
if end > 0 {
sess.And("id <= ?", end)
}
_, err := sess.Delete(new(Notice))
return err
}
// DeleteNoticesByIDs deletes notices by given IDs.
func DeleteNoticesByIDs(ids []int64) error {
if len(ids) == 0 {
return nil
}
_, err := x.Where("id IN (" + strings.Join(base.Int64sToStrings(ids), ",") + ")").Delete(new(Notice))
return err
}

View File

@@ -107,6 +107,26 @@ func (err ErrUserHasOrgs) Error() string {
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID)
}
// __ __.__ __ .__
// / \ / \__| | _|__|
// \ \/\/ / | |/ / |
// \ /| | <| |
// \__/\ / |__|__|_ \__|
// \/ \/
type ErrWikiAlreadyExist struct {
Title string
}
func IsErrWikiAlreadyExist(err error) bool {
_, ok := err.(ErrWikiAlreadyExist)
return ok
}
func (err ErrWikiAlreadyExist) Error() string {
return fmt.Sprintf("wiki page already exists [title: %s]", err.Title)
}
// __________ ___. .__ .__ ____ __.
// \______ \__ _\_ |__ | | |__| ____ | |/ _|____ ___.__.
// | ___/ | \ __ \| | | |/ ___\ | <_/ __ < | |
@@ -168,6 +188,22 @@ func (err ErrKeyNameAlreadyUsed) Error() string {
return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name)
}
type ErrKeyAccessDenied struct {
UserID int64
KeyID int64
Note string
}
func IsErrKeyAccessDenied(err error) bool {
_, ok := err.(ErrKeyAccessDenied)
return ok
}
func (err ErrKeyAccessDenied) Error() string {
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]",
err.UserID, err.KeyID, err.Note)
}
type ErrDeployKeyNotExist struct {
ID int64
KeyID int64
@@ -492,3 +528,23 @@ func IsErrAttachmentNotExist(err error) bool {
func (err ErrAttachmentNotExist) Error() string {
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
}
// _____ __ .__ __ .__ __ .__
// / _ \ __ ___/ |_| |__ ____ _____/ |_|__| ____ _____ _/ |_|__| ____ ____
// / /_\ \| | \ __\ | \_/ __ \ / \ __\ |/ ___\\__ \\ __\ |/ _ \ / \
// / | \ | /| | | Y \ ___/| | \ | | \ \___ / __ \| | | ( <_> ) | \
// \____|__ /____/ |__| |___| /\___ >___| /__| |__|\___ >____ /__| |__|\____/|___| /
// \/ \/ \/ \/ \/ \/ \/
type ErrAuthenticationNotExist struct {
ID int64
}
func IsErrAuthenticationNotExist(err error) bool {
_, ok := err.(ErrAuthenticationNotExist)
return ok
}
func (err ErrAuthenticationNotExist) Error() string {
return fmt.Sprintf("Authentication does not exist [id: %d]", err.ID)
}

View File

@@ -12,15 +12,14 @@ import (
"os"
"os/exec"
"strings"
"time"
"github.com/Unknwon/com"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
"github.com/Unknwon/com"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
)
@@ -80,36 +79,50 @@ func (diff *Diff) NumFiles() int {
const DIFF_HEAD = "diff --git "
func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
scanner := bufio.NewScanner(reader)
func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
var (
diff = &Diff{Files: make([]*DiffFile, 0)}
curFile *DiffFile
curSection = &DiffSection{
Lines: make([]*DiffLine, 0, 10),
}
leftLine, rightLine int
// FIXME: Should use cache in the future.
buf bytes.Buffer
lineCount int
)
diff := &Diff{Files: make([]*DiffFile, 0)}
var i int
for scanner.Scan() {
line := scanner.Text()
input := bufio.NewReader(reader)
isEOF := false
for {
if isEOF {
break
}
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
isEOF = true
} else {
return nil, fmt.Errorf("ReadString: %v", err)
}
}
if len(line) > 0 && line[len(line)-1] == '\n' {
// Remove line break.
line = line[:len(line)-1]
}
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
continue
}
if line == "" {
} else if len(line) == 0 {
continue
}
i = i + 1
lineCount++
// Diff data too large, we only show the first about maxlines lines
if i >= maxlines {
if lineCount >= maxlines {
log.Warn("Diff data too large")
diff.Files = nil
return diff, nil
@@ -189,17 +202,26 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
diff.Files = append(diff.Files, curFile)
// Check file diff type.
for scanner.Scan() {
for {
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
isEOF = true
} else {
return nil, fmt.Errorf("ReadString: %v", err)
}
}
switch {
case strings.HasPrefix(scanner.Text(), "new file"):
case strings.HasPrefix(line, "new file"):
curFile.Type = DIFF_FILE_ADD
curFile.IsCreated = true
case strings.HasPrefix(scanner.Text(), "deleted"):
case strings.HasPrefix(line, "deleted"):
curFile.Type = DIFF_FILE_DEL
curFile.IsDeleted = true
case strings.HasPrefix(scanner.Text(), "index"):
case strings.HasPrefix(line, "index"):
curFile.Type = DIFF_FILE_CHANGE
case strings.HasPrefix(scanner.Text(), "similarity index 100%"):
case strings.HasPrefix(line, "similarity index 100%"):
curFile.Type = DIFF_FILE_RENAME
curFile.IsRenamed = true
curFile.OldName = curFile.Name
@@ -212,6 +234,8 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
}
}
// FIXME: detect encoding while parsing.
var buf bytes.Buffer
for _, f := range diff.Files {
buf.Reset()
for _, sec := range f.Sections {
@@ -238,61 +262,55 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
return diff, nil
}
func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) {
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxlines int) (*Diff, error) {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return nil, err
}
commit, err := repo.GetCommit(afterCommitId)
commit, err := repo.GetCommit(afterCommitID)
if err != nil {
return nil, err
}
rd, wr := io.Pipe()
var cmd *exec.Cmd
// if "after" commit given
if beforeCommitId == "" {
if len(beforeCommitID) == 0 {
// First commit of repository.
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "show", afterCommitId)
cmd = exec.Command("git", "show", afterCommitID)
} else {
c, _ := commit.Parent(0)
cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitId)
cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitID)
}
} else {
cmd = exec.Command("git", "diff", "-M", beforeCommitId, afterCommitId)
cmd = exec.Command("git", "diff", "-M", beforeCommitID, afterCommitID)
}
cmd.Dir = repoPath
cmd.Stdout = wr
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
done := make(chan error)
go func() {
cmd.Start()
done <- cmd.Wait()
wr.Close()
}()
defer rd.Close()
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("StdoutPipe: %v", err)
}
desc := fmt.Sprintf("GetDiffRange(%s)", repoPath)
pid := process.Add(desc, cmd)
go func() {
// In case process became zombie.
select {
case <-time.After(5 * time.Minute):
if errKill := process.Kill(pid); errKill != nil {
log.Error(4, "git_diff.ParsePatch(Kill): %v", err)
}
<-done
// return "", ErrExecTimeout.Error(), ErrExecTimeout
case err = <-done:
process.Remove(pid)
}
}()
if err = cmd.Start(); err != nil {
return nil, fmt.Errorf("Start: %v", err)
}
return ParsePatch(pid, maxlines, cmd, rd)
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
defer process.Remove(pid)
diff, err := ParsePatch(maxlines, stdout)
if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err)
}
if err = cmd.Wait(); err != nil {
return nil, fmt.Errorf("Wait: %v", err)
}
return diff, nil
}
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {

View File

@@ -1297,7 +1297,7 @@ func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
}
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
// for the milestone associated witht the given issue.
// for the milestone associated with the given issue.
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)

View File

@@ -36,7 +36,6 @@ const (
var (
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
ErrAuthenticationNotExist = errors.New("Authentication does not exist")
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
)
@@ -191,13 +190,14 @@ func LoginSources() ([]*LoginSource, error) {
return auths, x.Find(&auths)
}
// GetLoginSourceByID returns login source by given ID.
func GetLoginSourceByID(id int64) (*LoginSource, error) {
source := new(LoginSource)
has, err := x.Id(id).Get(source)
if err != nil {
return nil, err
} else if !has {
return nil, ErrAuthenticationNotExist
return nil, ErrAuthenticationNotExist{id}
}
return source, nil
}
@@ -225,16 +225,16 @@ func DeleteSource(source *LoginSource) error {
// |_______ \/_______ /\____|__ /____|
// \/ \/ \/
// LoginUserLDAPSource queries if name/passwd can login against the LDAP directory pool,
// LoginUserLDAPSource queries if loginName/passwd can login against the LDAP directory pool,
// and create a local user if success when enabled.
// It returns the same LoginUserPlain semantic.
func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
func LoginUserLDAPSource(u *User, loginName, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
cfg := source.Cfg.(*LDAPConfig)
directBind := (source.Type == DLDAP)
fn, sn, mail, admin, logged := cfg.SearchEntry(name, passwd, directBind)
name, fn, sn, mail, admin, logged := cfg.SearchEntry(loginName, passwd, directBind)
if !logged {
// User not in LDAP, do nothing
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, loginName}
}
if !autoRegister {
@@ -242,6 +242,9 @@ func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, auto
}
// Fallback.
if len(name) == 0 {
name = loginName
}
if len(mail) == 0 {
mail = fmt.Sprintf("%s@localhost", name)
}
@@ -249,10 +252,10 @@ func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, auto
u = &User{
LowerName: strings.ToLower(name),
Name: name,
FullName: strings.TrimSpace(fn + " " + sn),
FullName: composeFullName(fn, sn, name),
LoginType: source.Type,
LoginSource: source.ID,
LoginName: name,
LoginName: loginName,
Email: mail,
IsAdmin: admin,
IsActive: true,
@@ -260,6 +263,19 @@ func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, auto
return u, CreateUser(u)
}
func composeFullName(firstName, surename, userName string) string {
switch {
case len(firstName) == 0 && len(surename) == 0:
return userName
case len(firstName) == 0:
return surename
case len(surename) == 0:
return firstName
default:
return firstName + " " + surename
}
}
// _________ __________________________
// / _____/ / \__ ___/\______ \
// \_____ \ / \ / \| | | ___/

View File

@@ -106,6 +106,11 @@ func Migrate(x *xorm.Engine) error {
}
v := currentVersion.Version
if _MIN_DB_VER > v {
log.Fatal(4, "Gogs no longer supports auto-migration from your previously installed version. Please try to upgrade to a lower version first, then upgrade to current version.")
return nil
}
if int(v-_MIN_DB_VER) > len(migrations) {
// User downgraded Gogs.
currentVersion.Version = int64(len(migrations) + _MIN_DB_VER)

View File

@@ -303,23 +303,23 @@ func addKey(e Engine, key *PublicKey) (err error) {
}
// AddPublicKey adds new public key to database and authorized_keys file.
func AddPublicKey(ownerID int64, name, content string) (err error) {
if err = checkKeyContent(content); err != nil {
return err
func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
if err := checkKeyContent(content); err != nil {
return nil, err
}
// Key name of same user cannot be duplicated.
has, err := x.Where("owner_id=? AND name=?", ownerID, name).Get(new(PublicKey))
if err != nil {
return err
return nil, err
} else if has {
return ErrKeyNameAlreadyUsed{ownerID, name}
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
return nil, err
}
key := &PublicKey{
@@ -330,10 +330,10 @@ func AddPublicKey(ownerID int64, name, content string) (err error) {
Type: KEY_TYPE_USER,
}
if err = addKey(sess, key); err != nil {
return fmt.Errorf("addKey: %v", err)
return nil, fmt.Errorf("addKey: %v", err)
}
return sess.Commit()
return key, sess.Commit()
}
// GetPublicKeyByID returns public key by given ID.
@@ -450,12 +450,18 @@ func deletePublicKey(e *xorm.Session, keyID int64) error {
}
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
func DeletePublicKey(id int64) (err error) {
has, err := x.Id(id).Get(new(PublicKey))
func DeletePublicKey(doer *User, id int64) (err error) {
key, err := GetPublicKeyByID(id)
if err != nil {
return err
} else if !has {
return nil
if IsErrKeyNotExist(err) {
return nil
}
return fmt.Errorf("GetPublicKeyByID: %v", err)
}
// Check if user has access to delete this key.
if !doer.IsAdmin && doer.Id != key.OwnerID {
return ErrKeyAccessDenied{doer.Id, key.ID, "public"}
}
sess := x.NewSession()
@@ -656,13 +662,27 @@ func UpdateDeployKey(key *DeployKey) error {
}
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
func DeleteDeployKey(id int64) error {
key := &DeployKey{ID: id}
has, err := x.Id(key.ID).Get(key)
func DeleteDeployKey(doer *User, id int64) error {
key, err := GetDeployKeyByID(id)
if err != nil {
return err
} else if !has {
return nil
if IsErrDeployKeyNotExist(err) {
return nil
}
return fmt.Errorf("GetDeployKeyByID: %v", err)
}
// Check if user has access to delete this key.
if !doer.IsAdmin {
repo, err := GetRepositoryByID(key.RepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
yes, err := HasAccess(doer, repo, ACCESS_MODE_ADMIN)
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !yes {
return ErrKeyAccessDenied{doer.Id, key.ID, "deploy"}
}
}
sess := x.NewSession()
@@ -676,7 +696,7 @@ func DeleteDeployKey(id int64) error {
}
// Check if this is the last reference to same key content.
has, err = sess.Where("key_id=?", key.KeyID).Get(new(DeployKey))
has, err := sess.Where("key_id=?", key.KeyID).Get(new(DeployKey))
if err != nil {
return err
} else if !has {

View File

@@ -252,7 +252,7 @@ func (pr *PullRequest) testPatch() (err error) {
// Checkout base branch.
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
fmt.Sprintf("PullRequest.Merge(git checkout): %s", pr.BaseRepo.ID),
fmt.Sprintf("PullRequest.Merge(git checkout): %v", pr.BaseRepo.ID),
"git", "checkout", pr.BaseBranch)
if err != nil {
return fmt.Errorf("git checkout: %s", stderr)
@@ -415,12 +415,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
return fmt.Errorf("GetOwner: %v", err)
}
headRepoPath, err := pr.HeadRepo.RepoPath()
if err != nil {
return fmt.Errorf("HeadRepo.RepoPath: %v", err)
}
headGitRepo, err := git.OpenRepository(headRepoPath)
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}

View File

@@ -51,6 +51,10 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
}
func init() {
git.GetVersion()
}
func createTag(gitRepo *git.Repository, rel *Release) error {
// Only actual create when publish.
if !rel.IsDraft {
@@ -175,12 +179,8 @@ func DeleteReleaseByID(id int64) error {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
repoPath, err := repo.RepoPath()
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
_, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
_, stderr, err := process.ExecDir(-1, repo.RepoPath(),
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
"git", "tag", "-d", rel.TagName)
if err != nil && !strings.Contains(stderr, "not found") {
return fmt.Errorf("git tag -d: %v - %s", err, stderr)

View File

@@ -24,11 +24,14 @@ import (
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
"gopkg.in/ini.v1"
"github.com/gogits/git-shell"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
@@ -95,19 +98,15 @@ func NewRepoContext() {
}
// Check Git version.
ver, err := git.GetVersion()
gitVer, err := git.Version()
if err != nil {
log.Fatal(4, "Fail to get Git version: %v", err)
}
reqVer, err := git.ParseVersion("1.7.1")
if err != nil {
log.Fatal(4, "Fail to parse required Git version: %v", err)
}
if ver.LessThan(reqVer) {
log.Info("Git Version: %s", gitVer)
if version.Compare("1.7.1", gitVer, ">") {
log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1")
}
log.Info("Git Version: %s", ver.String())
// Git requires setting user.name and user.email in order to commit changes.
for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} {
@@ -163,6 +162,14 @@ type Repository struct {
IsMirror bool
*Mirror `xorm:"-"`
// Advanced settings
EnableWiki bool `xorm:"NOT NULL DEFAULT true"`
EnableIssues bool `xorm:"NOT NULL DEFAULT true"`
EnableExternalTracker bool
ExternalTrackerFormat string
ExternalMetas map[string]string `xorm:"-"`
EnablePulls bool `xorm:"NOT NULL DEFAULT true"`
IsFork bool `xorm:"NOT NULL DEFAULT false"`
ForkID int64
BaseRepo *Repository `xorm:"-"`
@@ -197,6 +204,39 @@ func (repo *Repository) GetOwner() error {
return repo.getOwner(x)
}
func (repo *Repository) mustOwner(e Engine) *User {
if err := repo.getOwner(e); err != nil {
return &User{
Name: "error",
FullName: err.Error(),
}
}
return repo.Owner
}
// MustOwner always returns a valid *User object to avoid
// conceptually impossible error handling.
// It creates a fake object that contains error deftail
// when error occurs.
func (repo *Repository) MustOwner() *User {
return repo.mustOwner(x)
}
// ComposeMetas composes a map of metas for rendering external issue tracker URL.
func (repo *Repository) ComposeMetas() map[string]string {
if !repo.EnableExternalTracker {
return nil
} else if repo.ExternalMetas == nil {
repo.ExternalMetas = map[string]string{
"format": repo.ExternalTrackerFormat,
"user": repo.MustOwner().Name,
"repo": repo.Name,
}
}
return repo.ExternalMetas
}
// GetAssignees returns all users that have write access of repository.
func (repo *Repository) GetAssignees() (_ []*User, err error) {
if err = repo.GetOwner(); err != nil {
@@ -253,22 +293,16 @@ func (repo *Repository) GetBaseRepo() (err error) {
return err
}
func (repo *Repository) repoPath(e Engine) (string, error) {
if err := repo.getOwner(e); err != nil {
return "", err
}
return RepoPath(repo.Owner.Name, repo.Name), nil
func (repo *Repository) repoPath(e Engine) string {
return RepoPath(repo.mustOwner(e).Name, repo.Name)
}
func (repo *Repository) RepoPath() (string, error) {
func (repo *Repository) RepoPath() string {
return repo.repoPath(x)
}
func (repo *Repository) RepoLink() (string, error) {
if err := repo.GetOwner(); err != nil {
return "", err
}
return setting.AppSubUrl + "/" + repo.Owner.Name + "/" + repo.Name, nil
func (repo *Repository) RepoLink() string {
return setting.AppSubUrl + "/" + repo.MustOwner().Name + "/" + repo.Name
}
func (repo *Repository) HasAccess(u *User) bool {
@@ -305,31 +339,24 @@ func (repo *Repository) LocalCopyPath() string {
return path.Join(setting.AppDataPath, "tmp/local", com.ToStr(repo.ID))
}
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
repoPath, err := repo.RepoPath()
if err != nil {
return err
}
localPath := repo.LocalCopyPath()
func updateLocalCopy(repoPath, localPath string) error {
if !com.IsExist(localPath) {
_, stderr, err := process.Exec(
fmt.Sprintf("UpdateLocalCopy(git clone): %s", repoPath), "git", "clone", repoPath, localPath)
if err != nil {
return fmt.Errorf("git clone: %v - %s", err, stderr)
if err := git.Clone(repoPath, localPath); err != nil {
return fmt.Errorf("Clone: %v", err)
}
} else {
_, stderr, err := process.ExecDir(-1, localPath,
fmt.Sprintf("UpdateLocalCopy(git pull --all): %s", repoPath), "git", "pull", "--all")
if err != nil {
return fmt.Errorf("git pull: %v - %s", err, stderr)
if err := git.Pull(localPath, true); err != nil {
return fmt.Errorf("Pull: %v", err)
}
}
return nil
}
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
return updateLocalCopy(repo.RepoPath(), repo.LocalCopyPath())
}
// PatchPath returns corresponding patch file path of repository by given issue ID.
func (repo *Repository) PatchPath(index int64) (string, error) {
if err := repo.GetOwner(); err != nil {
@@ -346,7 +373,7 @@ func (repo *Repository) SavePatch(index int64, patch []byte) error {
return fmt.Errorf("PatchPath: %v", err)
}
os.MkdirAll(path.Dir(patchPath), os.ModePerm)
os.MkdirAll(filepath.Dir(patchPath), os.ModePerm)
if err = ioutil.WriteFile(patchPath, patch, 0644); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
@@ -354,6 +381,27 @@ func (repo *Repository) SavePatch(index int64, patch []byte) error {
return nil
}
// ComposePayload composes and returns *api.PayloadRepo corresponding to the repository.
func (repo *Repository) ComposePayload() *api.PayloadRepo {
cl := repo.CloneLink()
return &api.PayloadRepo{
ID: repo.ID,
Name: repo.LowerName,
URL: repo.RepoLink(),
SSHURL: cl.SSH,
CloneURL: cl.HTTPS,
Description: repo.Description,
Website: repo.Website,
Watchers: repo.NumWatches,
Owner: &api.PayloadAuthor{
Name: repo.MustOwner().DisplayName(),
Email: repo.MustOwner().Email,
UserName: repo.MustOwner().Name,
},
Private: repo.IsPrivate,
}
}
func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) {
has, err := e.Get(&Repository{
OwnerID: u.Id,
@@ -374,24 +422,31 @@ type CloneLink struct {
Git string
}
// CloneLink returns clone URLs of repository.
func (repo *Repository) CloneLink() (cl CloneLink, err error) {
if err = repo.GetOwner(); err != nil {
return cl, err
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
repoName := repo.Name
if isWiki {
repoName += ".wiki"
}
repo.Owner = repo.MustOwner()
cl := new(CloneLink)
if setting.SSHPort != 22 {
cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.SSHDomain, setting.SSHPort, repo.Owner.Name, repo.Name)
cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.SSHDomain, setting.SSHPort, repo.Owner.Name, repoName)
} else {
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSHDomain, repo.Owner.Name, repo.Name)
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSHDomain, repo.Owner.Name, repoName)
}
cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.Name, repo.Name)
return cl, nil
cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.Name, repoName)
return cl
}
// CloneLink returns clone URLs of repository.
func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(false)
}
var (
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
reservedPatterns = []string{"*.git", "*.keys"}
reservedPatterns = []string{"*.git", "*.keys", "*.wiki"}
)
// IsUsableName checks if name is reserved or pattern of name is not allowed.
@@ -463,6 +518,11 @@ func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
func createUpdateHook(repoPath string) error {
return git.SetUpdateHook(repoPath,
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
}
// MirrorRepository creates a mirror repository from source.
func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
_, stderr, err := process.ExecTimeout(10*time.Minute,
@@ -560,13 +620,19 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
}
// Check if repository has master branch, if so set it to default branch.
// Try to get HEAD branch and set it as default branch.
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return repo, fmt.Errorf("open git repository: %v", err)
log.Error(4, "OpenRepository: %v", err)
return repo, nil
}
if gitRepo.IsBranchExist("master") {
repo.DefaultBranch = "master"
headBranch, err := gitRepo.GetHEADBranch()
if err != nil {
log.Error(4, "GetHEADBranch: %v", err)
return repo, nil
}
if headBranch != nil {
repo.DefaultBranch = headBranch.Name
}
return repo, UpdateRepository(repo, false)
@@ -596,13 +662,6 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
return nil
}
func createUpdateHook(repoPath string) error {
hookPath := path.Join(repoPath, "hooks/update")
os.MkdirAll(path.Dir(hookPath), os.ModePerm)
return ioutil.WriteFile(hookPath,
[]byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)), 0777)
}
type CreateRepoOptions struct {
Name string
Description string
@@ -639,10 +698,7 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
return fmt.Errorf("getRepoInitFile[%s]: %v", opts.Readme, err)
}
cloneLink, err := repo.CloneLink()
if err != nil {
return fmt.Errorf("CloneLink: %v", err)
}
cloneLink := repo.CloneLink()
match := map[string]string{
"Name": repo.Name,
"Description": repo.Description,
@@ -691,22 +747,17 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
}
// InitRepository initializes README and .gitignore if needed.
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) error {
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) (err error) {
// Somehow the directory could exist.
if com.IsExist(repoPath) {
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
}
// Init bare new repository.
os.MkdirAll(repoPath, os.ModePerm)
_, stderr, err := process.ExecDir(-1, repoPath,
fmt.Sprintf("initRepository (git init --bare): %s", repoPath), "git", "init", "--bare")
if err != nil {
return fmt.Errorf("git init --bare: %v - %s", err, stderr)
}
if err := createUpdateHook(repoPath); err != nil {
return err
if err = git.InitRepository(repoPath, true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
} else if err = createUpdateHook(repoPath); err != nil {
return fmt.Errorf("createUpdateHook: %v", err)
}
tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
@@ -794,12 +845,15 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
// CreateRepository creates a repository for given user or organization.
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) {
repo := &Repository{
OwnerID: u.Id,
Owner: u,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.IsPrivate,
OwnerID: u.Id,
Owner: u,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.IsPrivate,
EnableWiki: true,
EnableIssues: true,
EnablePulls: true,
}
sess := x.NewSession()
@@ -977,7 +1031,14 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
// Change repository directory name.
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename directory: %v", err)
return fmt.Errorf("rename repository directory: %v", err)
}
wikiPath := WikiPath(owner.Name, repo.Name)
if com.IsExist(wikiPath) {
if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository wiki: %v", err)
}
}
return sess.Commit()
@@ -999,7 +1060,18 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
}
// Change repository directory name.
return os.Rename(RepoPath(u.LowerName, oldRepoName), RepoPath(u.LowerName, newRepoName))
if err = os.Rename(RepoPath(u.Name, oldRepoName), RepoPath(u.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository directory: %v", err)
}
wikiPath := WikiPath(u.Name, oldRepoName)
if com.IsExist(wikiPath) {
if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository wiki: %v", err)
}
}
return nil
}
func getRepositoriesByForkID(e Engine, forkID int64) ([]*Repository, error) {
@@ -1103,26 +1175,20 @@ func DeleteRepository(uid, repoID int64) error {
}
}
if _, err = sess.Delete(&Repository{ID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&Access{RepoID: repo.ID}); err != nil {
return err
} else if _, err = sess.Delete(&Action{RepoID: repo.ID}); err != nil {
return err
} else if _, err = sess.Delete(&Watch{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&Mirror{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&IssueUser{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&Milestone{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&Release{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&Collaboration{RepoID: repoID}); err != nil {
return err
} else if _, err = sess.Delete(&PullRequest{BaseRepoID: repoID}); err != nil {
return err
if err = deleteBeans(sess,
&Repository{ID: repoID},
&Access{RepoID: repo.ID},
&Action{RepoID: repo.ID},
&Watch{RepoID: repoID},
&Star{RepoID: repoID},
&Mirror{RepoID: repoID},
&IssueUser{RepoID: repoID},
&Milestone{RepoID: repoID},
&Release{RepoID: repoID},
&Collaboration{RepoID: repoID},
&PullRequest{BaseRepoID: repoID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
// Delete comments and attachments.
@@ -1164,12 +1230,18 @@ func DeleteRepository(uid, repoID int64) error {
}
// Remove repository files.
repoPath, err := repo.repoPath(sess)
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
repoPath := repo.repoPath(sess)
if err = os.RemoveAll(repoPath); err != nil {
desc := fmt.Sprintf("delete repository files[%s]: %v", repoPath, err)
desc := fmt.Sprintf("delete repository files [%s]: %v", repoPath, err)
log.Warn(desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
}
wikiPath := repo.WikiPath()
if err = os.RemoveAll(wikiPath); err != nil {
desc := fmt.Sprintf("delete repository wiki [%s]: %v", wikiPath, err)
log.Warn(desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
@@ -1315,14 +1387,7 @@ func DeleteRepositoryArchives() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
return os.RemoveAll(filepath.Join(repoPath, "archives"))
return os.RemoveAll(filepath.Join(repo.RepoPath(), "archives"))
})
}
@@ -1332,15 +1397,7 @@ func DeleteMissingRepositories() error {
if err := x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
if !com.IsDir(repoPath) {
if !com.IsDir(repo.RepoPath()) {
repos = append(repos, repo)
}
return nil
@@ -1371,14 +1428,7 @@ func RewriteRepositoryUpdateHook() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("RewriteRepositoryUpdateHook[%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
return createUpdateHook(repoPath)
return createUpdateHook(repo.RepoPath())
})
}
@@ -1445,11 +1495,7 @@ func MirrorUpdate() {
return nil
}
repoPath, err := m.Repo.RepoPath()
if err != nil {
return fmt.Errorf("Repo.RepoPath: %v", err)
}
repoPath := m.Repo.RepoPath()
if _, stderr, err := process.ExecDir(10*time.Minute,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update", "--prune"); err != nil {
@@ -1489,12 +1535,8 @@ func GitFsck() {
if err := x.Where("id>0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
_, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
repoPath := repo.RepoPath()
_, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
if err != nil {
desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
log.Warn(desc)
@@ -1590,7 +1632,7 @@ func CheckRepoStats() {
repoStatsCheck(checkers[i])
}
// FIXME: use checker when v0.8, stop supporting old fork repo format.
// FIXME: use checker when v0.9, stop supporting old fork repo format.
// ***** START: Repository.NumForks *****
results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
if err != nil {
@@ -1912,15 +1954,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
return nil, err
}
oldRepoPath, err := oldRepo.RepoPath()
if err != nil {
return nil, fmt.Errorf("get old repository path: %v", err)
}
repoPath := RepoPath(u.Name, repo.Name)
_, stderr, err := process.ExecTimeout(10*time.Minute,
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
"git", "clone", "--bare", oldRepoPath, repoPath)
"git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
if err != nil {
return nil, fmt.Errorf("git clone: %v", stderr)
}

View File

@@ -25,9 +25,11 @@ import (
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
oldgit "github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -664,7 +666,7 @@ func deleteUser(e *xorm.Session, u *User) error {
&IssueUser{UID: u.Id},
&EmailAddress{UID: u.Id},
); err != nil {
return fmt.Errorf("deleteUser: %v", err)
return fmt.Errorf("deleteBeans: %v", err)
}
// ***** START: PublicKey *****
@@ -938,11 +940,11 @@ func MakeEmailPrimary(email *EmailAddress) error {
// UserCommit represents a commit with validation of user.
type UserCommit struct {
User *User
*git.Commit
*oldgit.Commit
}
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
func ValidateCommitWithEmail(c *git.Commit) *User {
func ValidateCommitWithEmail(c *oldgit.Commit) *User {
u, err := GetUserByEmail(c.Author.Email)
if err != nil {
return nil
@@ -959,7 +961,7 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
e = oldCommits.Front()
)
for e != nil {
c := e.Value.(*git.Commit)
c := e.Value.(*oldgit.Commit)
if v, ok := emails[c.Author.Email]; !ok {
u, _ = GetUserByEmail(c.Author.Email)

View File

@@ -335,7 +335,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
t.ResponseInfo = &HookResponse{}
if err = json.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
log.Error(3, "Unmarshal[%d]: %v", t.ID, err)
log.Error(3, "Unmarshal [%d]: %v", t.ID, err)
}
}
}
@@ -343,7 +343,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
func (t *HookTask) MarshalJSON(v interface{}) string {
p, err := json.Marshal(v)
if err != nil {
log.Error(3, "Marshal[%d]: %v", t.ID, err)
log.Error(3, "Marshal [%d]: %v", t.ID, err)
}
return string(p)
}
@@ -526,6 +526,8 @@ func (t *HookTask) deliver() {
t.Delivered = time.Now().UTC().UnixNano()
if t.IsSucceed {
log.Trace("Hook delivered: %s", t.UUID)
} else {
log.Trace("Hook delivery failed: %s", t.UUID)
}
// Update webhook last delivery status.
@@ -590,24 +592,24 @@ func DeliverHooks() {
// Update hook task status.
for _, t := range tasks {
if err := UpdateHookTask(t); err != nil {
log.Error(4, "UpdateHookTask(%d): %v", t.ID, err)
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
}
}
// Start listening on new hook requests.
for repoID := range HookQueue.Queue() {
log.Trace("DeliverHooks[%v]: processing delivery hooks", repoID)
log.Trace("DeliverHooks [%v]: processing delivery hooks", repoID)
HookQueue.Remove(repoID)
tasks = make([]*HookTask, 0, 5)
if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil {
log.Error(4, "Get repository(%d) hook tasks: %v", repoID, err)
log.Error(4, "Get repository [%d] hook tasks: %v", repoID, err)
continue
}
for _, t := range tasks {
t.deliver()
if err := UpdateHookTask(t); err != nil {
log.Error(4, "UpdateHookTask[%d]: %v", t.ID, err)
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
continue
}
}

View File

@@ -33,8 +33,9 @@ type SlackPayload struct {
}
type SlackAttachment struct {
Color string `json:"color"`
Text string `json:"text"`
Fallback string `json:"fallback"`
Color string `json:"color"`
Text string `json:"text"`
}
func (p *SlackPayload) SetSecret(_ string) {}
@@ -82,19 +83,19 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
// n new commits
var (
branchName = git.RefEndName(p.Ref)
commitDesc string
commitString string
)
if len(p.Commits) == 1 {
commitString = "1 new commit"
if len(p.CompareUrl) > 0 {
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
}
commitDesc = "1 new commit"
} else {
commitString = fmt.Sprintf("%d new commits", len(p.Commits))
if p.CompareUrl != "" {
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
}
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
}
if len(p.CompareUrl) > 0 {
commitString = SlackLinkFormatter(p.CompareUrl, commitDesc)
} else {
commitString = commitDesc
}
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
@@ -111,7 +112,10 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
}
}
slackAttachments := []SlackAttachment{{Color: slack.Color, Text: attachmentText}}
slackAttachments := []SlackAttachment{{
Color: slack.Color,
Text: attachmentText,
}}
return &SlackPayload{
Channel: slack.Channel,

178
models/wiki.go Normal file
View File

@@ -0,0 +1,178 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"sync"
"github.com/Unknwon/com"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/setting"
)
// workingPool represents a pool of working status which makes sure
// that only one instance of same task is performing at a time.
// However, different type of tasks can performing at the same time.
type workingPool struct {
lock sync.Mutex
pool map[string]*sync.Mutex
count map[string]int
}
// CheckIn checks in a task and waits if others are running.
func (p *workingPool) CheckIn(name string) {
p.lock.Lock()
lock, has := p.pool[name]
if !has {
lock = &sync.Mutex{}
p.pool[name] = lock
}
p.count[name]++
p.lock.Unlock()
lock.Lock()
}
// CheckOut checks out a task to let other tasks run.
func (p *workingPool) CheckOut(name string) {
p.lock.Lock()
defer p.lock.Unlock()
p.pool[name].Unlock()
if p.count[name] == 1 {
delete(p.pool, name)
delete(p.count, name)
} else {
p.count[name]--
}
}
var wikiWorkingPool = &workingPool{
pool: make(map[string]*sync.Mutex),
count: make(map[string]int),
}
// ToWikiPageURL formats a string to corresponding wiki URL name.
func ToWikiPageURL(name string) string {
return strings.Replace(name, " ", "-", -1)
}
// ToWikiPageName formats a URL back to corresponding wiki page name.
func ToWikiPageName(name string) string {
return strings.Replace(name, "-", " ", -1)
}
// WikiCloneLink returns clone URLs of repository wiki.
func (repo *Repository) WikiCloneLink() (cl *CloneLink) {
return repo.cloneLink(true)
}
// WikiPath returns wiki data path by given user and repository name.
func WikiPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
}
func (repo *Repository) WikiPath() string {
return WikiPath(repo.MustOwner().Name, repo.Name)
}
// HasWiki returns true if repository has wiki.
func (repo *Repository) HasWiki() bool {
return com.IsDir(repo.WikiPath())
}
// InitWiki initializes a wiki for repository,
// it does nothing when repository already has wiki.
func (repo *Repository) InitWiki() error {
if repo.HasWiki() {
return nil
}
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
}
return nil
}
func (repo *Repository) LocalWikiPath() string {
return path.Join(setting.AppDataPath, "tmp/local-wiki", com.ToStr(repo.ID))
}
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
func (repo *Repository) UpdateLocalWiki() error {
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
}
// updateWikiPage adds new page to repository wiki.
func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, message string, isNew bool) (err error) {
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.InitWiki(); err != nil {
return fmt.Errorf("InitWiki: %v", err)
}
localPath := repo.LocalWikiPath()
// Discard local commits make sure even to remote when local copy exists.
if com.IsExist(localPath) {
// No need to check if nothing in the repository.
if git.IsBranchExist(localPath, "master") {
if err = git.ResetHEAD(localPath, true, "origin/master"); err != nil {
return fmt.Errorf("Reset: %v", err)
}
}
}
if err = repo.UpdateLocalWiki(); err != nil {
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = ToWikiPageName(strings.Replace(title, "/", " ", -1))
filename := path.Join(localPath, title+".md")
// If not a new file, show perform update not create.
if isNew {
if com.IsExist(filename) {
return ErrWikiAlreadyExist{filename}
}
} else {
os.Remove(path.Join(localPath, oldTitle+".md"))
}
if err = ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
if len(message) == 0 {
message = "Update page '" + title + "'"
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("AddChanges: %v", err)
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", "master"); err != nil {
return fmt.Errorf("Push: %v", err)
}
return nil
}
func (repo *Repository) AddWikiPage(doer *User, title, content, message string) error {
return repo.updateWikiPage(doer, "", title, content, message, true)
}
func (repo *Repository) EditWikiPage(doer *User, oldTitle, title, content, message string) error {
return repo.updateWikiPage(doer, oldTitle, title, content, message, false)
}

View File

@@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,11 +0,0 @@
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=github.com/mmitton/asn1-ber
GOFILES=\
ber.go\
include $(GOROOT)/src/Make.pkg

View File

@@ -1,14 +0,0 @@
ASN1 BER Encoding / Decoding Library for the GO programming language.
Required Librarys:
None
Working:
Very basic encoding / decoding needed for LDAP protocol
Tests Implemented:
None
TODO:
Fix all encoding / decoding to conform to ASN1 BER spec
Implement Tests / Benchmarks

View File

@@ -1,497 +0,0 @@
package ber
import (
"bytes"
"fmt"
"io"
"reflect"
"errors"
)
type Packet struct {
ClassType uint8
TagType uint8
Tag uint8
Value interface{}
ByteValue []byte
Data *bytes.Buffer
Children []*Packet
Description string
}
const (
TagEOC = 0x00
TagBoolean = 0x01
TagInteger = 0x02
TagBitString = 0x03
TagOctetString = 0x04
TagNULL = 0x05
TagObjectIdentifier = 0x06
TagObjectDescriptor = 0x07
TagExternal = 0x08
TagRealFloat = 0x09
TagEnumerated = 0x0a
TagEmbeddedPDV = 0x0b
TagUTF8String = 0x0c
TagRelativeOID = 0x0d
TagSequence = 0x10
TagSet = 0x11
TagNumericString = 0x12
TagPrintableString = 0x13
TagT61String = 0x14
TagVideotexString = 0x15
TagIA5String = 0x16
TagUTCTime = 0x17
TagGeneralizedTime = 0x18
TagGraphicString = 0x19
TagVisibleString = 0x1a
TagGeneralString = 0x1b
TagUniversalString = 0x1c
TagCharacterString = 0x1d
TagBMPString = 0x1e
TagBitmask = 0x1f // xxx11111b
)
var TagMap = map[uint8]string{
TagEOC: "EOC (End-of-Content)",
TagBoolean: "Boolean",
TagInteger: "Integer",
TagBitString: "Bit String",
TagOctetString: "Octet String",
TagNULL: "NULL",
TagObjectIdentifier: "Object Identifier",
TagObjectDescriptor: "Object Descriptor",
TagExternal: "External",
TagRealFloat: "Real (float)",
TagEnumerated: "Enumerated",
TagEmbeddedPDV: "Embedded PDV",
TagUTF8String: "UTF8 String",
TagRelativeOID: "Relative-OID",
TagSequence: "Sequence and Sequence of",
TagSet: "Set and Set OF",
TagNumericString: "Numeric String",
TagPrintableString: "Printable String",
TagT61String: "T61 String",
TagVideotexString: "Videotex String",
TagIA5String: "IA5 String",
TagUTCTime: "UTC Time",
TagGeneralizedTime: "Generalized Time",
TagGraphicString: "Graphic String",
TagVisibleString: "Visible String",
TagGeneralString: "General String",
TagUniversalString: "Universal String",
TagCharacterString: "Character String",
TagBMPString: "BMP String",
}
const (
ClassUniversal = 0 // 00xxxxxxb
ClassApplication = 64 // 01xxxxxxb
ClassContext = 128 // 10xxxxxxb
ClassPrivate = 192 // 11xxxxxxb
ClassBitmask = 192 // 11xxxxxxb
)
var ClassMap = map[uint8]string{
ClassUniversal: "Universal",
ClassApplication: "Application",
ClassContext: "Context",
ClassPrivate: "Private",
}
const (
TypePrimitive = 0 // xx0xxxxxb
TypeConstructed = 32 // xx1xxxxxb
TypeBitmask = 32 // xx1xxxxxb
)
var TypeMap = map[uint8]string{
TypePrimitive: "Primative",
TypeConstructed: "Constructed",
}
var Debug bool = false
func PrintBytes(buf []byte, indent string) {
data_lines := make([]string, (len(buf)/30)+1)
num_lines := make([]string, (len(buf)/30)+1)
for i, b := range buf {
data_lines[i/30] += fmt.Sprintf("%02x ", b)
num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
}
for i := 0; i < len(data_lines); i++ {
fmt.Print(indent + data_lines[i] + "\n")
fmt.Print(indent + num_lines[i] + "\n\n")
}
}
func PrintPacket(p *Packet) {
printPacket(p, 0, false)
}
func printPacket(p *Packet, indent int, printBytes bool) {
indent_str := ""
for len(indent_str) != indent {
indent_str += " "
}
class_str := ClassMap[p.ClassType]
tagtype_str := TypeMap[p.TagType]
tag_str := fmt.Sprintf("0x%02X", p.Tag)
if p.ClassType == ClassUniversal {
tag_str = TagMap[p.Tag]
}
value := fmt.Sprint(p.Value)
description := ""
if p.Description != "" {
description = p.Description + ": "
}
fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
if printBytes {
PrintBytes(p.Bytes(), indent_str)
}
for _, child := range p.Children {
printPacket(child, indent+1, printBytes)
}
}
func resizeBuffer(in []byte, new_size uint64) (out []byte) {
out = make([]byte, new_size)
copy(out, in)
return
}
func readBytes(reader io.Reader, buf []byte) error {
idx := 0
buflen := len(buf)
if reader == nil {
return errors.New("reader was nil, aborting")
}
for idx < buflen {
n, err := reader.Read(buf[idx:])
if err != nil {
return err
}
idx += n
}
return nil
}
func ReadPacket(reader io.Reader) (*Packet, error) {
buf := make([]byte, 2)
err := readBytes(reader, buf)
if err != nil {
return nil, err
}
idx := uint64(2)
datalen := uint64(buf[1])
if Debug {
fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf))
for _, b := range buf {
fmt.Printf("%02X ", b)
}
fmt.Printf("\n")
}
if datalen&128 != 0 {
a := datalen - 128
idx += a
buf = resizeBuffer(buf, 2+a)
err := readBytes(reader, buf[2:])
if err != nil {
return nil, err
}
datalen = DecodeInteger(buf[2 : 2+a])
if Debug {
fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf))
for _, b := range buf {
fmt.Printf("%02X ", b)
}
fmt.Printf("\n")
}
}
buf = resizeBuffer(buf, idx+datalen)
err = readBytes(reader, buf[idx:])
if err != nil {
return nil, err
}
if Debug {
fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen)
for _, b := range buf {
fmt.Printf("%02X ", b)
}
}
p := DecodePacket(buf)
return p, nil
}
func DecodeString(data []byte) (ret string) {
// for _, c := range data {
// ret += fmt.Sprintf("%c", c)
// }
return string(data)
}
func DecodeInteger(data []byte) (ret uint64) {
for _, i := range data {
ret = ret * 256
ret = ret + uint64(i)
}
return
}
func EncodeInteger(val uint64) []byte {
var out bytes.Buffer
found := false
shift := uint(56)
mask := uint64(0xFF00000000000000)
for mask > 0 {
if !found && (val&mask != 0) {
found = true
}
if found || (shift == 0) {
out.Write([]byte{byte((val & mask) >> shift)})
}
shift -= 8
mask = mask >> 8
}
return out.Bytes()
}
func DecodePacket(data []byte) *Packet {
p, _ := decodePacket(data)
return p
}
func decodePacket(data []byte) (*Packet, []byte) {
if Debug {
fmt.Printf("decodePacket: enter %d\n", len(data))
}
p := new(Packet)
p.ClassType = data[0] & ClassBitmask
p.TagType = data[0] & TypeBitmask
p.Tag = data[0] & TagBitmask
datalen := DecodeInteger(data[1:2])
datapos := uint64(2)
if datalen&128 != 0 {
datalen -= 128
datapos += datalen
datalen = DecodeInteger(data[2 : 2+datalen])
}
p.Data = new(bytes.Buffer)
p.Children = make([]*Packet, 0, 2)
p.Value = nil
value_data := data[datapos : datapos+datalen]
if p.TagType == TypeConstructed {
for len(value_data) != 0 {
var child *Packet
child, value_data = decodePacket(value_data)
p.AppendChild(child)
}
} else if p.ClassType == ClassUniversal {
p.Data.Write(data[datapos : datapos+datalen])
p.ByteValue = value_data
switch p.Tag {
case TagEOC:
case TagBoolean:
val := DecodeInteger(value_data)
p.Value = val != 0
case TagInteger:
p.Value = DecodeInteger(value_data)
case TagBitString:
case TagOctetString:
p.Value = DecodeString(value_data)
case TagNULL:
case TagObjectIdentifier:
case TagObjectDescriptor:
case TagExternal:
case TagRealFloat:
case TagEnumerated:
p.Value = DecodeInteger(value_data)
case TagEmbeddedPDV:
case TagUTF8String:
case TagRelativeOID:
case TagSequence:
case TagSet:
case TagNumericString:
case TagPrintableString:
p.Value = DecodeString(value_data)
case TagT61String:
case TagVideotexString:
case TagIA5String:
case TagUTCTime:
case TagGeneralizedTime:
case TagGraphicString:
case TagVisibleString:
case TagGeneralString:
case TagUniversalString:
case TagCharacterString:
case TagBMPString:
}
} else {
p.Data.Write(data[datapos : datapos+datalen])
}
return p, data[datapos+datalen:]
}
func (p *Packet) DataLength() uint64 {
return uint64(p.Data.Len())
}
func (p *Packet) Bytes() []byte {
var out bytes.Buffer
out.Write([]byte{p.ClassType | p.TagType | p.Tag})
packet_length := EncodeInteger(p.DataLength())
if p.DataLength() > 127 || len(packet_length) > 1 {
out.Write([]byte{byte(len(packet_length) | 128)})
out.Write(packet_length)
} else {
out.Write(packet_length)
}
out.Write(p.Data.Bytes())
return out.Bytes()
}
func (p *Packet) AppendChild(child *Packet) {
p.Data.Write(child.Bytes())
if len(p.Children) == cap(p.Children) {
newChildren := make([]*Packet, cap(p.Children)*2)
copy(newChildren, p.Children)
p.Children = newChildren[0:len(p.Children)]
}
p.Children = p.Children[0 : len(p.Children)+1]
p.Children[len(p.Children)-1] = child
}
func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string) *Packet {
p := new(Packet)
p.ClassType = ClassType
p.TagType = TagType
p.Tag = Tag
p.Data = new(bytes.Buffer)
p.Children = make([]*Packet, 0, 2)
p.Value = Value
p.Description = Description
if Value != nil {
v := reflect.ValueOf(Value)
if ClassType == ClassUniversal {
switch Tag {
case TagOctetString:
sv, ok := v.Interface().(string)
if ok {
p.Data.Write([]byte(sv))
}
}
}
}
return p
}
func NewSequence(Description string) *Packet {
return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description)
}
func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet {
intValue := 0
if Value {
intValue = 1
}
p := Encode(ClassType, TagType, Tag, nil, Description)
p.Value = Value
p.Data.Write(EncodeInteger(uint64(intValue)))
return p
}
func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet {
p := Encode(ClassType, TagType, Tag, nil, Description)
p.Value = Value
p.Data.Write(EncodeInteger(Value))
return p
}
func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet {
p := Encode(ClassType, TagType, Tag, nil, Description)
p.Value = Value
p.Data.Write([]byte(Value))
return p
}

View File

@@ -1,73 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package apiv1
import (
"reflect"
"github.com/go-macaron/binding"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/modules/auth"
)
type MarkdownForm struct {
Text string
Mode string
Context string
}
func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validateApiReq(errs, ctx.Data, f)
}
func validateApiReq(errs binding.Errors, data map[string]interface{}, f auth.Form) binding.Errors {
if errs.Len() == 0 {
return errs
}
data["HasError"] = true
typ := reflect.TypeOf(f)
val := reflect.ValueOf(f)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
fieldName := field.Tag.Get("form")
// Allow ignored fields in the struct
if fieldName == "-" {
continue
}
if errs[0].FieldNames[0] == field.Name {
switch errs[0].Classification {
case binding.ERR_REQUIRED:
data["ErrorMsg"] = fieldName + " cannot be empty"
case binding.ERR_ALPHA_DASH:
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) characters"
case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) or dot characters"
case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = fieldName + " must contain at least " + auth.GetMinSize(field) + " characters"
case binding.ERR_MAX_SIZE:
data["ErrorMsg"] = fieldName + " must contain at most " + auth.GetMaxSize(field) + " characters"
case binding.ERR_EMAIL:
data["ErrorMsg"] = fieldName + " is not a valid e-mail address"
case binding.ERR_URL:
data["ErrorMsg"] = fieldName + " is not a valid URL"
default:
data["ErrorMsg"] = "Unknown error: " + errs[0].Classification
}
return errs
}
}
return errs
}

View File

@@ -10,28 +10,29 @@ import (
)
type AuthenticationForm struct {
ID int64
Type int `binding:"Range(2,5)"`
Name string `binding:"Required;MaxSize(30)"`
Host string
Port int
BindDN string
BindPassword string
UserBase string
UserDN string `form:"user_dn"`
AttributeName string
AttributeSurname string
AttributeMail string
Filter string
AdminFilter string
IsActive bool
SMTPAuth string
SMTPHost string
SMTPPort int
AllowedDomains string
TLS bool
SkipVerify bool
PAMServiceName string `form:"pam_service_name"`
ID int64
Type int `binding:"Range(2,5)"`
Name string `binding:"Required;MaxSize(30)"`
Host string
Port int
BindDN string
BindPassword string
UserBase string
UserDN string
AttributeUsername string
AttributeName string
AttributeSurname string
AttributeMail string
Filter string
AdminFilter string
IsActive bool
SMTPAuth string
SMTPHost string
SMTPPort int
AllowedDomains string
TLS bool
SkipVerify bool
PAMServiceName string
}
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View File

@@ -11,27 +11,29 @@ import (
"fmt"
"strings"
"github.com/gogits/gogs/modules/ldap"
"gopkg.in/ldap.v2"
"github.com/gogits/gogs/modules/log"
)
// Basic LDAP authentication service
type Source struct {
Name string // canonical name (ie. corporate.ad)
Host string // LDAP host
Port int // port number
UseSSL bool // Use SSL
SkipVerify bool
BindDN string // DN to bind with
BindPassword string // Bind DN password
UserBase string // Base search path for users
UserDN string // Template for the DN of the user for simple auth
AttributeName string // First name attribute
AttributeSurname string // Surname attribute
AttributeMail string // E-mail attribute
Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin
Enabled bool // if this source is disabled
Name string // canonical name (ie. corporate.ad)
Host string // LDAP host
Port int // port number
UseSSL bool // Use SSL
SkipVerify bool
BindDN string // DN to bind with
BindPassword string // Bind DN password
UserBase string // Base search path for users
UserDN string // Template for the DN of the user for simple auth
AttributeUsername string // Username attribute
AttributeName string // First name attribute
AttributeSurname string // Surname attribute
AttributeMail string // E-mail attribute
Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin
Enabled bool // if this source is disabled
}
func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
@@ -100,7 +102,7 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
userDN := sr.Entries[0].DN
if userDN == "" {
log.Error(4, "LDAP search was succesful, but found no DN!")
log.Error(4, "LDAP search was successful, but found no DN!")
return "", false
}
@@ -108,7 +110,7 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
}
// searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, bool, bool) {
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
var userDN string
if directBind {
log.Trace("LDAP will bind directly via UserDN template: %s", ls.UserDN)
@@ -116,7 +118,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
var ok bool
userDN, ok = ls.sanitizedUserDN(name)
if !ok {
return "", "", "", false, false
return "", "", "", "", false, false
}
} else {
log.Trace("LDAP will use BindDN.")
@@ -124,7 +126,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
var found bool
userDN, found = ls.FindUserDN(name)
if !found {
return "", "", "", false, false
return "", "", "", "", false, false
}
}
@@ -132,7 +134,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
if err != nil {
log.Error(4, "LDAP Connect error (%s): %v", ls.Host, err)
ls.Enabled = false
return "", "", "", false, false
return "", "", "", "", false, false
}
defer l.Close()
@@ -140,13 +142,13 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
err = l.Bind(userDN, passwd)
if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return "", "", "", false, false
return "", "", "", "", false, false
}
log.Trace("Bound successfully with userDN: %s", userDN)
userFilter, ok := ls.sanitizedUserQuery(name)
if !ok {
return "", "", "", false, false
return "", "", "", "", false, false
}
search := ldap.NewSearchRequest(
@@ -157,7 +159,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
sr, err := l.Search(search)
if err != nil {
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
return "", "", "", false, false
return "", "", "", "", false, false
} else if len(sr.Entries) < 1 {
if directBind {
log.Error(4, "User filter inhibited user login.")
@@ -165,9 +167,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
}
return "", "", "", false, false
return "", "", "", "", false, false
}
username_attr := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
name_attr := sr.Entries[0].GetAttributeValue(ls.AttributeName)
sn_attr := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
mail_attr := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
@@ -189,7 +192,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
}
}
return name_attr, sn_attr, mail_attr, admin_attr, true
return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true
}
func ldapDial(ls *Source) (*ldap.Conn, error) {

View File

@@ -87,6 +87,13 @@ type RepoSettingForm struct {
Branch string
Interval int
Private bool
// Advanced settings
EnableWiki bool
EnableIssues bool
EnableExternalTracker bool
TrackerURLFormat string
EnablePulls bool
}
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@@ -237,3 +244,22 @@ type EditReleaseForm struct {
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __ __.__ __ .__
// / \ / \__| | _|__|
// \ \/\/ / | |/ / |
// \ /| | <| |
// \__/\ / |__|__|_ \__|
// \/ \/
type NewWikiForm struct {
OldTitle string
Title string `binding:"Required"`
Content string `binding:"Required"`
Message string
}
// FIXME: use code generation to generate this method.
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View File

@@ -137,50 +137,6 @@ var (
sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
)
func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
ms := MentionPattern.FindAll(rawBytes, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
rawBytes = bytes.Replace(rawBytes, m,
[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
}
ms = commitPattern.FindAll(rawBytes, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "commit/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
` <code><a href="%s">%s</a></code>`, m, ShortSha(string(m[i+7:j])))), -1)
}
ms = issueFullPattern.FindAll(rawBytes, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "issues/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
}
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix)
rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
return rawBytes
}
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
ms := sha1CurrentPattern.FindAll(rawBytes, -1)
for _, m := range ms {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
}
return rawBytes
}
func cutoutVerbosePrefix(prefix string) string {
count := 0
for i := 0; i < len(prefix); i++ {
@@ -194,7 +150,7 @@ func cutoutVerbosePrefix(prefix string) string {
return prefix
}
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
urlPrefix = cutoutVerbosePrefix(urlPrefix)
ms := issueIndexPattern.FindAll(rawBytes, -1)
for _, m := range ms {
@@ -204,24 +160,45 @@ func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
space = " "
m2 = m2[1:]
}
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
space, urlPrefix, m2[1:], m2)), 1)
if metas == nil {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
space, urlPrefix, m2[1:], m2)), 1)
} else {
// Support for external issue tracker
metas["index"] = string(m2[1:])
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s">%s</a>`,
space, com.Expand(metas["format"], metas), m2)), 1)
}
}
return rawBytes
}
func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
ms := MentionPattern.FindAll(rawBytes, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
rawBytes = bytes.Replace(rawBytes, m,
[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
}
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
return rawBytes
}
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
ms := sha1CurrentPattern.FindAll(rawBytes, -1)
for _, m := range ms {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
}
return rawBytes
}
func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
htmlFlags := 0
// htmlFlags |= blackfriday.HTML_USE_XHTML
// htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
// htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
// htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
// htmlFlags |= blackfriday.HTML_SKIP_HTML
htmlFlags |= blackfriday.HTML_SKIP_STYLE
// htmlFlags |= blackfriday.HTML_SKIP_SCRIPT
// htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
// htmlFlags |= blackfriday.HTML_COMPLETE_PAGE
renderer := &CustomRender{
Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""),
urlPrefix: urlPrefix,
@@ -252,9 +229,36 @@ var (
var noEndTags = []string{"img", "input", "br", "hr"}
// PreProcessMarkdown renders full links of commits, issues and pulls to shorter version.
func PreProcessMarkdown(rawHTML []byte, urlPrefix string) []byte {
ms := commitPattern.FindAll(rawHTML, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "commit/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
` <code><a href="%s">%s</a></code>`, m, ShortSha(string(m[i+7:j])))), -1)
}
ms = issueFullPattern.FindAll(rawHTML, -1)
for _, m := range ms {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "issues/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
}
return rawHTML
}
// PostProcessMarkdown treats different types of HTML differently,
// and only renders special links for plain text blocks.
func PostProcessMarkdown(rawHtml []byte, urlPrefix string) []byte {
func PostProcessMarkdown(rawHtml []byte, urlPrefix string, metas map[string]string) []byte {
startTags := make([]string, 0, 5)
var buf bytes.Buffer
tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
@@ -264,7 +268,7 @@ OUTER_LOOP:
token := tokenizer.Token()
switch token.Type {
case html.TextToken:
buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix))
buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas))
case html.StartTagToken:
buf.WriteString(token.String())
@@ -322,13 +326,14 @@ OUTER_LOOP:
return rawHtml
}
func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
result := RenderRawMarkdown(rawBytes, urlPrefix)
result = PostProcessMarkdown(result, urlPrefix)
func RenderMarkdown(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
result := PreProcessMarkdown(rawBytes, urlPrefix)
result = RenderRawMarkdown(result, urlPrefix)
result = PostProcessMarkdown(result, urlPrefix, metas)
result = Sanitizer.SanitizeBytes(result)
return result
}
func RenderMarkdownString(raw, urlPrefix string) string {
return string(RenderMarkdown([]byte(raw), urlPrefix))
func RenderMarkdownString(raw, urlPrefix string, metas map[string]string) string {
return string(RenderMarkdown([]byte(raw), urlPrefix, metas))
}

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,33 +0,0 @@
Basic LDAP v3 functionality for the GO programming language.
Required Librarys:
github.com/johnweldon/asn1-ber
Working:
Connecting to LDAP server
Binding to LDAP server
Searching for entries
Compiling string filters to LDAP filters
Paging Search Results
Modify Requests / Responses
Examples:
search
modify
Tests Implemented:
Filter Compile / Decompile
TODO:
Add Requests / Responses
Delete Requests / Responses
Modify DN Requests / Responses
Compare Requests / Responses
Implement Tests / Benchmarks
This feature is disabled at the moment, because in some cases the "Search Request Done" packet will be handled before the last "Search Request Entry":
Mulitple internal goroutines to handle network traffic
Makes library goroutine safe
Can perform multiple search requests at the same time and return
the results to the proper goroutine. All requests are blocking
requests, so the goroutine does not need special handling

View File

@@ -1,63 +0,0 @@
dn: dc=enterprise,dc=org
objectClass: dcObject
objectClass: organization
o: acme
dn: cn=admin,dc=enterprise,dc=org
objectClass: person
cn: admin
sn: admin
description: "LDAP Admin"
dn: ou=crew,dc=enterprise,dc=org
ou: crew
objectClass: organizationalUnit
dn: cn=kirkj,ou=crew,dc=enterprise,dc=org
cn: kirkj
sn: Kirk
gn: James Tiberius
mail: james.kirk@enterprise.org
objectClass: inetOrgPerson
dn: cn=spock,ou=crew,dc=enterprise,dc=org
cn: spock
sn: Spock
mail: spock@enterprise.org
objectClass: inetOrgPerson
dn: cn=mccoyl,ou=crew,dc=enterprise,dc=org
cn: mccoyl
sn: McCoy
gn: Leonard
mail: leonard.mccoy@enterprise.org
objectClass: inetOrgPerson
dn: cn=scottm,ou=crew,dc=enterprise,dc=org
cn: scottm
sn: Scott
gn: Montgomery
mail: Montgomery.scott@enterprise.org
objectClass: inetOrgPerson
dn: cn=uhuran,ou=crew,dc=enterprise,dc=org
cn: uhuran
sn: Uhura
gn: Nyota
mail: nyota.uhura@enterprise.org
objectClass: inetOrgPerson
dn: cn=suluh,ou=crew,dc=enterprise,dc=org
cn: suluh
sn: Sulu
gn: Hikaru
mail: hikaru.sulu@enterprise.org
objectClass: inetOrgPerson
dn: cn=chekovp,ou=crew,dc=enterprise,dc=org
cn: chekovp
sn: Chekov
gn: pavel
mail: pavel.chekov@enterprise.org
objectClass: inetOrgPerson

View File

@@ -1,89 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"errors"
"fmt"
"log"
"github.com/gogits/gogs/modules/ldap"
)
var (
LdapServer string = "localhost"
LdapPort uint16 = 389
BaseDN string = "dc=enterprise,dc=org"
BindDN string = "cn=admin,dc=enterprise,dc=org"
BindPW string = "enterprise"
Filter string = "(cn=kirkj)"
)
func search(l *ldap.Conn, filter string, attributes []string) (*ldap.Entry, *ldap.Error) {
search := ldap.NewSearchRequest(
BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter,
attributes,
nil)
sr, err := l.Search(search)
if err != nil {
log.Fatalf("ERROR: %s\n", err)
return nil, err
}
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
if len(sr.Entries) == 0 {
return nil, ldap.NewError(ldap.ErrorDebugging, errors.New(fmt.Sprintf("no entries found for: %s", filter)))
}
return sr.Entries[0], nil
}
func main() {
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort))
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
defer l.Close()
// l.Debug = true
l.Bind(BindDN, BindPW)
log.Printf("The Search for Kirk ... %s\n", Filter)
entry, err := search(l, Filter, []string{})
if err != nil {
log.Fatal("could not get entry")
}
entry.PrettyPrint(0)
log.Printf("modify the mail address and add a description ... \n")
modify := ldap.NewModifyRequest(entry.DN)
modify.Add("description", []string{"Captain of the USS Enterprise"})
modify.Replace("mail", []string{"captain@enterprise.org"})
if err := l.Modify(modify); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
entry, err = search(l, Filter, []string{})
if err != nil {
log.Fatal("could not get entry")
}
entry.PrettyPrint(0)
log.Printf("reset the entry ... \n")
modify = ldap.NewModifyRequest(entry.DN)
modify.Delete("description", []string{})
modify.Replace("mail", []string{"james.kirk@enterprise.org"})
if err := l.Modify(modify); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
entry, err = search(l, Filter, []string{})
if err != nil {
log.Fatal("could not get entry")
}
entry.PrettyPrint(0)
}

View File

@@ -1,52 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"log"
"github.com/gogits/gogs/modules/ldap"
)
var (
ldapServer string = "adserver"
ldapPort uint16 = 3268
baseDN string = "dc=*,dc=*"
filter string = "(&(objectClass=user)(sAMAccountName=*)(memberOf=CN=*,OU=*,DC=*,DC=*))"
Attributes []string = []string{"memberof"}
user string = "*"
passwd string = "*"
)
func main() {
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
defer l.Close()
// l.Debug = true
err = l.Bind(user, passwd)
if err != nil {
log.Printf("ERROR: Cannot bind: %s\n", err.Error())
return
}
search := ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter,
Attributes,
nil)
sr, err := l.Search(search)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
return
}
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
sr.PrettyPrint(0)
}

View File

@@ -1,45 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"log"
"github.com/gogits/gogs/modules/ldap"
)
var (
LdapServer string = "localhost"
LdapPort uint16 = 636
BaseDN string = "dc=enterprise,dc=org"
Filter string = "(cn=kirkj)"
Attributes []string = []string{"mail"}
)
func main() {
l, err := ldap.DialSSL("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil)
if err != nil {
log.Fatalf("ERROR: %s\n", err.String())
}
defer l.Close()
// l.Debug = true
search := ldap.NewSearchRequest(
BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
Filter,
Attributes,
nil)
sr, err := l.Search(search)
if err != nil {
log.Fatalf("ERROR: %s\n", err.String())
return
}
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
sr.PrettyPrint(0)
}

View File

@@ -1,45 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"log"
"github.com/gogits/gogs/modules/ldap"
)
var (
LdapServer string = "localhost"
LdapPort uint16 = 389
BaseDN string = "dc=enterprise,dc=org"
Filter string = "(cn=kirkj)"
Attributes []string = []string{"mail"}
)
func main() {
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", LdapServer, LdapPort), nil)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
defer l.Close()
// l.Debug = true
search := ldap.NewSearchRequest(
BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
Filter,
Attributes,
nil)
sr, err := l.Search(search)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
return
}
log.Printf("Search: %s -> num of entries = %d\n", search.Filter, len(sr.Entries))
sr.PrettyPrint(0)
}

View File

@@ -1,67 +0,0 @@
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /private/etc/openldap/schema/core.schema
include /private/etc/openldap/schema/cosine.schema
include /private/etc/openldap/schema/inetorgperson.schema
# Define global ACLs to disable default read access.
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org
pidfile /private/var/db/openldap/run/slapd.pid
argsfile /private/var/db/openldap/run/slapd.args
# Load dynamic backend modules:
# modulepath /usr/libexec/openldap
# moduleload back_bdb.la
# moduleload back_hdb.la
# moduleload back_ldap.la
# Sample security restrictions
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64
# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
# access to *
# by self write
# by users read
# by anonymous auth
#
# if no access controls are present, the default policy
# allows anyone and everyone to read anything but restricts
# updates to rootdn. (e.g., "access to * by * read")
#
# rootdn can always read and write EVERYTHING!
#######################################################################
# BDB database definitions
#######################################################################
database bdb
suffix "dc=enterprise,dc=org"
rootdn "cn=admin,dc=enterprise,dc=org"
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {SSHA}laO00HsgszhK1O0Z5qR0/i/US69Osfeu
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /private/var/db/openldap/openldap-data
# Indices to maintain
index objectClass eq

View File

@@ -1,55 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ldap
import (
"errors"
"github.com/gogits/gogs/modules/asn1-ber"
)
func (l *Conn) Bind(username, password string) error {
messageID := l.nextMessageID()
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
packet.AppendChild(bindRequest)
if l.Debug {
ber.PrintPacket(packet)
}
channel, err := l.sendMessage(packet)
if err != nil {
return err
}
if channel == nil {
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
}
defer l.finishMessage(messageID)
packet = <-channel
if packet == nil {
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve response"))
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return err
}
ber.PrintPacket(packet)
}
resultCode, resultDescription := getLDAPResultCode(packet)
if resultCode != 0 {
return NewError(resultCode, errors.New(resultDescription))
}
return nil
}

View File

@@ -1,275 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ldap
import (
"crypto/tls"
"errors"
"log"
"net"
"sync"
"github.com/gogits/gogs/modules/asn1-ber"
)
const (
MessageQuit = 0
MessageRequest = 1
MessageResponse = 2
MessageFinish = 3
)
type messagePacket struct {
Op int
MessageID uint64
Packet *ber.Packet
Channel chan *ber.Packet
}
// Conn represents an LDAP Connection
type Conn struct {
conn net.Conn
isTLS bool
isClosing bool
Debug debugging
chanConfirm chan bool
chanResults map[uint64]chan *ber.Packet
chanMessage chan *messagePacket
chanMessageID chan uint64
wgSender sync.WaitGroup
wgClose sync.WaitGroup
once sync.Once
}
// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
c, err := net.Dial(network, addr)
if err != nil {
return nil, NewError(ErrorNetwork, err)
}
conn := NewConn(c)
conn.start()
return conn, nil
}
// DialTLS connects to the given address on the given network using tls.Dial
// and then returns a new Conn for the connection.
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
c, err := tls.Dial(network, addr, config)
if err != nil {
return nil, NewError(ErrorNetwork, err)
}
conn := NewConn(c)
conn.isTLS = true
conn.start()
return conn, nil
}
// NewConn returns a new Conn using conn for network I/O.
func NewConn(conn net.Conn) *Conn {
return &Conn{
conn: conn,
chanConfirm: make(chan bool),
chanMessageID: make(chan uint64),
chanMessage: make(chan *messagePacket, 10),
chanResults: map[uint64]chan *ber.Packet{},
}
}
func (l *Conn) start() {
go l.reader()
go l.processMessages()
l.wgClose.Add(1)
}
// Close closes the connection.
func (l *Conn) Close() {
l.once.Do(func() {
l.isClosing = true
l.wgSender.Wait()
l.Debug.Printf("Sending quit message and waiting for confirmation")
l.chanMessage <- &messagePacket{Op: MessageQuit}
<-l.chanConfirm
close(l.chanMessage)
l.Debug.Printf("Closing network connection")
if err := l.conn.Close(); err != nil {
log.Print(err)
}
l.conn = nil
l.wgClose.Done()
})
l.wgClose.Wait()
}
// Returns the next available messageID
func (l *Conn) nextMessageID() uint64 {
if l.chanMessageID != nil {
if messageID, ok := <-l.chanMessageID; ok {
return messageID
}
}
return 0
}
// StartTLS sends the command to start a TLS session and then creates a new TLS Client
func (l *Conn) StartTLS(config *tls.Config) error {
messageID := l.nextMessageID()
if l.isTLS {
return NewError(ErrorNetwork, errors.New("ldap: already encrypted"))
}
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
packet.AppendChild(request)
l.Debug.PrintPacket(packet)
_, err := l.conn.Write(packet.Bytes())
if err != nil {
return NewError(ErrorNetwork, err)
}
packet, err = ber.ReadPacket(l.conn)
if err != nil {
return NewError(ErrorNetwork, err)
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return err
}
ber.PrintPacket(packet)
}
if packet.Children[1].Children[0].Value.(uint64) == 0 {
conn := tls.Client(l.conn, config)
l.isTLS = true
l.conn = conn
}
return nil
}
func (l *Conn) sendMessage(packet *ber.Packet) (chan *ber.Packet, error) {
if l.isClosing {
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
}
out := make(chan *ber.Packet)
message := &messagePacket{
Op: MessageRequest,
MessageID: packet.Children[0].Value.(uint64),
Packet: packet,
Channel: out,
}
l.sendProcessMessage(message)
return out, nil
}
func (l *Conn) finishMessage(messageID uint64) {
if l.isClosing {
return
}
message := &messagePacket{
Op: MessageFinish,
MessageID: messageID,
}
l.sendProcessMessage(message)
}
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
if l.isClosing {
return false
}
l.wgSender.Add(1)
l.chanMessage <- message
l.wgSender.Done()
return true
}
func (l *Conn) processMessages() {
defer func() {
for messageID, channel := range l.chanResults {
l.Debug.Printf("Closing channel for MessageID %d", messageID)
close(channel)
delete(l.chanResults, messageID)
}
close(l.chanMessageID)
l.chanConfirm <- true
close(l.chanConfirm)
}()
var messageID uint64 = 1
for {
select {
case l.chanMessageID <- messageID:
messageID++
case messagePacket, ok := <-l.chanMessage:
if !ok {
l.Debug.Printf("Shutting down - message channel is closed")
return
}
switch messagePacket.Op {
case MessageQuit:
l.Debug.Printf("Shutting down - quit message received")
return
case MessageRequest:
// Add to message list and write to network
l.Debug.Printf("Sending message %d", messagePacket.MessageID)
l.chanResults[messagePacket.MessageID] = messagePacket.Channel
// go routine
buf := messagePacket.Packet.Bytes()
_, err := l.conn.Write(buf)
if err != nil {
l.Debug.Printf("Error Sending Message: %s", err.Error())
break
}
case MessageResponse:
l.Debug.Printf("Receiving message %d", messagePacket.MessageID)
if chanResult, ok := l.chanResults[messagePacket.MessageID]; ok {
chanResult <- messagePacket.Packet
} else {
log.Printf("Received unexpected message %d", messagePacket.MessageID)
ber.PrintPacket(messagePacket.Packet)
}
case MessageFinish:
// Remove from message list
l.Debug.Printf("Finished message %d", messagePacket.MessageID)
close(l.chanResults[messagePacket.MessageID])
delete(l.chanResults, messagePacket.MessageID)
}
}
}
}
func (l *Conn) reader() {
defer func() {
l.Close()
}()
for {
packet, err := ber.ReadPacket(l.conn)
if err != nil {
l.Debug.Printf("reader: %s", err.Error())
return
}
addLDAPDescriptions(packet)
message := &messagePacket{
Op: MessageResponse,
MessageID: packet.Children[0].Value.(uint64),
Packet: packet,
}
if !l.sendProcessMessage(message) {
return
}
}
}

View File

@@ -1,157 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ldap
import (
"fmt"
"github.com/gogits/gogs/modules/asn1-ber"
)
const (
ControlTypePaging = "1.2.840.113556.1.4.319"
)
var ControlTypeMap = map[string]string{
ControlTypePaging: "Paging",
}
type Control interface {
GetControlType() string
Encode() *ber.Packet
String() string
}
type ControlString struct {
ControlType string
Criticality bool
ControlValue string
}
func (c *ControlString) GetControlType() string {
return c.ControlType
}
func (c *ControlString) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
if c.Criticality {
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
}
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlValue, "Control Value"))
return packet
}
func (c *ControlString) String() string {
return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
}
type ControlPaging struct {
PagingSize uint32
Cookie []byte
}
func (c *ControlPaging) GetControlType() string {
return ControlTypePaging
}
func (c *ControlPaging) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size"))
cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
cookie.Value = c.Cookie
cookie.Data.Write(c.Cookie)
seq.AppendChild(cookie)
p2.AppendChild(seq)
packet.AppendChild(p2)
return packet
}
func (c *ControlPaging) String() string {
return fmt.Sprintf(
"Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q",
ControlTypeMap[ControlTypePaging],
ControlTypePaging,
false,
c.PagingSize,
c.Cookie)
}
func (c *ControlPaging) SetCookie(cookie []byte) {
c.Cookie = cookie
}
func FindControl(controls []Control, controlType string) Control {
for _, c := range controls {
if c.GetControlType() == controlType {
return c
}
}
return nil
}
func DecodeControl(packet *ber.Packet) Control {
ControlType := packet.Children[0].Value.(string)
Criticality := false
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
value := packet.Children[1]
if len(packet.Children) == 3 {
value = packet.Children[2]
packet.Children[1].Description = "Criticality"
Criticality = packet.Children[1].Value.(bool)
}
value.Description = "Control Value"
switch ControlType {
case ControlTypePaging:
value.Description += " (Paging)"
c := new(ControlPaging)
if value.Value != nil {
valueChildren := ber.DecodePacket(value.Data.Bytes())
value.Data.Truncate(0)
value.Value = nil
value.AppendChild(valueChildren)
}
value = value.Children[0]
value.Description = "Search Control Value"
value.Children[0].Description = "Paging Size"
value.Children[1].Description = "Cookie"
c.PagingSize = uint32(value.Children[0].Value.(uint64))
c.Cookie = value.Children[1].Data.Bytes()
value.Children[1].Value = c.Cookie
return c
}
c := new(ControlString)
c.ControlType = ControlType
c.Criticality = Criticality
c.ControlValue = value.Value.(string)
return c
}
func NewControlString(controlType string, criticality bool, controlValue string) *ControlString {
return &ControlString{
ControlType: controlType,
Criticality: criticality,
ControlValue: controlValue,
}
}
func NewControlPaging(pagingSize uint32) *ControlPaging {
return &ControlPaging{PagingSize: pagingSize}
}
func encodeControls(controls []Control) *ber.Packet {
packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
for _, control := range controls {
packet.AppendChild(control.Encode())
}
return packet
}

View File

@@ -1,24 +0,0 @@
package ldap
import (
"log"
"github.com/gogits/gogs/modules/asn1-ber"
)
// debugging type
// - has a Printf method to write the debug output
type debugging bool
// write debug output
func (debug debugging) Printf(format string, args ...interface{}) {
if debug {
log.Printf(format, args...)
}
}
func (debug debugging) PrintPacket(packet *ber.Packet) {
if debug {
ber.PrintPacket(packet)
}
}

View File

@@ -1,248 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ldap
import (
"errors"
"fmt"
"github.com/gogits/gogs/modules/asn1-ber"
)
const (
FilterAnd = 0
FilterOr = 1
FilterNot = 2
FilterEqualityMatch = 3
FilterSubstrings = 4
FilterGreaterOrEqual = 5
FilterLessOrEqual = 6
FilterPresent = 7
FilterApproxMatch = 8
FilterExtensibleMatch = 9
)
var FilterMap = map[uint64]string{
FilterAnd: "And",
FilterOr: "Or",
FilterNot: "Not",
FilterEqualityMatch: "Equality Match",
FilterSubstrings: "Substrings",
FilterGreaterOrEqual: "Greater Or Equal",
FilterLessOrEqual: "Less Or Equal",
FilterPresent: "Present",
FilterApproxMatch: "Approx Match",
FilterExtensibleMatch: "Extensible Match",
}
const (
FilterSubstringsInitial = 0
FilterSubstringsAny = 1
FilterSubstringsFinal = 2
)
var FilterSubstringsMap = map[uint64]string{
FilterSubstringsInitial: "Substrings Initial",
FilterSubstringsAny: "Substrings Any",
FilterSubstringsFinal: "Substrings Final",
}
func CompileFilter(filter string) (*ber.Packet, error) {
if len(filter) == 0 || filter[0] != '(' {
return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('"))
}
packet, pos, err := compileFilter(filter, 1)
if err != nil {
return nil, err
}
if pos != len(filter) {
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
}
return packet, nil
}
func DecompileFilter(packet *ber.Packet) (ret string, err error) {
defer func() {
if r := recover(); r != nil {
err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
}
}()
ret = "("
err = nil
childStr := ""
switch packet.Tag {
case FilterAnd:
ret += "&"
for _, child := range packet.Children {
childStr, err = DecompileFilter(child)
if err != nil {
return
}
ret += childStr
}
case FilterOr:
ret += "|"
for _, child := range packet.Children {
childStr, err = DecompileFilter(child)
if err != nil {
return
}
ret += childStr
}
case FilterNot:
ret += "!"
childStr, err = DecompileFilter(packet.Children[0])
if err != nil {
return
}
ret += childStr
case FilterSubstrings:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += "="
switch packet.Children[1].Children[0].Tag {
case FilterSubstringsInitial:
ret += ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
case FilterSubstringsAny:
ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
case FilterSubstringsFinal:
ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes())
}
case FilterEqualityMatch:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += "="
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
case FilterGreaterOrEqual:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += ">="
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
case FilterLessOrEqual:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += "<="
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
case FilterPresent:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += "=*"
case FilterApproxMatch:
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
ret += "~="
ret += ber.DecodeString(packet.Children[1].Data.Bytes())
}
ret += ")"
return
}
func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) {
for pos < len(filter) && filter[pos] == '(' {
child, newPos, err := compileFilter(filter, pos+1)
if err != nil {
return pos, err
}
pos = newPos
parent.AppendChild(child)
}
if pos == len(filter) {
return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
}
return pos + 1, nil
}
func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
var packet *ber.Packet
var err error
defer func() {
if r := recover(); r != nil {
err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter"))
}
}()
newPos := pos
switch filter[pos] {
case '(':
packet, newPos, err = compileFilter(filter, pos+1)
newPos++
return packet, newPos, err
case '&':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd])
newPos, err = compileFilterSet(filter, pos+1, packet)
return packet, newPos, err
case '|':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr])
newPos, err = compileFilterSet(filter, pos+1, packet)
return packet, newPos, err
case '!':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot])
var child *ber.Packet
child, newPos, err = compileFilter(filter, pos+1)
packet.AppendChild(child)
return packet, newPos, err
default:
attribute := ""
condition := ""
for newPos < len(filter) && filter[newPos] != ')' {
switch {
case packet != nil:
condition += fmt.Sprintf("%c", filter[newPos])
case filter[newPos] == '=':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch])
case filter[newPos] == '>' && filter[newPos+1] == '=':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual])
newPos++
case filter[newPos] == '<' && filter[newPos+1] == '=':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual])
newPos++
case filter[newPos] == '~' && filter[newPos+1] == '=':
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterLessOrEqual])
newPos++
case packet == nil:
attribute += fmt.Sprintf("%c", filter[newPos])
}
newPos++
}
if newPos == len(filter) {
err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
return packet, newPos, err
}
if packet == nil {
err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter"))
return packet, newPos, err
}
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
switch {
case packet.Tag == FilterEqualityMatch && condition == "*":
packet.Tag = FilterPresent
packet.Description = FilterMap[uint64(packet.Tag)]
case packet.Tag == FilterEqualityMatch && condition[0] == '*' && condition[len(condition)-1] == '*':
// Any
packet.Tag = FilterSubstrings
packet.Description = FilterMap[uint64(packet.Tag)]
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsAny, condition[1:len(condition)-1], "Any Substring"))
packet.AppendChild(seq)
case packet.Tag == FilterEqualityMatch && condition[0] == '*':
// Final
packet.Tag = FilterSubstrings
packet.Description = FilterMap[uint64(packet.Tag)]
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsFinal, condition[1:], "Final Substring"))
packet.AppendChild(seq)
case packet.Tag == FilterEqualityMatch && condition[len(condition)-1] == '*':
// Initial
packet.Tag = FilterSubstrings
packet.Description = FilterMap[uint64(packet.Tag)]
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterSubstringsInitial, condition[:len(condition)-1], "Initial Substring"))
packet.AppendChild(seq)
default:
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, condition, "Condition"))
}
newPos++
return packet, newPos, err
}
}

View File

@@ -1,78 +0,0 @@
package ldap
import (
"testing"
"github.com/gogits/gogs/modules/asn1-ber"
)
type compileTest struct {
filterStr string
filterType int
}
var testFilters = []compileTest{
compileTest{filterStr: "(&(sn=Miller)(givenName=Bob))", filterType: FilterAnd},
compileTest{filterStr: "(|(sn=Miller)(givenName=Bob))", filterType: FilterOr},
compileTest{filterStr: "(!(sn=Miller))", filterType: FilterNot},
compileTest{filterStr: "(sn=Miller)", filterType: FilterEqualityMatch},
compileTest{filterStr: "(sn=Mill*)", filterType: FilterSubstrings},
compileTest{filterStr: "(sn=*Mill)", filterType: FilterSubstrings},
compileTest{filterStr: "(sn=*Mill*)", filterType: FilterSubstrings},
compileTest{filterStr: "(sn>=Miller)", filterType: FilterGreaterOrEqual},
compileTest{filterStr: "(sn<=Miller)", filterType: FilterLessOrEqual},
compileTest{filterStr: "(sn=*)", filterType: FilterPresent},
compileTest{filterStr: "(sn~=Miller)", filterType: FilterApproxMatch},
// compileTest{ filterStr: "()", filterType: FilterExtensibleMatch },
}
func TestFilter(t *testing.T) {
// Test Compiler and Decompiler
for _, i := range testFilters {
filter, err := CompileFilter(i.filterStr)
if err != nil {
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
} else if filter.Tag != uint8(i.filterType) {
t.Errorf("%q Expected %q got %q", i.filterStr, FilterMap[uint64(i.filterType)], FilterMap[uint64(filter.Tag)])
} else {
o, err := DecompileFilter(filter)
if err != nil {
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
} else if i.filterStr != o {
t.Errorf("%q expected, got %q", i.filterStr, o)
}
}
}
}
func BenchmarkFilterCompile(b *testing.B) {
b.StopTimer()
filters := make([]string, len(testFilters))
// Test Compiler and Decompiler
for idx, i := range testFilters {
filters[idx] = i.filterStr
}
maxIdx := len(filters)
b.StartTimer()
for i := 0; i < b.N; i++ {
CompileFilter(filters[i%maxIdx])
}
}
func BenchmarkFilterDecompile(b *testing.B) {
b.StopTimer()
filters := make([]*ber.Packet, len(testFilters))
// Test Compiler and Decompiler
for idx, i := range testFilters {
filters[idx], _ = CompileFilter(i.filterStr)
}
maxIdx := len(filters)
b.StartTimer()
for i := 0; i < b.N; i++ {
DecompileFilter(filters[i%maxIdx])
}
}

View File

@@ -1,302 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ldap
import (
"errors"
"fmt"
"io/ioutil"
"github.com/gogits/gogs/modules/asn1-ber"
)
// LDAP Application Codes
const (
ApplicationBindRequest = 0
ApplicationBindResponse = 1
ApplicationUnbindRequest = 2
ApplicationSearchRequest = 3
ApplicationSearchResultEntry = 4
ApplicationSearchResultDone = 5
ApplicationModifyRequest = 6
ApplicationModifyResponse = 7
ApplicationAddRequest = 8
ApplicationAddResponse = 9
ApplicationDelRequest = 10
ApplicationDelResponse = 11
ApplicationModifyDNRequest = 12
ApplicationModifyDNResponse = 13
ApplicationCompareRequest = 14
ApplicationCompareResponse = 15
ApplicationAbandonRequest = 16
ApplicationSearchResultReference = 19
ApplicationExtendedRequest = 23
ApplicationExtendedResponse = 24
)
var ApplicationMap = map[uint8]string{
ApplicationBindRequest: "Bind Request",
ApplicationBindResponse: "Bind Response",
ApplicationUnbindRequest: "Unbind Request",
ApplicationSearchRequest: "Search Request",
ApplicationSearchResultEntry: "Search Result Entry",
ApplicationSearchResultDone: "Search Result Done",
ApplicationModifyRequest: "Modify Request",
ApplicationModifyResponse: "Modify Response",
ApplicationAddRequest: "Add Request",
ApplicationAddResponse: "Add Response",
ApplicationDelRequest: "Del Request",
ApplicationDelResponse: "Del Response",
ApplicationModifyDNRequest: "Modify DN Request",
ApplicationModifyDNResponse: "Modify DN Response",
ApplicationCompareRequest: "Compare Request",
ApplicationCompareResponse: "Compare Response",
ApplicationAbandonRequest: "Abandon Request",
ApplicationSearchResultReference: "Search Result Reference",
ApplicationExtendedRequest: "Extended Request",
ApplicationExtendedResponse: "Extended Response",
}
// LDAP Result Codes
const (
LDAPResultSuccess = 0
LDAPResultOperationsError = 1
LDAPResultProtocolError = 2
LDAPResultTimeLimitExceeded = 3
LDAPResultSizeLimitExceeded = 4
LDAPResultCompareFalse = 5
LDAPResultCompareTrue = 6
LDAPResultAuthMethodNotSupported = 7
LDAPResultStrongAuthRequired = 8
LDAPResultReferral = 10
LDAPResultAdminLimitExceeded = 11
LDAPResultUnavailableCriticalExtension = 12
LDAPResultConfidentialityRequired = 13
LDAPResultSaslBindInProgress = 14
LDAPResultNoSuchAttribute = 16
LDAPResultUndefinedAttributeType = 17
LDAPResultInappropriateMatching = 18
LDAPResultConstraintViolation = 19
LDAPResultAttributeOrValueExists = 20
LDAPResultInvalidAttributeSyntax = 21
LDAPResultNoSuchObject = 32
LDAPResultAliasProblem = 33
LDAPResultInvalidDNSyntax = 34
LDAPResultAliasDereferencingProblem = 36
LDAPResultInappropriateAuthentication = 48
LDAPResultInvalidCredentials = 49
LDAPResultInsufficientAccessRights = 50
LDAPResultBusy = 51
LDAPResultUnavailable = 52
LDAPResultUnwillingToPerform = 53
LDAPResultLoopDetect = 54
LDAPResultNamingViolation = 64
LDAPResultObjectClassViolation = 65
LDAPResultNotAllowedOnNonLeaf = 66
LDAPResultNotAllowedOnRDN = 67
LDAPResultEntryAlreadyExists = 68
LDAPResultObjectClassModsProhibited = 69
LDAPResultAffectsMultipleDSAs = 71
LDAPResultOther = 80
ErrorNetwork = 200
ErrorFilterCompile = 201
ErrorFilterDecompile = 202
ErrorDebugging = 203
)
var LDAPResultCodeMap = map[uint8]string{
LDAPResultSuccess: "Success",
LDAPResultOperationsError: "Operations Error",
LDAPResultProtocolError: "Protocol Error",
LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
LDAPResultCompareFalse: "Compare False",
LDAPResultCompareTrue: "Compare True",
LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
LDAPResultStrongAuthRequired: "Strong Auth Required",
LDAPResultReferral: "Referral",
LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
LDAPResultConfidentialityRequired: "Confidentiality Required",
LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
LDAPResultNoSuchAttribute: "No Such Attribute",
LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
LDAPResultInappropriateMatching: "Inappropriate Matching",
LDAPResultConstraintViolation: "Constraint Violation",
LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
LDAPResultNoSuchObject: "No Such Object",
LDAPResultAliasProblem: "Alias Problem",
LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
LDAPResultInvalidCredentials: "Invalid Credentials",
LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
LDAPResultBusy: "Busy",
LDAPResultUnavailable: "Unavailable",
LDAPResultUnwillingToPerform: "Unwilling To Perform",
LDAPResultLoopDetect: "Loop Detect",
LDAPResultNamingViolation: "Naming Violation",
LDAPResultObjectClassViolation: "Object Class Violation",
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
LDAPResultEntryAlreadyExists: "Entry Already Exists",
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
LDAPResultOther: "Other",
}
// Adds descriptions to an LDAP Response packet for debugging
func addLDAPDescriptions(packet *ber.Packet) (err error) {
defer func() {
if r := recover(); r != nil {
err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions"))
}
}()
packet.Description = "LDAP Response"
packet.Children[0].Description = "Message ID"
application := packet.Children[1].Tag
packet.Children[1].Description = ApplicationMap[application]
switch application {
case ApplicationBindRequest:
addRequestDescriptions(packet)
case ApplicationBindResponse:
addDefaultLDAPResponseDescriptions(packet)
case ApplicationUnbindRequest:
addRequestDescriptions(packet)
case ApplicationSearchRequest:
addRequestDescriptions(packet)
case ApplicationSearchResultEntry:
packet.Children[1].Children[0].Description = "Object Name"
packet.Children[1].Children[1].Description = "Attributes"
for _, child := range packet.Children[1].Children[1].Children {
child.Description = "Attribute"
child.Children[0].Description = "Attribute Name"
child.Children[1].Description = "Attribute Values"
for _, grandchild := range child.Children[1].Children {
grandchild.Description = "Attribute Value"
}
}
if len(packet.Children) == 3 {
addControlDescriptions(packet.Children[2])
}
case ApplicationSearchResultDone:
addDefaultLDAPResponseDescriptions(packet)
case ApplicationModifyRequest:
addRequestDescriptions(packet)
case ApplicationModifyResponse:
case ApplicationAddRequest:
addRequestDescriptions(packet)
case ApplicationAddResponse:
case ApplicationDelRequest:
addRequestDescriptions(packet)
case ApplicationDelResponse:
case ApplicationModifyDNRequest:
addRequestDescriptions(packet)
case ApplicationModifyDNResponse:
case ApplicationCompareRequest:
addRequestDescriptions(packet)
case ApplicationCompareResponse:
case ApplicationAbandonRequest:
addRequestDescriptions(packet)
case ApplicationSearchResultReference:
case ApplicationExtendedRequest:
addRequestDescriptions(packet)
case ApplicationExtendedResponse:
}
return nil
}
func addControlDescriptions(packet *ber.Packet) {
packet.Description = "Controls"
for _, child := range packet.Children {
child.Description = "Control"
child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
value := child.Children[1]
if len(child.Children) == 3 {
child.Children[1].Description = "Criticality"
value = child.Children[2]
}
value.Description = "Control Value"
switch child.Children[0].Value.(string) {
case ControlTypePaging:
value.Description += " (Paging)"
if value.Value != nil {
valueChildren := ber.DecodePacket(value.Data.Bytes())
value.Data.Truncate(0)
value.Value = nil
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
value.AppendChild(valueChildren)
}
value.Children[0].Description = "Real Search Control Value"
value.Children[0].Children[0].Description = "Paging Size"
value.Children[0].Children[1].Description = "Cookie"
}
}
}
func addRequestDescriptions(packet *ber.Packet) {
packet.Description = "LDAP Request"
packet.Children[0].Description = "Message ID"
packet.Children[1].Description = ApplicationMap[packet.Children[1].Tag]
if len(packet.Children) == 3 {
addControlDescriptions(packet.Children[2])
}
}
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
resultCode := packet.Children[1].Children[0].Value.(uint64)
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[uint8(resultCode)] + ")"
packet.Children[1].Children[1].Description = "Matched DN"
packet.Children[1].Children[2].Description = "Error Message"
if len(packet.Children[1].Children) > 3 {
packet.Children[1].Children[3].Description = "Referral"
}
if len(packet.Children) == 3 {
addControlDescriptions(packet.Children[2])
}
}
func DebugBinaryFile(fileName string) error {
file, err := ioutil.ReadFile(fileName)
if err != nil {
return NewError(ErrorDebugging, err)
}
ber.PrintBytes(file, "")
packet := ber.DecodePacket(file)
addLDAPDescriptions(packet)
ber.PrintPacket(packet)
return nil
}
type Error struct {
Err error
ResultCode uint8
}
func (e *Error) Error() string {
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
}
func NewError(resultCode uint8, err error) error {
return &Error{ResultCode: resultCode, Err: err}
}
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
if len(packet.Children) >= 2 {
response := packet.Children[1]
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) == 3 {
return uint8(response.Children[0].Value.(uint64)), response.Children[2].Value.(string)
}
}
return ErrorNetwork, "Invalid packet format"
}

View File

@@ -1,123 +0,0 @@
package ldap
import (
"fmt"
"testing"
)
var ldapServer = "ldap.itd.umich.edu"
var ldapPort = uint16(389)
var baseDN = "dc=umich,dc=edu"
var filter = []string{
"(cn=cis-fac)",
"(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
"(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
var attributes = []string{
"cn",
"description"}
func TestConnect(t *testing.T) {
fmt.Printf("TestConnect: starting...\n")
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
if err != nil {
t.Errorf(err.Error())
return
}
defer l.Close()
fmt.Printf("TestConnect: finished...\n")
}
func TestSearch(t *testing.T) {
fmt.Printf("TestSearch: starting...\n")
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
if err != nil {
t.Errorf(err.Error())
return
}
defer l.Close()
searchRequest := NewSearchRequest(
baseDN,
ScopeWholeSubtree, DerefAlways, 0, 0, false,
filter[0],
attributes,
nil)
sr, err := l.Search(searchRequest)
if err != nil {
t.Errorf(err.Error())
return
}
fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
}
func TestSearchWithPaging(t *testing.T) {
fmt.Printf("TestSearchWithPaging: starting...\n")
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
if err != nil {
t.Errorf(err.Error())
return
}
defer l.Close()
err = l.Bind("", "")
if err != nil {
t.Errorf(err.Error())
return
}
searchRequest := NewSearchRequest(
baseDN,
ScopeWholeSubtree, DerefAlways, 0, 0, false,
filter[1],
attributes,
nil)
sr, err := l.SearchWithPaging(searchRequest, 5)
if err != nil {
t.Errorf(err.Error())
return
}
fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
}
func testMultiGoroutineSearch(t *testing.T, l *Conn, results chan *SearchResult, i int) {
searchRequest := NewSearchRequest(
baseDN,
ScopeWholeSubtree, DerefAlways, 0, 0, false,
filter[i],
attributes,
nil)
sr, err := l.Search(searchRequest)
if err != nil {
t.Errorf(err.Error())
results <- nil
return
}
results <- sr
}
func TestMultiGoroutineSearch(t *testing.T) {
fmt.Printf("TestMultiGoroutineSearch: starting...\n")
l, err := Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
if err != nil {
t.Errorf(err.Error())
return
}
defer l.Close()
results := make([]chan *SearchResult, len(filter))
for i := range filter {
results[i] = make(chan *SearchResult)
go testMultiGoroutineSearch(t, l, results[i], i)
}
for i := range filter {
sr := <-results[i]
if sr == nil {
t.Errorf("Did not receive results from goroutine for %q", filter[i])
} else {
fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries))
}
}
}

View File

@@ -1,156 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// File contains Modify functionality
//
// https://tools.ietf.org/html/rfc4511
//
// ModifyRequest ::= [APPLICATION 6] SEQUENCE {
// object LDAPDN,
// changes SEQUENCE OF change SEQUENCE {
// operation ENUMERATED {
// add (0),
// delete (1),
// replace (2),
// ... },
// modification PartialAttribute } }
//
// PartialAttribute ::= SEQUENCE {
// type AttributeDescription,
// vals SET OF value AttributeValue }
//
// AttributeDescription ::= LDAPString
// -- Constrained to <attributedescription>
// -- [RFC4512]
//
// AttributeValue ::= OCTET STRING
//
package ldap
import (
"errors"
"log"
"github.com/gogits/gogs/modules/asn1-ber"
)
const (
AddAttribute = 0
DeleteAttribute = 1
ReplaceAttribute = 2
)
type PartialAttribute struct {
attrType string
attrVals []string
}
func (p *PartialAttribute) encode() *ber.Packet {
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.attrType, "Type"))
set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
for _, value := range p.attrVals {
set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
}
seq.AppendChild(set)
return seq
}
type ModifyRequest struct {
dn string
addAttributes []PartialAttribute
deleteAttributes []PartialAttribute
replaceAttributes []PartialAttribute
}
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
m.addAttributes = append(m.addAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
}
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
m.deleteAttributes = append(m.deleteAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
}
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
m.replaceAttributes = append(m.replaceAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
}
func (m ModifyRequest) encode() *ber.Packet {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.dn, "DN"))
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
for _, attribute := range m.addAttributes {
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
change.AppendChild(attribute.encode())
changes.AppendChild(change)
}
for _, attribute := range m.deleteAttributes {
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
change.AppendChild(attribute.encode())
changes.AppendChild(change)
}
for _, attribute := range m.replaceAttributes {
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
change.AppendChild(attribute.encode())
changes.AppendChild(change)
}
request.AppendChild(changes)
return request
}
func NewModifyRequest(
dn string,
) *ModifyRequest {
return &ModifyRequest{
dn: dn,
}
}
func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
messageID := l.nextMessageID()
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
packet.AppendChild(modifyRequest.encode())
l.Debug.PrintPacket(packet)
channel, err := l.sendMessage(packet)
if err != nil {
return err
}
if channel == nil {
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
}
defer l.finishMessage(messageID)
l.Debug.Printf("%d: waiting for response", messageID)
packet = <-channel
l.Debug.Printf("%d: got response %p", messageID, packet)
if packet == nil {
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return err
}
ber.PrintPacket(packet)
}
if packet.Children[1].Tag == ApplicationModifyResponse {
resultCode, resultDescription := getLDAPResultCode(packet)
if resultCode != 0 {
return NewError(resultCode, errors.New(resultDescription))
}
} else {
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}
l.Debug.Printf("%d: returning", messageID)
return nil
}

View File

@@ -1,350 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// File contains Search functionality
//
// https://tools.ietf.org/html/rfc4511
//
// SearchRequest ::= [APPLICATION 3] SEQUENCE {
// baseObject LDAPDN,
// scope ENUMERATED {
// baseObject (0),
// singleLevel (1),
// wholeSubtree (2),
// ... },
// derefAliases ENUMERATED {
// neverDerefAliases (0),
// derefInSearching (1),
// derefFindingBaseObj (2),
// derefAlways (3) },
// sizeLimit INTEGER (0 .. maxInt),
// timeLimit INTEGER (0 .. maxInt),
// typesOnly BOOLEAN,
// filter Filter,
// attributes AttributeSelection }
//
// AttributeSelection ::= SEQUENCE OF selector LDAPString
// -- The LDAPString is constrained to
// -- <attributeSelector> in Section 4.5.1.8
//
// Filter ::= CHOICE {
// and [0] SET SIZE (1..MAX) OF filter Filter,
// or [1] SET SIZE (1..MAX) OF filter Filter,
// not [2] Filter,
// equalityMatch [3] AttributeValueAssertion,
// substrings [4] SubstringFilter,
// greaterOrEqual [5] AttributeValueAssertion,
// lessOrEqual [6] AttributeValueAssertion,
// present [7] AttributeDescription,
// approxMatch [8] AttributeValueAssertion,
// extensibleMatch [9] MatchingRuleAssertion,
// ... }
//
// SubstringFilter ::= SEQUENCE {
// type AttributeDescription,
// substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
// initial [0] AssertionValue, -- can occur at most once
// any [1] AssertionValue,
// final [2] AssertionValue } -- can occur at most once
// }
//
// MatchingRuleAssertion ::= SEQUENCE {
// matchingRule [1] MatchingRuleId OPTIONAL,
// type [2] AttributeDescription OPTIONAL,
// matchValue [3] AssertionValue,
// dnAttributes [4] BOOLEAN DEFAULT FALSE }
//
//
package ldap
import (
"errors"
"fmt"
"strings"
"github.com/gogits/gogs/modules/asn1-ber"
)
const (
ScopeBaseObject = 0
ScopeSingleLevel = 1
ScopeWholeSubtree = 2
)
var ScopeMap = map[int]string{
ScopeBaseObject: "Base Object",
ScopeSingleLevel: "Single Level",
ScopeWholeSubtree: "Whole Subtree",
}
const (
NeverDerefAliases = 0
DerefInSearching = 1
DerefFindingBaseObj = 2
DerefAlways = 3
)
var DerefMap = map[int]string{
NeverDerefAliases: "NeverDerefAliases",
DerefInSearching: "DerefInSearching",
DerefFindingBaseObj: "DerefFindingBaseObj",
DerefAlways: "DerefAlways",
}
type Entry struct {
DN string
Attributes []*EntryAttribute
}
func (e *Entry) GetAttributeValues(attribute string) []string {
for _, attr := range e.Attributes {
if attr.Name == attribute {
return attr.Values
}
}
return []string{}
}
func (e *Entry) GetAttributeValue(attribute string) string {
values := e.GetAttributeValues(attribute)
if len(values) == 0 {
return ""
}
return values[0]
}
func (e *Entry) Print() {
fmt.Printf("DN: %s\n", e.DN)
for _, attr := range e.Attributes {
attr.Print()
}
}
func (e *Entry) PrettyPrint(indent int) {
fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
for _, attr := range e.Attributes {
attr.PrettyPrint(indent + 2)
}
}
type EntryAttribute struct {
Name string
Values []string
}
func (e *EntryAttribute) Print() {
fmt.Printf("%s: %s\n", e.Name, e.Values)
}
func (e *EntryAttribute) PrettyPrint(indent int) {
fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
}
type SearchResult struct {
Entries []*Entry
Referrals []string
Controls []Control
}
func (s *SearchResult) Print() {
for _, entry := range s.Entries {
entry.Print()
}
}
func (s *SearchResult) PrettyPrint(indent int) {
for _, entry := range s.Entries {
entry.PrettyPrint(indent)
}
}
type SearchRequest struct {
BaseDN string
Scope int
DerefAliases int
SizeLimit int
TimeLimit int
TypesOnly bool
Filter string
Attributes []string
Controls []Control
}
func (s *SearchRequest) encode() (*ber.Packet, error) {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN"))
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope"))
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases"))
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit"))
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit"))
request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only"))
// compile and encode filter
filterPacket, err := CompileFilter(s.Filter)
if err != nil {
return nil, err
}
request.AppendChild(filterPacket)
// encode attributes
attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
for _, attribute := range s.Attributes {
attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
}
request.AppendChild(attributesPacket)
return request, nil
}
func NewSearchRequest(
BaseDN string,
Scope, DerefAliases, SizeLimit, TimeLimit int,
TypesOnly bool,
Filter string,
Attributes []string,
Controls []Control,
) *SearchRequest {
return &SearchRequest{
BaseDN: BaseDN,
Scope: Scope,
DerefAliases: DerefAliases,
SizeLimit: SizeLimit,
TimeLimit: TimeLimit,
TypesOnly: TypesOnly,
Filter: Filter,
Attributes: Attributes,
Controls: Controls,
}
}
func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
if searchRequest.Controls == nil {
searchRequest.Controls = make([]Control, 0)
}
pagingControl := NewControlPaging(pagingSize)
searchRequest.Controls = append(searchRequest.Controls, pagingControl)
searchResult := new(SearchResult)
for {
result, err := l.Search(searchRequest)
l.Debug.Printf("Looking for Paging Control...")
if err != nil {
return searchResult, err
}
if result == nil {
return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
}
for _, entry := range result.Entries {
searchResult.Entries = append(searchResult.Entries, entry)
}
for _, referral := range result.Referrals {
searchResult.Referrals = append(searchResult.Referrals, referral)
}
for _, control := range result.Controls {
searchResult.Controls = append(searchResult.Controls, control)
}
l.Debug.Printf("Looking for Paging Control...")
pagingResult := FindControl(result.Controls, ControlTypePaging)
if pagingResult == nil {
pagingControl = nil
l.Debug.Printf("Could not find paging control. Breaking...")
break
}
cookie := pagingResult.(*ControlPaging).Cookie
if len(cookie) == 0 {
pagingControl = nil
l.Debug.Printf("Could not find cookie. Breaking...")
break
}
pagingControl.SetCookie(cookie)
}
if pagingControl != nil {
l.Debug.Printf("Abandoning Paging...")
pagingControl.PagingSize = 0
l.Search(searchRequest)
}
return searchResult, nil
}
func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
messageID := l.nextMessageID()
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
// encode search request
encodedSearchRequest, err := searchRequest.encode()
if err != nil {
return nil, err
}
packet.AppendChild(encodedSearchRequest)
// encode search controls
if searchRequest.Controls != nil {
packet.AppendChild(encodeControls(searchRequest.Controls))
}
l.Debug.PrintPacket(packet)
channel, err := l.sendMessage(packet)
if err != nil {
return nil, err
}
if channel == nil {
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
}
defer l.finishMessage(messageID)
result := &SearchResult{
Entries: make([]*Entry, 0),
Referrals: make([]string, 0),
Controls: make([]Control, 0)}
foundSearchResultDone := false
for !foundSearchResultDone {
l.Debug.Printf("%d: waiting for response", messageID)
packet = <-channel
l.Debug.Printf("%d: got response %p", messageID, packet)
if packet == nil {
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}
switch packet.Children[1].Tag {
case 4:
entry := new(Entry)
entry.DN = packet.Children[1].Children[0].Value.(string)
for _, child := range packet.Children[1].Children[1].Children {
attr := new(EntryAttribute)
attr.Name = child.Children[0].Value.(string)
for _, value := range child.Children[1].Children {
attr.Values = append(attr.Values, value.Value.(string))
}
entry.Attributes = append(entry.Attributes, attr)
}
result.Entries = append(result.Entries, entry)
case 5:
resultCode, resultDescription := getLDAPResultCode(packet)
if resultCode != 0 {
return result, NewError(resultCode, errors.New(resultDescription))
}
if len(packet.Children) == 3 {
for _, child := range packet.Children[2].Children {
result.Controls = append(result.Controls, DecodeControl(child))
}
}
foundSearchResultDone = true
case 19:
result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
}
}
l.Debug.Printf("%d: returning", messageID)
return result, nil
}

View File

@@ -125,7 +125,7 @@ func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *
subject := fmt.Sprintf("[%s] %s (#%d)", repo.Name, issue.Name, issue.Index)
content := fmt.Sprintf("%s<br>-<br> <a href=\"%s%s/%s/issues/%d\">View it on Gogs</a>.",
base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name),
base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()),
setting.AppUrl, owner.Name, repo.Name, issue.Index)
msg := NewMessage(tos, subject, content)
msg.Info = fmt.Sprintf("Subject: %s, issue notify", subject)
@@ -148,7 +148,7 @@ func SendIssueMentionMail(r macaron.Render, u, owner *models.User,
data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
data["Subject"] = subject
data["ActUserName"] = u.DisplayName()
data["Content"] = string(base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name))
data["Content"] = string(base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()))
body, err := r.HTMLString(string(NOTIFY_MENTION), data)
if err != nil {

View File

@@ -130,22 +130,3 @@ func Toggle(options *ToggleOptions) macaron.Handler {
}
}
}
// Contexter middleware already checks token for user sign in process.
func ApiReqToken() macaron.Handler {
return func(ctx *Context) {
if !ctx.IsSigned {
ctx.Error(401)
return
}
}
}
func ApiReqBasicAuth() macaron.Handler {
return func(ctx *Context) {
if !ctx.IsBasicAuth {
ctx.Error(401)
return
}
}
}

View File

@@ -59,7 +59,7 @@ type Context struct {
IsSigned bool
IsBasicAuth bool
Repo RepoContext
Repo *RepoContext
Org struct {
IsOwner bool
@@ -73,17 +73,22 @@ type Context struct {
}
// IsOwner returns true if current user is the owner of repository.
func (r RepoContext) IsOwner() bool {
func (r *RepoContext) IsOwner() bool {
return r.AccessMode >= models.ACCESS_MODE_OWNER
}
// IsAdmin returns true if current user has admin or higher access of repository.
func (r RepoContext) IsAdmin() bool {
func (r *RepoContext) IsAdmin() bool {
return r.AccessMode >= models.ACCESS_MODE_ADMIN
}
// IsPusher returns true if current user has write or higher access of repository.
func (r *RepoContext) IsPusher() bool {
return r.AccessMode >= models.ACCESS_MODE_WRITE
}
// Return if the current user has read access for this repository
func (r RepoContext) HasAccess() bool {
func (r *RepoContext) HasAccess() bool {
return r.AccessMode >= models.ACCESS_MODE_READ
}
@@ -203,6 +208,7 @@ func Contexter() macaron.Handler {
csrf: x,
Flash: f,
Session: sess,
Repo: &RepoContext{},
}
// Compute current URL for real-time change language.
ctx.Data["Link"] = setting.AppSubUrl + strings.TrimSuffix(ctx.Req.URL.Path, "/")

View File

@@ -48,7 +48,12 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
if ctx.IsSigned {
// Admin has super access.
if ctx.IsSigned && ctx.User.IsAdmin {
ctx.Org.IsOwner = true
ctx.Org.IsMember = true
ctx.Org.IsAdminTeam = true
} else if ctx.IsSigned {
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id)
if ctx.Org.IsOwner {
ctx.Org.IsMember = true
@@ -68,6 +73,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
ctx.Org.OrgLink = setting.AppSubUrl + "/org/" + org.Name
ctx.Data["OrgLink"] = ctx.Org.OrgLink

View File

@@ -6,7 +6,6 @@ package middleware
import (
"fmt"
"net/url"
"path"
"strings"
@@ -18,26 +17,72 @@ import (
"github.com/gogits/gogs/modules/setting"
)
func ApiRepoAssignment() macaron.Handler {
func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
// Non-fork repository will not return error in this method.
if err := repo.GetBaseRepo(); err != nil {
if models.IsErrRepoNotExist(err) {
repo.IsFork = false
repo.ForkID = 0
return
}
ctx.Handle(500, "GetBaseRepo", err)
return
} else if err = repo.BaseRepo.GetOwner(); err != nil {
ctx.Handle(500, "BaseRepo.GetOwner", err)
return
}
bsaeRepo := repo.BaseRepo
baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name))
if err != nil {
ctx.Handle(500, "OpenRepository", err)
return
}
if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) {
ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch
} else {
baseBranches, err := baseGitRepo.GetBranches()
if err != nil {
ctx.Handle(500, "GetBranches", err)
return
}
if len(baseBranches) > 0 {
ctx.Data["BaseDefaultBranch"] = baseBranches[0]
}
}
}
func RepoAssignment(args ...bool) macaron.Handler {
return func(ctx *Context) {
userName := ctx.Params(":username")
repoName := ctx.Params(":reponame")
var (
displayBare bool // To display bare page if it is a bare repo.
)
if len(args) >= 1 {
displayBare = args[0]
}
var (
owner *models.User
err error
)
// Check if the user is the same as the repository owner.
userName := ctx.Params(":username")
repoName := ctx.Params(":reponame")
refName := ctx.Params(":branchname")
if len(refName) == 0 {
refName = ctx.Params(":path")
}
// Check if the user is the same as the repository owner
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
owner = ctx.User
} else {
owner, err = models.GetUserByName(userName)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(404)
ctx.Handle(404, "GetUserByName", err)
} else {
ctx.APIError(500, "GetUserByName", err)
ctx.Handle(500, "GetUserByName", err)
}
return
}
@@ -48,31 +93,131 @@ func ApiRepoAssignment() macaron.Handler {
repo, err := models.GetRepositoryByName(owner.Id, repoName)
if err != nil {
if models.IsErrRepoNotExist(err) {
ctx.Error(404)
ctx.Handle(404, "GetRepositoryByName", err)
} else {
ctx.APIError(500, "GetRepositoryByName", err)
ctx.Handle(500, "GetRepositoryByName", err)
}
return
} else if err = repo.GetOwner(); err != nil {
ctx.APIError(500, "GetOwner", err)
ctx.Handle(500, "GetOwner", err)
return
}
mode, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.APIError(500, "AccessLevel", err)
return
// Admin has super access.
if ctx.IsSigned && ctx.User.IsAdmin {
ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
} else {
mode, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.Handle(500, "AccessLevel", err)
return
}
ctx.Repo.AccessMode = mode
}
ctx.Repo.AccessMode = mode
// Check access.
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
ctx.Error(404)
ctx.Handle(404, "no access right", err)
return
}
ctx.Data["HasAccess"] = true
if repo.IsMirror {
ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
if err != nil {
ctx.Handle(500, "GetMirror", err)
return
}
ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
}
ctx.Repo.Repository = repo
ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
if err != nil {
ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
return
}
ctx.Repo.GitRepo = gitRepo
ctx.Repo.RepoLink = repo.RepoLink()
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
tags, err := ctx.Repo.GitRepo.GetTags()
if err != nil {
ctx.Handle(500, "GetTags", err)
return
}
ctx.Data["Tags"] = tags
ctx.Repo.Repository.NumTags = len(tags)
if repo.IsFork {
RetrieveBaseRepo(ctx, repo)
if ctx.Written() {
return
}
}
ctx.Data["Title"] = owner.Name + "/" + repo.Name
ctx.Data["Repository"] = repo
ctx.Data["Owner"] = ctx.Repo.Repository.Owner
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher()
ctx.Data["CanPullRequest"] = ctx.Repo.IsAdmin() && repo.BaseRepo != nil && repo.BaseRepo.EnablePulls
ctx.Data["DisableSSH"] = setting.DisableSSH
ctx.Data["CloneLink"] = repo.CloneLink()
ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
if ctx.IsSigned {
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
}
// repo is bare and display enable
if ctx.Repo.Repository.IsBare {
log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
// NOTE: to prevent templating error
ctx.Data["BranchName"] = ""
if displayBare {
if !ctx.Repo.IsAdmin() {
ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
}
ctx.HTML(200, "repo/bare")
}
return
}
ctx.Data["TagName"] = ctx.Repo.TagName
brs, err := ctx.Repo.GitRepo.GetBranches()
if err != nil {
ctx.Handle(500, "GetBranches", err)
return
}
ctx.Data["Branches"] = brs
ctx.Data["BrancheCount"] = len(brs)
// If not branch selected, try default one.
// If default branch doesn't exists, fall back to some other branch.
if len(ctx.Repo.BranchName) == 0 {
if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
} else if len(brs) > 0 {
ctx.Repo.BranchName = brs[0]
}
}
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["CommitID"] = ctx.Repo.CommitID
if ctx.Query("go-get") == "1" {
ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
prefix := path.Join(setting.AppUrl, owner.Name, repo.Name, "src", ctx.Repo.BranchName)
ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
}
}
}
@@ -188,224 +333,18 @@ func RepoRef() macaron.Handler {
}
}
func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
// Non-fork repository will not return error in this method.
if err := repo.GetBaseRepo(); err != nil {
if models.IsErrRepoNotExist(err) {
repo.IsFork = false
repo.ForkID = 0
return
}
ctx.Handle(500, "GetBaseRepo", err)
return
} else if err = repo.BaseRepo.GetOwner(); err != nil {
ctx.Handle(500, "BaseRepo.GetOwner", err)
return
}
bsaeRepo := repo.BaseRepo
baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name))
if err != nil {
ctx.Handle(500, "OpenRepository", err)
return
}
if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) {
ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch
} else {
baseBranches, err := baseGitRepo.GetBranches()
if err != nil {
ctx.Handle(500, "GetBranches", err)
return
}
if len(baseBranches) > 0 {
ctx.Data["BaseDefaultBranch"] = baseBranches[0]
}
}
}
func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
return func(ctx *Context) {
var (
displayBare bool // To display bare page if it is a bare repo.
)
if len(args) >= 1 {
displayBare = args[0]
}
var (
owner *models.User
err error
)
userName := ctx.Params(":username")
repoName := ctx.Params(":reponame")
refName := ctx.Params(":branchname")
if len(refName) == 0 {
refName = ctx.Params(":path")
}
// Check if the user is the same as the repository owner
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
owner = ctx.User
} else {
owner, err = models.GetUserByName(userName)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Handle(404, "GetUserByName", err)
} else {
ctx.Handle(500, "GetUserByName", err)
}
return
}
}
ctx.Repo.Owner = owner
// Get repository.
repo, err := models.GetRepositoryByName(owner.Id, repoName)
if err != nil {
if models.IsErrRepoNotExist(err) {
ctx.Handle(404, "GetRepositoryByName", err)
} else {
ctx.Handle(500, "GetRepositoryByName", err)
}
return
} else if err = repo.GetOwner(); err != nil {
ctx.Handle(500, "GetOwner", err)
return
}
// Admin has super access.
if ctx.IsSigned && ctx.User.IsAdmin {
ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
} else {
mode, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.Handle(500, "AccessLevel", err)
return
}
ctx.Repo.AccessMode = mode
}
// Check access.
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
ctx.Handle(404, "no access right", err)
return
}
ctx.Data["HasAccess"] = true
if repo.IsMirror {
ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
if err != nil {
ctx.Handle(500, "GetMirror", err)
return
}
ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
}
ctx.Repo.Repository = repo
ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
if err != nil {
ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
return
}
ctx.Repo.GitRepo = gitRepo
ctx.Repo.RepoLink, err = repo.RepoLink()
if err != nil {
ctx.Handle(500, "RepoLink", err)
return
}
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
tags, err := ctx.Repo.GitRepo.GetTags()
if err != nil {
ctx.Handle(500, "GetTags", err)
return
}
ctx.Data["Tags"] = tags
ctx.Repo.Repository.NumTags = len(tags)
if repo.IsFork {
RetrieveBaseRepo(ctx, repo)
if ctx.Written() {
return
}
}
ctx.Data["Title"] = owner.Name + "/" + repo.Name
ctx.Data["Repository"] = repo
ctx.Data["Owner"] = ctx.Repo.Repository.Owner
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
ctx.Data["DisableSSH"] = setting.DisableSSH
ctx.Repo.CloneLink, err = repo.CloneLink()
if err != nil {
ctx.Handle(500, "CloneLink", err)
return
}
ctx.Data["CloneLink"] = ctx.Repo.CloneLink
if ctx.IsSigned {
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
}
// repo is bare and display enable
if ctx.Repo.Repository.IsBare {
log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
// NOTE: to prevent templating error
ctx.Data["BranchName"] = ""
if displayBare {
if !ctx.Repo.IsAdmin() {
ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
}
ctx.HTML(200, "repo/bare")
}
return
}
ctx.Data["TagName"] = ctx.Repo.TagName
brs, err := ctx.Repo.GitRepo.GetBranches()
if err != nil {
ctx.Handle(500, "GetBranches", err)
return
}
ctx.Data["Branches"] = brs
ctx.Data["BrancheCount"] = len(brs)
// If not branch selected, try default one.
// If default branch doesn't exists, fall back to some other branch.
if len(ctx.Repo.BranchName) == 0 {
if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
} else if len(brs) > 0 {
ctx.Repo.BranchName = brs[0]
}
}
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["CommitID"] = ctx.Repo.CommitID
if ctx.Query("go-get") == "1" {
ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
prefix := path.Join(setting.AppUrl, owner.Name, repo.Name, "src", ctx.Repo.BranchName)
ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
}
}
}
func RequireRepoAdmin() macaron.Handler {
return func(ctx *Context) {
if !ctx.Repo.IsAdmin() {
if !ctx.IsSigned {
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login")
return
}
ctx.Handle(404, ctx.Req.RequestURI, nil)
return
}
}
}
func RequireRepoPusher() macaron.Handler {
return func(ctx *Context) {
if !ctx.Repo.IsPusher() {
ctx.Handle(404, ctx.Req.RequestURI, nil)
return
}

View File

@@ -113,7 +113,8 @@ func Remove(pid int64) {
func Kill(pid int64) error {
for i, proc := range Processes {
if proc.Pid == pid {
if proc.Cmd.Process != nil && proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
if proc.Cmd != nil && proc.Cmd.Process != nil &&
proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
if err := proc.Cmd.Process.Kill(); err != nil {
return fmt.Errorf("fail to kill process(%d/%s): %v", proc.Pid, proc.Description, err)
}

View File

@@ -65,7 +65,10 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
cmdName := strings.TrimLeft(payload, "'()")
os.Setenv("SSH_ORIGINAL_COMMAND", cmdName)
log.Trace("Payload: %v", cmdName)
cmd := exec.Command(setting.AppPath, "serv", "key-"+keyID)
args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf}
log.Trace("Arguments: %v", args)
cmd := exec.Command(setting.AppPath, args...)
stdout, err := cmd.StdoutPipe()
if err != nil {
@@ -153,6 +156,7 @@ func Listen(port int) {
if err != nil {
panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr))
}
log.Trace("New private key is generateed: %s", keyPath)
}
privateBytes, err := ioutil.ReadFile(keyPath)

View File

@@ -183,9 +183,9 @@ func ReplaceLeft(s, old, new string) string {
}
// RenderCommitMessage renders commit message with XSS-safe and special links.
func RenderCommitMessage(msg, urlPrefix string) template.HTML {
func RenderCommitMessage(msg, urlPrefix string, metas map[string]string) template.HTML {
cleanMsg := template.HTMLEscapeString(msg)
fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix))
fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
for i := range msgLines {
msgLines[i] = ReplaceLeft(msgLines[i], " ", "&nbsp;")

View File

@@ -4,8 +4,8 @@
"files": {
"\/css\/dropzone-4.2.0.css": {
"fileType": 16,
"ignore": 0,
"ignoreWasSetByUser": 0,
"ignore": 1,
"ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/css\/dropzone-4.2.0.css",
"outputAbbreviatedPath": "No Output Path",
"outputPathIsOutsideProject": 0,
@@ -92,6 +92,15 @@
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0
},
"\/css\/simplemde-1.8.1.min.css": {
"fileType": 16,
"ignore": 1,
"ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/css\/simplemde-1.8.1.min.css",
"outputAbbreviatedPath": "No Output Path",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0
},
"\/css\/themes\/default\/assets\/images\/flags.png": {
"fileType": 32768,
"ignore": 0,

View File

@@ -911,6 +911,16 @@ pre.raw {
.ui .form .fake {
display: none !important;
}
.ui .form .sub.field {
margin-left: 25px;
}
.ui .sha.label {
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
font-size: 13px;
padding: 6px 10px 4px 10px;
font-weight: normal;
margin: 0 6px;
}
.ui.status.buttons .octicon {
margin-right: 4px;
}
@@ -1043,6 +1053,7 @@ footer .container .links > *:first-child {
.octicon.icon,
.mega-octicon.icon {
font-family: octicons;
font-size: 16px;
opacity: 1 !important;
}
.sr-only {
@@ -1748,7 +1759,7 @@ footer .container .links > *:first-child {
font-size: 30px;
}
.repository .head .ui.huge.breadcrumb {
font-weight: 300;
font-weight: 400;
font-size: 1.7rem;
}
.repository .head .fork-flag {
@@ -1758,6 +1769,11 @@ footer .container .links > *:first-child {
line-height: 10px;
white-space: nowrap;
}
.repository .navbar .ui.label {
margin-top: -2px;
margin-left: 7px;
padding: 3px 5px;
}
.repository .owner.dropdown {
min-width: 40% !important;
}
@@ -1801,82 +1817,61 @@ footer .container .links > *:first-child {
margin: 1px;
padding-right: 0;
}
.repository .ui.tabs.container {
margin-top: 14px;
margin-bottom: 0px;
}
.repository .ui.tabs.container .ui.menu {
border-bottom: none;
}
.repository .ui.tabs.divider {
margin-top: 0;
margin-bottom: 20px;
}
.repository #clone-panel {
margin-top: -8px;
width: 100%;
}
.repository #clone-panel input {
border-radius: 0;
padding: 5px 10px;
}
.repository #clone-panel .clone.button {
font-size: 13px;
padding: 0 5px;
}
.repository #clone-panel .clone.button:first-child {
border-radius: .28571429rem 0 0 .28571429rem;
}
.repository #clone-panel .icon.button {
padding: 0 10px;
}
.repository #clone-panel .dropdown .menu {
right: 0!important;
left: auto!important;
}
.repository.file.list #repo-desc {
font-size: 1.2em;
}
.repository.file.list .choose.reference .header .icon {
font-size: 1.4em;
}
.repository.file.list .head.meta {
padding: 0;
}
.repository.file.list .head.meta li {
list-style: none;
display: inline-block;
}
.repository.file.list .head.meta li .ui.breadcrumb {
margin-top: -5px;
}
.repository.file.list .head.meta li .ui.breadcrumb span,
.repository.file.list .head.meta li .ui.breadcrumb a {
font-size: 16px;
}
.repository.file.list .clone.input {
margin-top: -8px;
width: 100%;
}
.repository.file.list .clone.input input {
border-radius: 0;
padding: 5px 10px;
}
.repository.file.list .clone.input .clone.button {
font-size: 13px;
padding: 0 5px;
}
.repository.file.list .clone.input .clone.button:first-child {
border-radius: .28571429rem 0 0 .28571429rem;
}
.repository.file.list .clone.input .icon.button {
padding: 0 10px;
}
.repository.file.list .clone.input .dropdown .menu {
right: 0!important;
left: auto!important;
}
.repository.file.list #repo-files-table .table.list {
width: 80% !important;
}
.repository.file.list #repo-files-table thead th {
padding-top: 8px;
padding-bottom: 5px;
font-weight: normal;
}
.repository.file.list #repo-files-table thead th #last-commit-message {
margin-left: 5px;
margin-bottom: -4px;
width: 400px;
}
.repository.file.list #repo-files-table thead th .age {
margin-top: 2px;
.repository.file.list #repo-files-table thead th:first-child {
display: block;
position: relative;
width: 325%;
}
.repository.file.list #repo-files-table thead .ui.avatar {
margin-bottom: 5px;
}
.repository.file.list #repo-files-table tbody .icon {
margin-left: 5px;
}
.repository.file.list #repo-files-table tbody .name {
max-width: 120px;
}
.repository.file.list #repo-files-table tbody .message {
max-width: 300px;
}
.repository.file.list #repo-files-table tbody .age {
min-width: 150px;
}
.repository.file.list #repo-files-table tbody .text.truncate {
margin-bottom: -5px;
max-width: 100%;
margin-left: 3px;
margin-right: 5px;
}
.repository.file.list #repo-files-table td {
padding-top: 8px;
@@ -2241,30 +2236,15 @@ footer .container .links > *:first-child {
font-weight: normal;
padding: 5px 10px;
}
.repository .commits.table {
font-size: 13px;
}
.repository .commits.table th:first-child,
.repository .commits.table td:first-child {
.repository #commits-table thead th:first-of-type {
padding-left: 15px;
}
.repository .commits.table td {
line-height: 15px;
.repository #commits-table thead .sha {
font-size: 13px;
padding: 6px 40px 4px 35px;
}
.repository .commits.table .author {
min-width: 180px;
}
.repository .commits.table .message span {
max-width: 500px;
}
.repository .commits.table .date {
width: 120px;
}
.repository .sha.label {
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
font-size: 14px;
padding: 6px 10px 4px 10px;
font-weight: normal;
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) {
background-color: rgba(0, 0, 0, 0.02) !important;
}
.repository .diff-detail-box {
margin: 15px 0;
@@ -2341,6 +2321,7 @@ footer .container .links > *:first-child {
}
.repository .diff-file-box .code-diff pre {
margin: 0;
font-size: 13px;
}
.repository .diff-file-box .code-diff .lines-num {
border-right: 1px solid #d4d4d5;
@@ -2513,6 +2494,36 @@ footer .container .links > *:first-child {
.repository.forks .list .item .link {
padding-top: 5px;
}
.repository.wiki.start .ui.segment {
padding-top: 70px;
padding-bottom: 100px;
}
.repository.wiki.start .ui.segment .mega-octicon {
font-size: 48px;
}
.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment {
background: inherit;
}
.repository.wiki.new .editor-preview {
background-color: white;
}
.repository.wiki.view .choose.page {
margin-top: -5px;
}
.repository.wiki.view .ui.sub.header {
text-transform: none;
}
.repository.wiki.view .markdown {
padding: 15px 30px;
}
.repository.wiki.view .markdown h1:first-of-type,
.repository.wiki.view .markdown h2:first-of-type,
.repository.wiki.view .markdown h3:first-of-type,
.repository.wiki.view .markdown h4:first-of-type,
.repository.wiki.view .markdown h5:first-of-type,
.repository.wiki.view .markdown h6:first-of-type {
margin-top: 0;
}
.repository.settings.collaboration .collaborator.list {
padding: 0;
}
@@ -2988,12 +2999,18 @@ footer .container .links > *:first-child {
padding: 0;
font-size: 13px;
}
.admin .table.segment:not(.striped) {
padding-top: 5px;
}
.admin .table.segment:not(.striped) thead th:last-child {
padding-right: 5px !important;
}
.admin .table.segment th {
padding-top: 5px;
padding-bottom: 5px;
}
.admin .table.segment th:first-of-type,
.admin .table.segment td:first-of-type {
.admin .table.segment:not(.select) th:first-of-type,
.admin .table.segment:not(.select) td:first-of-type {
padding-left: 15px !important;
}
.admin .ui.header,

7
public/css/simplemde-1.8.1.min.css vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -231,6 +231,11 @@ function initRepository() {
});
}
// Wiki
if ($('.repository.wiki.view').length > 0) {
initFilterSearchDropdown('.choose.page .dropdown');
}
// Options
if ($('.repository.settings.options').length > 0) {
$('#repo_name').keyup(function () {
@@ -445,6 +450,53 @@ function initRepository() {
}
}
function initWiki() {
if ($('.repository.wiki').length == 0) {
return;
}
if ($('.repository.wiki.new').length > 0) {
var $edit_area = $('#edit-area');
var simplemde = new SimpleMDE({
autoDownloadFontAwesome: false,
element: $edit_area[0],
previewRender: function (plainText, preview) { // Async method
setTimeout(function () {
if ($('.editor-preview-active').length == 0) {
return;
}
$.post($edit_area.data('url'), {
"_csrf": csrf,
"mode": "gfm",
"context": $edit_area.data('context'),
"text": plainText
},
function (data) {
preview.innerHTML = '<div class="markdown">' + data + '</div>';
emojify.run($('.editor-preview')[0]);
}
);
}, 0);
return "Loading...";
},
renderingConfig: {
singleLineBreaks: false
},
spellChecker: false,
tabSize: 4,
toolbar: ["bold", "italic", "strikethrough", "|",
"heading", "heading-1", "heading-2", "heading-3", "|",
"code", "quote", "|",
"unordered-list", "ordered-list", "|",
"link", "image", "horizontal-rule", "|",
"preview", "fullscreen"]
})
}
}
function initOrganization() {
if ($('.organization').length == 0) {
return;
@@ -496,6 +548,19 @@ function initWebhook() {
$('.events.fields').hide();
}
});
// Test delivery
$('#test-delivery').click(function () {
var $this = $(this);
$this.addClass('loading disabled');
$.post($this.data('link'), {
"_csrf": csrf
}).done(
setTimeout(function () {
window.location.href = $this.data('redirect');
}, 5000)
)
});
}
@@ -555,6 +620,50 @@ function initAdmin() {
}
});
}
// Notice
if ($('.admin.notice')) {
var $detail_modal = $('#detail-modal');
// Attach view detail modals
$('.view-detail').click(function () {
$detail_modal.find('.content p').text($(this).data('content'));
$detail_modal.modal('show');
return false;
});
// Select actions
var $checkboxes = $('.select.table .ui.checkbox');
$('.select.action').click(function () {
switch ($(this).data('action')) {
case 'select-all':
$checkboxes.checkbox('check');
break;
case 'deselect-all':
$checkboxes.checkbox('uncheck');
break;
case 'inverse':
$checkboxes.checkbox('toggle');
break;
}
});
$('#delete-selection').click(function () {
var $this = $(this);
$this.addClass("loading disabled");
var ids = [];
$checkboxes.each(function () {
if ($(this).checkbox('is checked')) {
ids.push($(this).data('id'));
}
});
$.post($this.data('link'), {
"_csrf": csrf,
"ids": ids
}).done(function () {
window.location.href = $this.data('redirect');
});
});
}
}
function buttonsClickOnEnter() {
@@ -698,6 +807,9 @@ $(document).ready(function () {
$('.slide.up.dropdown').dropdown({
transition: 'slide up'
});
$('.upward.dropdown').dropdown({
direction: 'upward'
});
$('.ui.accordion').accordion();
$('.ui.checkbox').checkbox();
$('.ui.progress').progress({
@@ -835,6 +947,7 @@ $(document).ready(function () {
initCommentForm();
initInstall();
initRepository();
initWiki();
initOrganization();
initUser();
initWebhook();
@@ -885,7 +998,7 @@ $(window).load(function () {
}
// Code view.
if ($('.code-view').length > 0) {
if ($('.code-view .linenums').length > 0) {
var $block = $('.code-view .linenums');
var lines = $block.html().split("\n");
$block.html('');

14
public/js/libs/simplemde-1.8.1.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -5,13 +5,27 @@
.table.segment {
padding: 0;
font-size: 13px;
&:not(.striped) {
padding-top: 5px;
thead {
th:last-child {
padding-right: 5px !important;
}
}
}
th {
padding-top: 5px;
padding-bottom: 5px;
}
th, td {
&:first-of-type {
padding-left: 15px !important;
&:not(.select) {
th, td {
&:first-of-type {
padding-left: 15px !important;
}
}
}
}

View File

@@ -217,6 +217,18 @@ pre {
.fake {
display: none !important;
}
.sub.field {
margin-left: 25px;
}
}
.sha.label {
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
font-size: 13px;
padding: 6px 10px 4px 10px;
font-weight: normal;
margin: 0 6px;
}
&.status.buttons {
@@ -305,9 +317,11 @@ footer {
.generate-img(@n, (@i + 1));
}
// ensure Semantic UI .icon font family and 14px size does not apply to .icon.octicon
.octicon.icon,
.mega-octicon.icon {
font-family: octicons;
font-size: 16px;
opacity: 1 !important;
}

View File

@@ -20,7 +20,7 @@
font-size: 30px;
}
.ui.huge.breadcrumb {
font-weight: 300;
font-weight: 400;
font-size: 1.7rem;
}
.fork-flag {
@@ -32,6 +32,14 @@
}
}
.navbar {
.ui.label {
margin-top: -2px;
margin-left: 7px;
padding: 3px 5px;
}
}
.owner.dropdown {
min-width: 40% !important;
}
@@ -83,6 +91,45 @@
}
}
.ui.tabs {
&.container {
margin-top: 14px;
margin-bottom: 0px;
.ui.menu {
border-bottom: none;
}
}
&.divider {
margin-top: 0;
margin-bottom: 20px;
}
}
#clone-panel {
margin-top: -8px;
width: 100%;
input {
border-radius: 0;
padding: 5px 10px;
}
.clone.button {
font-size: 13px;
padding: 0 5px;
&:first-child {
border-radius: .28571429rem 0 0 .28571429rem;
}
}
.icon.button {
padding: 0 10px;
}
.dropdown .menu {
right: 0!important;
left: auto!important;
}
}
&.file.list {
#repo-desc {
font-size: 1.2em;
@@ -92,66 +139,18 @@
font-size: 1.4em;
}
}
.head.meta {
padding: 0;
li {
list-style: none;
display: inline-block;
.ui.breadcrumb {
margin-top: -5px;
span,
a {
font-size: 16px;
}
}
}
}
.clone.input {
margin-top: -8px;
width: 100%;
input {
border-radius: 0;
padding: 5px 10px;
}
.clone.button {
font-size: 13px;
padding: 0 5px;
&:first-child {
border-radius: .28571429rem 0 0 .28571429rem;
}
}
.icon.button {
padding: 0 10px;
}
.dropdown .menu {
right: 0!important;
left: auto!important;
}
}
#repo-files-table {
.table.list {
width: 80% !important;
}
thead {
th {
padding-top: 8px;
padding-bottom: 5px;
font-weight: normal;
#last-commit-message {
margin-left: 5px;
margin-bottom: -4px;
width: 400px;
}
.age {
margin-top: 2px;
&:first-child {
display: block;
position: relative;
width: 325%;
}
}
.ui.avatar {
@@ -160,21 +159,8 @@
}
tbody {
.icon {
margin-left: 5px;
}
.name {
max-width: 120px;
}
.message {
max-width: 300px;
}
.age {
min-width: 150px;
}
.text.truncate {
margin-bottom: -5px;
max-width: 100%;
margin-left: 3px;
margin-right: 5px;
}
}
td {
@@ -602,31 +588,19 @@
}
}
}
.commits.table {
font-size: 13px;
th, td {
&:first-child {
#commits-table {
thead {
th:first-of-type {
padding-left: 15px;
}
.sha {
font-size: 13px;
padding: 6px 40px 4px 35px;
}
}
td {
line-height: 15px;
&.ui.basic.striped.table tbody tr:nth-child(2n) {
background-color: rgba(0, 0, 0, .02)!important;
}
.author {
min-width: 180px;
}
.message span {
max-width: 500px;
}
.date {
width: 120px;
}
}
.sha.label {
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
font-size: 14px;
padding: 6px 10px 4px 10px;
font-weight: normal;
}
.diff-detail-box {
@@ -702,12 +676,14 @@
}
.code-diff {
font-size: 13px;
td {
padding: 0;
border-top: none;
}
pre {
margin: 0;
font-size: 13px;
}
.lines-num {
border-right: 1px solid #d4d4d5;
@@ -939,6 +915,50 @@
}
}
&.wiki {
&.start {
.ui.segment {
padding-top: 70px;
padding-bottom: 100px;
.mega-octicon {
font-size: 48px;
}
}
}
&.new {
.CodeMirror {
.CodeMirror-code .cm-comment {
background: inherit;
}
}
.editor-preview {
background-color: white;
}
}
&.view {
.choose.page {
margin-top: -5px;
}
.ui.sub.header {
text-transform: none;
}
.markdown {
padding: 15px 30px;
h1, h2, h3, h4, h5, h6 {
&:first-of-type {
margin-top: 0;
}
}
}
}
}
&.settings {
&.collaboration {
.collaborator.list {

View File

@@ -68,21 +68,22 @@ func NewAuthSource(ctx *middleware.Context) {
func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
return &models.LDAPConfig{
Source: &ldap.Source{
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.TLS,
SkipVerify: form.SkipVerify,
BindDN: form.BindDN,
UserDN: form.UserDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
Enabled: true,
Name: form.Name,
Host: form.Host,
Port: form.Port,
UseSSL: form.TLS,
SkipVerify: form.SkipVerify,
BindDN: form.BindDN,
UserDN: form.UserDN,
BindPassword: form.BindPassword,
UserBase: form.UserBase,
AttributeUsername: form.AttributeUsername,
AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail,
Filter: form.Filter,
AdminFilter: form.AdminFilter,
Enabled: true,
},
}
}

View File

@@ -5,6 +5,7 @@
package admin
import (
"github.com/Unknwon/com"
"github.com/Unknwon/paginater"
"github.com/gogits/gogs/models"
@@ -41,13 +42,32 @@ func Notices(ctx *middleware.Context) {
ctx.HTML(200, NOTICES)
}
func DeleteNotice(ctx *middleware.Context) {
id := ctx.ParamsInt64(":id")
if err := models.DeleteNotice(id); err != nil {
ctx.Handle(500, "DeleteNotice", err)
func DeleteNotices(ctx *middleware.Context) {
strs := ctx.QueryStrings("ids[]")
ids := make([]int64, 0, len(strs))
for i := range strs {
id := com.StrTo(strs[i]).MustInt64()
if id > 0 {
ids = append(ids, id)
}
}
if err := models.DeleteNoticesByIDs(ids); err != nil {
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
ctx.Status(500)
} else {
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
ctx.Status(200)
}
}
func EmptyNotices(ctx *middleware.Context) {
if err := models.DeleteNotices(0, 0); err != nil {
ctx.Handle(500, "DeleteNotices", err)
return
}
log.Trace("System notice deleted by admin(%s): %d", ctx.User.Name, id)
log.Trace("System notices deleted by admin (%s): [start: %d]", ctx.User.Name, 0)
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
ctx.Redirect(setting.AppSubUrl + "/admin/notices")
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
@@ -17,7 +18,7 @@ const (
REPOS base.TplName = "admin/repo/list"
)
func Repositories(ctx *middleware.Context) {
func Repos(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("admin.repositories")
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminRepositories"] = true
@@ -39,3 +40,22 @@ func Repositories(ctx *middleware.Context) {
ctx.Data["Total"] = total
ctx.HTML(200, REPOS)
}
func DeleteRepo(ctx *middleware.Context) {
repo, err := models.GetRepositoryByID(ctx.QueryInt64("id"))
if err != nil {
ctx.Handle(500, "GetRepositoryByID", err)
return
}
if err := models.DeleteRepository(repo.MustOwner().Id, repo.ID); err != nil {
ctx.Handle(500, "DeleteRepository", err)
return
}
log.Trace("Repository deleted: %s/%s", repo.MustOwner().Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
ctx.JSON(200, map[string]interface{}{
"redirect": setting.AppSubUrl + "/admin/repos?page=" + ctx.Query("page"),
})
}

View File

@@ -121,7 +121,7 @@ func NewUserPost(ctx *middleware.Context, form auth.AdminCrateUserForm) {
}
return
}
log.Trace("Account created by admin(%s): %s", ctx.User.Name, u.Name)
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
// Send e-mail notification.
if form.SendNotify && setting.MailService != nil {
@@ -224,7 +224,7 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) {
}
return
}
log.Trace("Account profile updated by admin(%s): %s", ctx.User.Name, u.Name)
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid"))
@@ -254,7 +254,7 @@ func DeleteUser(ctx *middleware.Context) {
}
return
}
log.Trace("Account deleted by admin(%s): %s", ctx.User.Name, u.Name)
log.Trace("Account deleted by admin (%s): %s", ctx.User.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.deletion_success"))
ctx.JSON(200, map[string]interface{}{

View File

@@ -0,0 +1,152 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package admin
import (
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/routers/api/v1/user"
to "github.com/gogits/gogs/routers/api/v1/utils"
)
func parseLoginSource(ctx *middleware.Context, u *models.User, sourceID int64, loginName string) {
if sourceID == 0 {
return
}
source, err := models.GetLoginSourceByID(sourceID)
if err != nil {
if models.IsErrAuthenticationNotExist(err) {
ctx.APIError(422, "", err)
} else {
ctx.APIError(500, "GetLoginSourceByID", err)
}
return
}
u.LoginType = source.Type
u.LoginSource = source.ID
u.LoginName = loginName
}
// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#create-a-new-user
func CreateUser(ctx *middleware.Context, form api.CreateUserOption) {
u := &models.User{
Name: form.Username,
Email: form.Email,
Passwd: form.Password,
IsActive: true,
LoginType: models.PLAIN,
}
parseLoginSource(ctx, u, form.SourceID, form.LoginName)
if ctx.Written() {
return
}
if err := models.CreateUser(u); err != nil {
if models.IsErrUserAlreadyExist(err) ||
models.IsErrEmailAlreadyUsed(err) ||
models.IsErrNameReserved(err) ||
models.IsErrNamePatternNotAllowed(err) {
ctx.APIError(422, "", err)
} else {
ctx.APIError(500, "CreateUser", err)
}
return
}
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
// Send e-mail notification.
if form.SendNotify && setting.MailService != nil {
mailer.SendRegisterNotifyMail(ctx.Context, u)
}
ctx.JSON(201, to.ApiUser(u))
}
// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#edit-an-existing-user
func EditUser(ctx *middleware.Context, form api.EditUserOption) {
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
parseLoginSource(ctx, u, form.SourceID, form.LoginName)
if ctx.Written() {
return
}
if len(form.Password) > 0 {
u.Passwd = form.Password
u.Salt = models.GetUserSalt()
u.EncodePasswd()
}
u.LoginName = form.LoginName
u.FullName = form.FullName
u.Email = form.Email
u.Website = form.Website
u.Location = form.Location
if form.Active != nil {
u.IsActive = *form.Active
}
if form.Admin != nil {
u.IsAdmin = *form.Admin
}
if form.AllowGitHook != nil {
u.AllowGitHook = *form.AllowGitHook
}
if form.AllowImportLocal != nil {
u.AllowImportLocal = *form.AllowImportLocal
}
if err := models.UpdateUser(u); err != nil {
if models.IsErrEmailAlreadyUsed(err) {
ctx.APIError(422, "", err)
} else {
ctx.APIError(500, "UpdateUser", err)
}
return
}
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.JSON(200, to.ApiUser(u))
}
// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#delete-a-user
func DeleteUser(ctx *middleware.Context) {
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := models.DeleteUser(u); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) {
ctx.APIError(422, "", err)
} else {
ctx.APIError(500, "DeleteUser", err)
}
return
}
log.Trace("Account deleted by admin(%s): %s", ctx.User.Name, u.Name)
ctx.Status(204)
}
// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#create-a-public-key-for-user
func CreatePublicKey(ctx *middleware.Context, form api.CreateKeyOption) {
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
user.CreateUserPublicKey(ctx, form, u.Id)
}

195
routers/api/v1/api.go Normal file
View File

@@ -0,0 +1,195 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
import (
"strings"
"github.com/go-macaron/binding"
"gopkg.in/macaron.v1"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/routers/api/v1/admin"
"github.com/gogits/gogs/routers/api/v1/misc"
"github.com/gogits/gogs/routers/api/v1/repo"
"github.com/gogits/gogs/routers/api/v1/user"
)
func RepoAssignment() macaron.Handler {
return func(ctx *middleware.Context) {
userName := ctx.Params(":username")
repoName := ctx.Params(":reponame")
var (
owner *models.User
err error
)
// Check if the user is the same as the repository owner.
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
owner = ctx.User
} else {
owner, err = models.GetUserByName(userName)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(404)
} else {
ctx.APIError(500, "GetUserByName", err)
}
return
}
}
ctx.Repo.Owner = owner
// Get repository.
repo, err := models.GetRepositoryByName(owner.Id, repoName)
if err != nil {
if models.IsErrRepoNotExist(err) {
ctx.Error(404)
} else {
ctx.APIError(500, "GetRepositoryByName", err)
}
return
} else if err = repo.GetOwner(); err != nil {
ctx.APIError(500, "GetOwner", err)
return
}
mode, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.APIError(500, "AccessLevel", err)
return
}
ctx.Repo.AccessMode = mode
// Check access.
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
ctx.Error(404)
return
}
ctx.Repo.Repository = repo
}
}
// Contexter middleware already checks token for user sign in process.
func ReqToken() macaron.Handler {
return func(ctx *middleware.Context) {
if !ctx.IsSigned {
ctx.Error(401)
return
}
}
}
func ReqBasicAuth() macaron.Handler {
return func(ctx *middleware.Context) {
if !ctx.IsBasicAuth {
ctx.Error(401)
return
}
}
}
func ReqAdmin() macaron.Handler {
return func(ctx *middleware.Context) {
if !ctx.User.IsAdmin {
ctx.Error(403)
return
}
}
}
// RegisterRoutes registers all v1 APIs routes to web application.
// FIXME: custom form error response
func RegisterRoutes(m *macaron.Macaron) {
bind := binding.Bind
m.Group("/v1", func() {
// Miscellaneous
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
m.Post("/markdown/raw", misc.MarkdownRaw)
// Users
m.Group("/users", func() {
m.Get("/search", user.Search)
m.Group("/:username", func() {
m.Get("", user.GetInfo)
m.Group("/tokens", func() {
m.Combo("").Get(user.ListAccessTokens).
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
}, ReqBasicAuth())
})
})
m.Group("/users", func() {
m.Group("/:username", func() {
m.Get("/keys", user.ListPublicKeys)
})
}, ReqToken())
m.Group("/user", func() {
m.Group("/keys", func() {
m.Combo("").Get(user.ListMyPublicKeys).
Post(bind(api.CreateKeyOption{}), user.CreatePublicKey)
m.Combo("/:id").Get(user.GetPublicKey).
Delete(user.DeletePublicKey)
})
}, ReqToken())
// Repositories
m.Combo("/user/repos", ReqToken()).Get(repo.ListMyRepos).
Post(bind(api.CreateRepoOption{}), repo.Create)
m.Post("/org/:org/repos", ReqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
m.Group("/repos", func() {
m.Get("/search", repo.Search)
})
m.Group("/repos", func() {
m.Post("/migrate", bind(auth.MigrateRepoForm{}), repo.Migrate)
m.Combo("/:username/:reponame").Get(repo.Get).
Delete(repo.Delete)
m.Group("/:username/:reponame", func() {
m.Combo("/hooks").Get(repo.ListHooks).
Post(bind(api.CreateHookOption{}), repo.CreateHook)
m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), repo.EditHook)
m.Get("/raw/*", middleware.RepoRef(), repo.GetRawFile)
m.Get("/archive/*", repo.GetArchive)
m.Group("/keys", func() {
m.Combo("").Get(repo.ListDeployKeys).
Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey)
m.Combo("/:id").Get(repo.GetDeployKey).
Delete(repo.DeleteDeploykey)
})
}, RepoAssignment())
}, ReqToken())
m.Any("/*", func(ctx *middleware.Context) {
ctx.Error(404)
})
m.Group("/admin", func() {
m.Group("/users", func() {
m.Post("", bind(api.CreateUserOption{}), admin.CreateUser)
m.Group("/:username", func() {
m.Combo("").Patch(bind(api.EditUserOption{}), admin.EditUser).
Delete(admin.DeleteUser)
m.Post("/keys", admin.CreatePublicKey)
})
})
}, ReqAdmin())
})
}

View File

@@ -2,19 +2,17 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
package misc
import (
"strings"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/auth/apiv1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
// Render an arbitrary Markdown document.
func Markdown(ctx *middleware.Context, form apiv1.MarkdownForm) {
// https://github.com/gogits/go-gogs-client/wiki/Miscellaneous#render-an-arbitrary-markdown-document
func Markdown(ctx *middleware.Context, form api.MarkdownOption) {
if ctx.HasApiError() {
ctx.APIError(422, "", ctx.GetErrMsg())
return
@@ -27,14 +25,13 @@ func Markdown(ctx *middleware.Context, form apiv1.MarkdownForm) {
switch form.Mode {
case "gfm":
ctx.Write(base.RenderMarkdown([]byte(form.Text),
setting.AppUrl+strings.TrimPrefix(form.Context, "/")))
ctx.Write(base.RenderMarkdown([]byte(form.Text), form.Context, nil))
default:
ctx.Write(base.RenderRawMarkdown([]byte(form.Text), ""))
}
}
// Render a Markdown document in raw mode.
// https://github.com/gogits/go-gogs-client/wiki/Miscellaneous#render-a-markdown-document-in-raw-mode
func MarkdownRaw(ctx *middleware.Context) {
body, err := ctx.Req.Body().Bytes()
if err != nil {

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
package repo
import (
"github.com/gogits/gogs/models"
@@ -11,7 +11,8 @@ import (
"github.com/gogits/gogs/routers/repo"
)
func GetRepoRawFile(ctx *middleware.Context) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Contents#download-raw-content
func GetRawFile(ctx *middleware.Context) {
if !ctx.Repo.HasAccess() {
ctx.Error(404)
return
@@ -31,7 +32,8 @@ func GetRepoRawFile(ctx *middleware.Context) {
}
}
func GetRepoArchive(ctx *middleware.Context) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Contents#download-archive
func GetArchive(ctx *middleware.Context) {
repoPath := models.RepoPath(ctx.Params(":username"), ctx.Params(":reponame"))
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {

View File

@@ -2,11 +2,10 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
package repo
import (
"encoding/json"
"fmt"
"github.com/Unknwon/com"
@@ -14,36 +13,11 @@ import (
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/middleware"
to "github.com/gogits/gogs/routers/api/v1/utils"
)
// ToApiHook converts webhook to API format.
func ToApiHook(repoLink string, w *models.Webhook) *api.Hook {
config := map[string]string{
"url": w.URL,
"content_type": w.ContentType.Name(),
}
if w.HookTaskType == models.SLACK {
s := w.GetSlackHook()
config["channel"] = s.Channel
config["username"] = s.Username
config["icon_url"] = s.IconURL
config["color"] = s.Color
}
return &api.Hook{
ID: w.ID,
Type: w.HookTaskType.Name(),
URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID),
Active: w.IsActive,
Config: config,
Events: w.EventsArray(),
Updated: w.Updated,
Created: w.Created,
}
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories#list-hooks
func ListRepoHooks(ctx *middleware.Context) {
func ListHooks(ctx *middleware.Context) {
hooks, err := models.GetWebhooksByRepoID(ctx.Repo.Repository.ID)
if err != nil {
ctx.APIError(500, "GetWebhooksByRepoID", err)
@@ -52,14 +26,14 @@ func ListRepoHooks(ctx *middleware.Context) {
apiHooks := make([]*api.Hook, len(hooks))
for i := range hooks {
apiHooks[i] = ToApiHook(ctx.Repo.RepoLink, hooks[i])
apiHooks[i] = to.ApiHook(ctx.Repo.RepoLink, hooks[i])
}
ctx.JSON(200, &apiHooks)
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories#create-a-hook
func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) {
func CreateHook(ctx *middleware.Context, form api.CreateHookOption) {
if !models.IsValidHookTaskType(form.Type) {
ctx.APIError(422, "", "Invalid hook type")
return
@@ -120,11 +94,11 @@ func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) {
return
}
ctx.JSON(201, ToApiHook(ctx.Repo.RepoLink, w))
ctx.JSON(201, to.ApiHook(ctx.Repo.RepoLink, w))
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook
func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) {
func EditHook(ctx *middleware.Context, form api.EditHookOption) {
w, err := models.GetWebhookByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrWebhookNotExist(err) {
@@ -187,5 +161,5 @@ func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) {
return
}
ctx.JSON(200, ToApiHook(ctx.Repo.RepoLink, w))
ctx.JSON(200, to.ApiHook(ctx.Repo.RepoLink, w))
}

114
routers/api/v1/repo/keys.go Normal file
View File

@@ -0,0 +1,114 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"fmt"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
to "github.com/gogits/gogs/routers/api/v1/utils"
)
func composeDeployKeysAPILink(repoPath string) string {
return setting.AppUrl + "api/v1/repos/" + repoPath + "/keys/"
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#list-deploy-keys
func ListDeployKeys(ctx *middleware.Context) {
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
if err != nil {
ctx.Handle(500, "ListDeployKeys", err)
return
}
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
apiKeys := make([]*api.DeployKey, len(keys))
for i := range keys {
if err = keys[i].GetContent(); err != nil {
ctx.APIError(500, "GetContent", err)
return
}
apiKeys[i] = to.ApiDeployKey(apiLink, keys[i])
}
ctx.JSON(200, &apiKeys)
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#get-a-deploy-key
func GetDeployKey(ctx *middleware.Context) {
key, err := models.GetDeployKeyByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrDeployKeyNotExist(err) {
ctx.Error(404)
} else {
ctx.Handle(500, "GetDeployKeyByID", err)
}
return
}
if err = key.GetContent(); err != nil {
ctx.APIError(500, "GetContent", err)
return
}
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
ctx.JSON(200, to.ApiDeployKey(apiLink, key))
}
func HandleCheckKeyStringError(ctx *middleware.Context, err error) {
if models.IsErrKeyUnableVerify(err) {
ctx.APIError(422, "", "Unable to verify key content")
} else {
ctx.APIError(422, "", fmt.Errorf("Invalid key content: %v", err))
}
}
func HandleAddKeyError(ctx *middleware.Context, err error) {
switch {
case models.IsErrKeyAlreadyExist(err):
ctx.APIError(422, "", "Key content has been used as non-deploy key")
case models.IsErrKeyNameAlreadyUsed(err):
ctx.APIError(422, "", "Key title has been used")
default:
ctx.APIError(500, "AddKey", err)
}
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#add-a-new-deploy-key
func CreateDeployKey(ctx *middleware.Context, form api.CreateKeyOption) {
content, err := models.CheckPublicKeyString(form.Key)
if err != nil {
HandleCheckKeyStringError(ctx, err)
return
}
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content)
if err != nil {
HandleAddKeyError(ctx, err)
return
}
key.Content = content
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
ctx.JSON(201, to.ApiDeployKey(apiLink, key))
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#remove-a-deploy-key
func DeleteDeploykey(ctx *middleware.Context) {
if err := models.DeleteDeployKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
if models.IsErrKeyAccessDenied(err) {
ctx.APIError(403, "", "You do not have access to this key")
} else {
ctx.APIError(500, "DeleteDeployKey", err)
}
return
}
ctx.Status(204)
}

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
package repo
import (
"path"
@@ -16,28 +16,11 @@ import (
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
to "github.com/gogits/gogs/routers/api/v1/utils"
)
// ToApiRepository converts repository to API format.
func ToApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository {
cl, err := repo.CloneLink()
if err != nil {
log.Error(4, "CloneLink: %v", err)
}
return &api.Repository{
Id: repo.ID,
Owner: *ToApiUser(owner),
FullName: owner.Name + "/" + repo.Name,
Private: repo.IsPrivate,
Fork: repo.IsFork,
HtmlUrl: setting.AppUrl + owner.Name + "/" + repo.Name,
CloneUrl: cl.HTTPS,
SshUrl: cl.SSH,
Permissions: permission,
}
}
func SearchRepos(ctx *middleware.Context) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories#search-repositories
func Search(ctx *middleware.Context) {
opt := models.SearchOption{
Keyword: path.Base(ctx.Query("q")),
Uid: com.StrTo(ctx.Query("uid")).MustInt64(),
@@ -114,12 +97,12 @@ func ListMyRepos(ctx *middleware.Context) {
repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos))
for i := range ownRepos {
repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true})
repos[i] = to.ApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true})
}
i := numOwnRepos
for repo, access := range accessibleRepos {
repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{
repos[i] = to.ApiRepository(repo.Owner, repo, api.Permission{
Admin: access >= models.ACCESS_MODE_ADMIN,
Push: access >= models.ACCESS_MODE_WRITE,
Pull: true,
@@ -156,11 +139,11 @@ func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoO
return
}
ctx.JSON(201, ToApiRepository(owner, repo, api.Permission{true, true, true}))
ctx.JSON(201, to.ApiRepository(owner, repo, api.Permission{true, true, true}))
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories#create
func CreateRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
func Create(ctx *middleware.Context, opt api.CreateRepoOption) {
// Shouldn't reach this condition, but just in case.
if ctx.User.IsOrganization() {
ctx.APIError(422, "", "not allowed creating repository for organization")
@@ -187,7 +170,8 @@ func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
createRepo(ctx, org, opt)
}
func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories#migrate
func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) {
ctxUser := ctx.User
// Not equal means context user is an organization,
// or is another user/organization if current user is admin.
@@ -255,7 +239,7 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
}
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
ctx.JSON(201, ToApiRepository(ctxUser, repo, api.Permission{true, true, true}))
ctx.JSON(201, to.ApiRepository(ctxUser, repo, api.Permission{true, true, true}))
}
func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repository) {
@@ -282,16 +266,18 @@ func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repositor
return owner, repo
}
func GetRepo(ctx *middleware.Context) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories#get
func Get(ctx *middleware.Context) {
owner, repo := parseOwnerAndRepo(ctx)
if ctx.Written() {
return
}
ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true}))
ctx.JSON(200, to.ApiRepository(owner, repo, api.Permission{true, true, true}))
}
func DeleteRepo(ctx *middleware.Context) {
// https://github.com/gogits/go-gogs-client/wiki/Repositories#delete
func Delete(ctx *middleware.Context) {
owner, repo := parseOwnerAndRepo(ctx)
if ctx.Written() {
return

View File

@@ -1,115 +0,0 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
import (
"fmt"
"github.com/Unknwon/com"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
func ToApiDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey {
return &api.DeployKey{
ID: key.ID,
Key: key.Content,
URL: apiLink + com.ToStr(key.ID),
Title: key.Name,
Created: key.Created,
ReadOnly: true, // All deploy keys are read-only.
}
}
func composeDeployKeysAPILink(repoPath string) string {
return setting.AppUrl + "api/v1/repos/" + repoPath + "/keys/"
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories---Deploy-Keys#list-deploy-keys
func ListRepoDeployKeys(ctx *middleware.Context) {
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
if err != nil {
ctx.Handle(500, "ListDeployKeys", err)
return
}
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
apiKeys := make([]*api.DeployKey, len(keys))
for i := range keys {
if err = keys[i].GetContent(); err != nil {
ctx.APIError(500, "GetContent", err)
return
}
apiKeys[i] = ToApiDeployKey(apiLink, keys[i])
}
ctx.JSON(200, &apiKeys)
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories---Deploy-Keys#get-a-deploy-key
func GetRepoDeployKey(ctx *middleware.Context) {
key, err := models.GetDeployKeyByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrDeployKeyNotExist(err) {
ctx.Error(404)
} else {
ctx.Handle(500, "GetDeployKeyByID", err)
}
return
}
if err = key.GetContent(); err != nil {
ctx.APIError(500, "GetContent", err)
return
}
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
ctx.JSON(200, ToApiDeployKey(apiLink, key))
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories---Deploy-Keys#add-a-new-deploy-key
func CreateRepoDeployKey(ctx *middleware.Context, form api.CreateDeployKeyOption) {
content, err := models.CheckPublicKeyString(form.Key)
if err != nil {
if models.IsErrKeyUnableVerify(err) {
ctx.APIError(422, "", "Unable to verify key content")
} else {
ctx.APIError(422, "", fmt.Errorf("Invalid key content: %v", err))
}
return
}
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content)
if err != nil {
ctx.Data["HasError"] = true
switch {
case models.IsErrKeyAlreadyExist(err):
ctx.APIError(422, "", "Key content has been used as non-deploy key")
case models.IsErrKeyNameAlreadyUsed(err):
ctx.APIError(422, "", "Key title has been used")
default:
ctx.APIError(500, "AddDeployKey", err)
}
return
}
key.Content = content
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name)
ctx.JSON(201, ToApiDeployKey(apiLink, key))
}
// https://github.com/gogits/go-gogs-client/wiki/Repositories---Deploy-Keys#remove-a-deploy-key
func DeleteRepoDeploykey(ctx *middleware.Context) {
if err := models.DeleteDeployKey(ctx.ParamsInt64(":id")); err != nil {
ctx.APIError(500, "DeleteDeployKey", err)
return
}
ctx.Status(204)
}

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package v1
package user
import (
api "github.com/gogits/go-gogs-client"
@@ -11,7 +11,7 @@ import (
"github.com/gogits/gogs/modules/middleware"
)
// GET /users/:username/tokens
// https://github.com/gogits/go-gogs-client/wiki/Users#list-access-tokens-for-a-user
func ListAccessTokens(ctx *middleware.Context) {
tokens, err := models.ListAccessTokens(ctx.User.Id)
if err != nil {
@@ -26,12 +26,8 @@ func ListAccessTokens(ctx *middleware.Context) {
ctx.JSON(200, &apiTokens)
}
type CreateAccessTokenForm struct {
Name string `json:"name" binding:"Required"`
}
// POST /users/:username/tokens
func CreateAccessToken(ctx *middleware.Context, form CreateAccessTokenForm) {
// https://github.com/gogits/go-gogs-client/wiki/Users#create-a-access-token
func CreateAccessToken(ctx *middleware.Context, form api.CreateAccessTokenOption) {
t := &models.AccessToken{
UID: ctx.User.Id,
Name: form.Name,

115
routers/api/v1/user/keys.go Normal file
View File

@@ -0,0 +1,115 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package user
import (
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/routers/api/v1/repo"
to "github.com/gogits/gogs/routers/api/v1/utils"
)
// GetUserByParams returns user whose name is presented in URL paramenter.
func GetUserByParams(ctx *middleware.Context) *models.User {
user, err := models.GetUserByName(ctx.Params(":username"))
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(404)
} else {
ctx.APIError(500, "GetUserByName", err)
}
return nil
}
return user
}
func composePublicKeysAPILink() string {
return setting.AppUrl + "api/v1/user/keys/"
}
func listPublicKeys(ctx *middleware.Context, uid int64) {
keys, err := models.ListPublicKeys(uid)
if err != nil {
ctx.APIError(500, "ListPublicKeys", err)
return
}
apiLink := composePublicKeysAPILink()
apiKeys := make([]*api.PublicKey, len(keys))
for i := range keys {
apiKeys[i] = to.ApiPublicKey(apiLink, keys[i])
}
ctx.JSON(200, &apiKeys)
}
// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#list-your-public-keys
func ListMyPublicKeys(ctx *middleware.Context) {
listPublicKeys(ctx, ctx.User.Id)
}
// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#list-public-keys-for-a-user
func ListPublicKeys(ctx *middleware.Context) {
user := GetUserByParams(ctx)
if ctx.Written() {
return
}
listPublicKeys(ctx, user.Id)
}
// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#get-a-single-public-key
func GetPublicKey(ctx *middleware.Context) {
key, err := models.GetPublicKeyByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrKeyNotExist(err) {
ctx.Error(404)
} else {
ctx.Handle(500, "GetPublicKeyByID", err)
}
return
}
apiLink := composePublicKeysAPILink()
ctx.JSON(200, to.ApiPublicKey(apiLink, key))
}
// CreateUserPublicKey creates new public key to given user by ID.
func CreateUserPublicKey(ctx *middleware.Context, form api.CreateKeyOption, uid int64) {
content, err := models.CheckPublicKeyString(form.Key)
if err != nil {
repo.HandleCheckKeyStringError(ctx, err)
return
}
key, err := models.AddPublicKey(uid, form.Title, content)
if err != nil {
repo.HandleAddKeyError(ctx, err)
return
}
apiLink := composePublicKeysAPILink()
ctx.JSON(201, to.ApiPublicKey(apiLink, key))
}
// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#create-a-public-key
func CreatePublicKey(ctx *middleware.Context, form api.CreateKeyOption) {
CreateUserPublicKey(ctx, form, ctx.User.Id)
}
// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#delete-a-public-key
func DeletePublicKey(ctx *middleware.Context) {
if err := models.DeletePublicKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
if models.IsErrKeyAccessDenied(err) {
ctx.APIError(403, "", "You do not have access to this key")
} else {
ctx.APIError(500, "DeletePublicKey", err)
}
return
}
ctx.Status(204)
}

Some files were not shown because too many files have changed in this diff Show More