Compare commits

...

201 Commits

Author SHA1 Message Date
Unknwon
1c7dcdd6b9 Update dep revision 2016-07-17 10:46:21 +08:00
lstahlman
25b3836418 Refresh repository mirror from database when the repository's name has changed. (#3276) 2016-07-17 09:30:43 +08:00
Unknwon
5aa2bf86f4 Update locales and .gopmfile 2016-07-17 09:25:30 +08:00
Unknwon
b0eb47cb1c Fix misselection of issues view type 2016-07-17 09:25:24 +08:00
lstahlman
e7a4f96fb6 Updated Issues and Issues Stats functions to include table aliases. This addresses errors involving ambiguous column references when filtering issues by the view type "Mentioning you". (#3269) 2016-07-17 09:18:35 +08:00
Unknwon
60110adc06 models/webhook: restrict deletion to be explicitly with repo and org ID 2016-07-17 08:33:59 +08:00
Dennis Chen
5ff2dfb23e api: delete repository webhooks (#3275)
Allows the deletion of a webhook from a repository at the
/:user/:repo/hooks/:id endpoint.

Solves drone/drone issue #1603.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2016-07-17 08:08:38 +08:00
Unknwon
eac32419fc templates/org/home: minor UI fix 2016-07-16 15:54:43 +08:00
Unknwon
e3d3d424b2 Minor fix for go vet 2016-07-16 15:15:00 +08:00
Unknwon
971e2c3bd6 Upgrade octicon to 4.3.0 2016-07-16 12:45:13 +08:00
Unknwon
c083d76567 #2937 able to prohibit user login 2016-07-16 10:22:16 +08:00
Unknwon
52322ef624 models/user_mail: refactor EmailAddress 2016-07-16 10:08:04 +08:00
Sandro Santilli
a4ea3bd015 Return avatar link as absolute url (#3235)
Fixes relative urls coming from api/v1

See https://github.com/drone/drone/issues/1701
2016-07-16 08:19:30 +08:00
Unknwon
3d93532c87 #3274 fix can't get webhook detail of organization 2016-07-16 01:02:55 +08:00
Unknwon
fff615d5fc Bump version 2016-07-16 00:37:21 +08:00
Unknwon
f1b8d52eb3 #2854 fix no mail notification when issue is closed/reopened 2016-07-16 00:36:39 +08:00
Unknwon
7ca5f8f119 models/repo: remove redundant info for some repo methods
RepoLink -> Link, RepoRelLink -> RelLink, FullRepoLink -> FullLink
2016-07-15 21:53:43 +08:00
Unknwon
194a742fb9 #2798 fix assign operation not take effect 2016-07-15 17:06:17 +08:00
Unknwon
160956dd31 Update Docker README 2016-07-15 14:32:42 +08:00
Unknwon
089bacd54e Update bindata and CSS 2016-07-15 14:13:30 +08:00
Kim Carlbäcker
d950bf68e3 Ignore Response Body for Slack Hooks #3169 (#3256) 2016-07-15 14:02:19 +08:00
Richard Mahn
7796c9e122 Fixes #3263 - Change for Fontawesome icons to not conflict withs semantic-ui (#3267) 2016-07-15 13:57:28 +08:00
Laica Lunasys
528ec9bffd Apply font for Japanese / Chinese (more) (#3266) 2016-07-15 13:52:37 +08:00
Atakan Goktepe
32ec4734f9 Changed Turkish language name to 'Türkçe' (#3268) 2016-07-15 13:44:49 +08:00
Andrey Arapov
6a98e7d914 docker: Support timezones (#3262) 2016-07-15 10:55:05 +08:00
Unknwon
a752f09055 #2709 validate username attribute fetched from LDAP 2016-07-12 07:07:57 +08:00
lstahlman
846bf2ca9f Add timestamps to repository api response (#3255)
Additional properties: created_at, updated_at
2016-07-12 06:28:51 +08:00
Kim Carlbäcker
f4ab50501e [Fix] Don't display way too large files #1513 (#3253)
* Add MaxDisplayFileSize setting

* Don't show files that are too large

* Localized FileTooLarge

* Change IsFileTooBig => IsFileTooLarge
2016-07-12 06:21:26 +08:00
Unknwon
de10387f41 #2586 bump git-module requirement 2016-07-12 06:20:09 +08:00
Unknwon
1faaaeb3d9 Update glide.lock 2016-07-11 07:57:15 +08:00
lstahlman
12cb84b97f Extend the API to include more repository properties (#3249)
Adds description, stars_count, forks_count, watchers_count and
open_issues_count.
2016-07-11 07:56:15 +08:00
Unknwon
fdcca9292e #2458 fix emoji been rendered inside raw content area 2016-07-11 05:28:56 +08:00
Unknwon
a1f717f65a Update locale 2016-07-09 23:59:13 +08:00
Unknwon
70a281a39b #2375 preserve cases for action content 2016-07-09 23:37:32 +08:00
Unknwon
9fcf66f0e0 Minor fix for #3246 2016-07-09 13:42:05 +08:00
Pablo Saavedra
98b152030d The pruning for the synchronized mirrors is a option now. Default value: enable_prune = true (#3246)
Executed go fmt

getEngine() not handles DB parameters (#2972) (#2974)

Uses .AllCols() for Update in updateMirror()

Spanish traslation removed

Fixed a wrong way to ommit the --prune option in process.ExecDir() for MirrorUpdate function
2016-07-09 13:22:28 +08:00
Pheng Heong TAN
467d7dacb6 Modify behaviour of repo-delete. (#3232)
Re: issues gogits/gogs#2863 and gogits/gogs#3231

As a result of modifications to the contents of the conf folder, `make bindata`
was run, causing an update to bindata.go.

Meta
-----
This commit will be rebased onto the 'develop' branch.
2016-07-09 13:13:57 +08:00
Unknwon
d62ab49978 #3057 retrieve webhook with repo_id
This prevents user retrieve arbitrary webhook by changing URL to
access webhook from other unauthorized repositories.
2016-07-08 13:57:09 +08:00
Unknwon
e30c701386 #3229 disallow repository name . and ..
Since . and .. has browser automatical behaviors, we need to disallow those names.
2016-07-08 07:34:05 +08:00
Unknwon
401bf944ef Use SecurityProtocol to replace UseSSL in LDAP config
Initially proposed by #2376 and fixes #3068 as well.
2016-07-08 07:25:09 +08:00
Unknwon
326c982660 Upgrade frontend assets 2016-07-07 06:04:55 +08:00
Unknwon
4b25bdfbc4 #3058 #3059 support correct page size and link header 2016-07-04 17:27:06 +08:00
Tom
528682a294 getEngine() not handles DB parameters (#2972) (#2974) 2016-07-02 22:39:39 +08:00
Unknwon
6aa00f7bcf #2968 use HTTP_ADDR to replace localhost 2016-07-02 18:54:48 +08:00
Unknwon
f485fcde96 #2947 fix inapproriate comment 2016-07-02 18:23:15 +08:00
Unknwon
6f6b37f148 #3078 update default app.ini 2016-07-01 22:27:52 +08:00
j.yao.SUSE
99c3a9390f change setting.go -> LocalUrl default value to (#3078) 2016-07-01 22:26:15 +08:00
Vasily Mikhaylichenko
f0df46c88a Add an OpenBSD daemon control script (#3060) 2016-07-01 22:24:41 +08:00
Unknwon
e84ac64964 Do not show filename not have suffifx .md 2016-07-01 15:34:03 +08:00
Unknwon
3a30c06345 Fix wiki vulnerabilities
- Arbitrary file creation leading to command execution
- .md file creation/deletion

Reported by Gabriel Campana.
2016-07-01 15:33:35 +08:00
Unknwon
a10ca2c5f6 #2959 update README version description 2016-06-30 15:16:29 +08:00
wanglinzhizhi
927d9f092b port 25 do not work, and port 465 is right (#3145)
QQ STMP host port is 465

host = smtp.qq.com:465

and need the Authorized
2016-06-30 04:04:15 +08:00
Unknwon
7938506e07 #518 update git-module require version 2016-06-30 02:21:23 +08:00
Unknwon
6f7276278d #3174 genetate bindata 2016-06-29 23:25:41 +08:00
Andrey Nering
743d22669a Re-work MAX_DIFF_LINES: supress diff per file, not the whole diff (#3174) 2016-06-29 23:11:00 +08:00
Cosmin Stroe
84841c8c4b Stricter parsing of issue URLs and commit URLs. (#3121) 2016-06-29 23:07:39 +08:00
Unknwon
274a2ca528 Update locale bindata 2016-06-28 00:26:18 +08:00
Sandro Santilli
d4aaef90e6 Fix typo in english/US message (#2938)
"is activate" -> "is activated"
2016-06-28 00:24:06 +08:00
Andrey Nering
6efb1e5626 Localize collaboration settings. (#3100)
Closes #2764
2016-06-28 00:22:30 +08:00
Unknwon
73b4acbb63 Update glide.yaml 2016-06-27 23:40:36 +08:00
Sandro Santilli
8a248696e9 Use a gopher as default avatar (rather than the gravatar logo) (#3208)
Also changes the avatar from a jpeg to a png, to allow for
transparent background. The indexed png is also smaller in size.

Note that at the moment the default avatar is only used when
the user requested a custom avatar and the custom avatar file
is not found (should never happen).

In the future the default avatar could be used as a default
return when by-mail avatar lookups fail too (both gravatar
and libravatar support passing a default)
2016-06-27 18:12:30 +08:00
Franz Schmidt
8b35c194ec Fixes #3110 (#3136) 2016-06-27 17:02:39 +08:00
Robin Lambertz
ac05f88641 Fix #3154 (#3155) 2016-06-27 16:58:53 +08:00
Unknwon
4bbb878d20 Minor fix for #3194
- Update locale bindata
2016-06-27 16:38:35 +08:00
Sandro Santilli
2ce60ff314 Include repository owner name and description in html title (#3194)
Closes #3192
2016-06-27 16:32:35 +08:00
SjonHortensius
17a4d8a5e5 Fix capitalisation of repo-name in news (#3203)
use 'official' repo.Name instead of incoming repoName; to enforce
correct capitalisation
2016-06-27 16:10:12 +08:00
Richard Bukovansky
04592c385b Adding myself (#3084)
As you included Czech translation to official distribution, I think I'm missing here.
I know, selfish as hell... ;)
2016-06-27 15:59:33 +08:00
Robin Lambertz
bc00da1721 Fix negative issue count (#3207) 2016-06-27 01:53:30 +08:00
Sandro Santilli
76a0e43e88 Do not assume avatar needs be changed from gravatar.com (#3209)
Always send user to settings screen to change avatar.
Drops "change_custom_avatar" localized message, keeps "change_avatar"
for the generic one.

NOTE: only changes the en-US locale, as per
https://github.com/gogits/gogs/wiki/Contributing-Code#those-we-do-not-accept

NOTE: requires rebuild of bindata.go to fully see effects
2016-06-27 01:51:09 +08:00
chriswatt
24caccccdd Fix empty space surrounding hidden issue labels (#3200) 2016-06-24 23:38:25 +08:00
Unknwon
26342b0c24 Update locale 2016-06-12 18:03:51 +08:00
Unknwon
a4eaddff81 #2958 Update dep version 2016-06-12 17:54:22 +08:00
Unknwon
c041273dd3 repo/http: clean code 2016-06-01 04:19:01 -07:00
Paul Tötterman
fb970b9d87 Add ServerName to tls.Config in LDAP auth (#3104)
From https://godoc.org/crypto/tls#Config

    ServerName is used to verify the hostname on the returned
    certificates unless InsecureSkipVerify is given. It is also included
    in the client's handshake to support virtual hosting unless it is
    an IP address.

This is needed for certificate validation without InsecureSkipVerify.
2016-06-01 01:11:28 -07:00
Unknwon
0240f520ab #2954 minor fix for when to set HTML alternative 2016-05-30 01:50:20 -07:00
Unknwon
3d105733a9 Update glide.lock 2016-05-30 01:39:49 -07:00
Unknwon
8df3ba96f3 #2954 use text/plain as default email content format 2016-05-30 01:32:01 -07:00
Sandro Santilli
d35a1c30f4 Do not write HTML in text/plain mail part (#2954)
* Do not write HTML in text/plain mail part

Fixes #2928

* Pass text/plain first, text/html second

* Do not send plain/text email if html2text failed (untested)
2016-05-30 01:18:49 -07:00
Unknwon
e9ae926e04 #809 fix wrong closed issue count when create closed issue via API
Add start count corrector for Repository.NumClosedIssues
2016-05-27 18:23:39 -07:00
Thomas Fanninger
28c03f1147 Update .gopmfile (#3133)
Build only work with the current master of the package. Otherwise, I get this error.
```
...
# github.com/gogits/gogs/routers/api/v1/convert
routers/api/v1/convert/convert.go:200: undefined: gogs.Team
routers/api/v1/convert/convert.go:201: undefined: gogs.Team
...
```
2016-05-26 19:05:50 -07:00
Alex Myasoedov
84d9aff8a2 gogs dump tempdir flag (#3086) 2016-05-23 17:10:05 -07:00
Andrey Nering
12d30255a7 Add comment note (#3093) 2016-05-23 13:24:40 -07:00
Unknwon
7826eae452 #3045 fix DEPRECATED Action signature erorr 2016-05-12 14:32:28 -04:00
Unknwon
8a2347592d locale: update Czech 2016-05-12 14:31:06 -04:00
Jean-Philippe Roemer
bcd4adb3a0 Update docker/build.sh script to use glide & make (#3079)
* docker: update build script to use glide + make

- docker/build.sh will now use glide to fetch dependencies
- glide is built from source to keep compatibility with arm
  (no pre-prebuilt binary for arm)
- docker/build.sh will also now use the provided Makefile
  It will generate an error when trying to get git build has as we do
  not ship the 88mo .git directory during the build (should not cause
  any problem as the variable it sets was not set previously)

* docker: fix docker arm build

- drop gosu version back to 1.7 as gosu binary for armhf is broken
- see tianon/gosu#19

* docker: update gosu to 1.9

Signed-off-by: Jean-Philippe Roemer <jp@roemer.im>
2016-05-11 13:11:59 -04:00
Unknwon
bf5faf76eb #809 able to set issue state to closed when create 2016-05-11 12:19:26 -04:00
Unknwon
f473895c41 bindata: follow up data clean 2016-05-11 12:17:52 -04:00
Unknwon
fbf43c31e5 Add Czech support 2016-05-11 12:00:47 -04:00
Kim Carlbäcker
3c0c7a9f83 Fix listing team members (#3048) 2016-05-06 20:02:36 -04:00
Siarhei Navatski
13216c5c20 Update glide.lock with latest go-gogs-client (#2939) 2016-05-06 19:48:02 -04:00
Julien Reichardt
6be9a2c1db Add DPlatform as an installation way (#3044) 2016-05-06 19:44:05 -04:00
Andrey Nering
d8612f7704 Fix remove folder issues, including initialization failling. (#2969)
- Prevent panic on creating notice if database is not available
- Prevent incorrect folder on Windows ("/" instead of "\")
2016-05-06 15:48:18 -04:00
Unknwon
0a78d99a4d models/release: filter input to prevent command line argument vulnerability 2016-05-06 15:40:41 -04:00
Kim Carlbäcker
3df8eb60e3 PDF-Previews in file-lists now working (#3000) 2016-04-26 21:48:44 -04:00
Unknwon
0325bec283 #2895 minor fix for bug of xorm 2016-04-26 00:22:03 -04:00
Thomas Boerger
dfad51fe9e Made the issue stats query more secure with parameterized placeholders (#2895) 2016-04-26 00:07:49 -04:00
Unknwon
7049cb9d97 Add new language support
- Update language choose dropdown to fit more languages
2016-04-25 13:40:23 -04:00
Unknwon
78b8b63774 #2992 set default style name when empty in AfterSet 2016-04-22 18:36:05 -04:00
Cosmin Stroe
ba314a7a36 Support alphanumeric issue style (ABC-1234) for external issue tracker (#2992) 2016-04-22 18:28:08 -04:00
Tamás Molnár
39356f4238 Set utf-8 charset for text files when serving raw content (#2898) 2016-04-20 19:38:11 -04:00
Kim Carlbäcker
b3c05026df [Feature/WIP] Confirm on editing forms (fixes #2881) (#2980)
* Add and start jQuery AreYouSure

* Update SimpleMDE to 1.10.1 for `forceSync` support

* Forgot to remove old version SimpleMDE 1.10.0

* formatting -.-
2016-04-19 16:45:28 -04:00
Kim Carlbäcker
ce36fd7a49 Fixed #2909 (#2979) 2016-04-19 16:35:36 -04:00
Jean-Philippe Roemer
69e00f9948 docker: update documentation for container options (#2965)
- Created a Container options section in `docker/README.md`
- Add documentation for SOCAT_LINK
- Move CROND documentation to the new section
2016-04-12 10:46:32 -04:00
Unknwon
3257df0da3 Update locales 2016-04-11 18:38:25 -04:00
Unknwon
0f2869069b Merge pull request #2920 from l2dy/patch-1
Update ISC license
2016-04-05 13:36:58 -04:00
Unknwon
a27c6f4b75 #2916 fix sort' field missing on issue pagination link 2016-04-04 19:48:10 -04:00
Unknwon
d27ca649c7 api/admin: add/remove organization team repository 2016-04-04 19:41:34 -04:00
Unknwon
d9900e4dbc Merge pull request #2914 from psychomario/linenumoptimize
Reduce line number creation to one DOM manipulation
2016-04-04 19:33:52 -04:00
l2dy
e75a1444af Update ISC license 2016-04-03 01:56:48 +00:00
PsychoMario
b35157f4ff reduce line number creation to one DOM manipulation 2016-03-30 20:28:40 +01:00
Unknwon
762ab056a2 Fix XORM IN condition table name parse 2016-03-27 18:21:37 -04:00
Unknwon
78481f0e42 Merge pull request #2894 from tboerger/feature/join-condition
Followup fix for previous query fix
2016-03-27 18:07:52 -04:00
Thomas Boerger
746c7fd4e7 Followup fix for previous query fix 2016-03-28 00:05:49 +02:00
Unknwon
7f26ae0b45 Merge pull request #2893 from tboerger/feature/sql-security
Try to make the SQL queries cleaner and more secure
2016-03-27 17:40:28 -04:00
Thomas Boerger
b5948f2e71 Made the issues query more secure and simpler 2016-03-27 23:26:45 +02:00
Thomas Boerger
79a1bfd963 Try to make the SQL queries cleaner and more secure 2016-03-27 22:59:57 +02:00
Unknwon
ac53bb593d #2878 print error of JSON unmarshal and always returns a valid object 2016-03-26 16:42:20 -04:00
Unknwon
dd36c431ec #2842 add quotes to attachment file name 2016-03-25 22:11:58 -04:00
Unknwon
b1d41cfa60 #1692 add admin APIs to add/remove a user from teams 2016-03-25 18:04:02 -04:00
Unknwon
9dda9ef07c Merge pull request #2883 from nikkomiu/develop
Fixes #2842 Parses URL through EscapePound template function
2016-03-25 17:09:21 -04:00
Nikko Miu
9a43fcb61c Changed EscapePound function with string replace function 2016-03-24 20:48:52 -05:00
Unknwon
5ec8ef0230 Update locales 2016-03-23 15:56:56 -04:00
Unknwon
d3db1b2591 Merge pull request #2879 from dakira/develop
use monospace font for wiki and issue textareas (fix #2869)
2016-03-23 10:32:24 -04:00
Matthias Niess
3decc0b3d6 use monospace font for wiki and issue textareas (fix #2869) 2016-03-23 13:55:07 +01:00
Unknwon
98b58fa050 Handle windows deletion when start
Fix #2872
2016-03-23 03:16:53 -04:00
Unknwon
5e11341232 Fix status code 2016-03-21 12:57:04 -04:00
Unknwon
90e93b1f3a Change list teams API to non-admin specific 2016-03-21 12:53:04 -04:00
Unknwon
e6f927f61a #1692 api: admin list and create team under organization 2016-03-21 12:47:54 -04:00
Unknwon
60ae8ac3d2 Add route for #2846 2016-03-21 10:49:46 -04:00
Unknwon
004fb30ebe Remove code for checking ssh-keygen 2016-03-19 20:31:23 -04:00
Unknwon
3fb4f7f498 Prepare release 2016-03-19 14:51:41 -04:00
Unknwon
9e09e48502 #2850 fix potential SSH commands dislocation
When use builtin SSH server with concurrent operations, there are probabilities
One connection could use the command from another connections.

Fix this by set SSH_ORIGINAL_COMMAND for each command, not set in global scope.
2016-03-18 06:13:16 -04:00
Unknwon
c79774e8d4 Update locales 2016-03-18 04:03:13 -04:00
Unknwon
d6b09c35f7 Update .gopmfile and fix #2848 2016-03-17 14:29:45 -04:00
Unknwon
0048980da5 Merge pull request #2845 from moltam/feature/org-member-full-name-avatar
Display org member's full name in link title.
2016-03-16 17:17:45 -04:00
Tamás Molnár
d169d00be6 Display org member's full name in link title. 2016-03-16 22:04:19 +01:00
Unknwon
ff731ea07d #2814 LOWER() column value within search 2016-03-16 16:55:19 -04:00
Unknwon
9a5a27ea8d Improve repository lable style
- add border-radius to filter list items
- use color as background of label for issue/pull view page
2016-03-15 19:52:40 -04:00
Unknwon
94d7b62922 Merge pull request #2831 from odinuge/user-search-name
Make user search look in username, name and email
2016-03-15 19:39:12 -04:00
Unknwon
2df42e369e Merge pull request #2829 from odinuge/htmlmeta
Set description meta tag correctly
2016-03-15 17:54:44 -04:00
Unknwon
1f5bb08c25 Merge pull request #2836 from odinuge/markdown-links-rebase
Fix relative links in markdown files
2016-03-15 17:43:33 -04:00
Odin Ugedal
01ff65a93e Fix indent 2016-03-15 22:35:59 +01:00
Odin Ugedal
8540043c45 Make separate string variables for space 2016-03-15 21:28:55 +01:00
Odin Ugedal
f57adf3637 Fix relative links in markdown files
Replace spaces with "%20" in "urlPrefix", before markdon processing.
The spaces were causing blackfriday (markdown processor) to behave
strange. This fixes #2545.
2016-03-15 20:43:46 +01:00
Odin Ugedal
a75fa58e1c Make description meta tag golang 1.4 compatible 2016-03-15 19:57:19 +01:00
Odin Ugedal
6ccb2d36cf Remove email from user search 2016-03-15 19:44:58 +01:00
Unknwon
414e5f09c7 Merge pull request #2832 from dankm/build-flags
Make go's build flags a variable
2016-03-15 14:42:15 -04:00
Unknwon
a04596659b Merge pull request #2830 from odinuge/branchname-compare
Fix problems with '#' in branchname
2016-03-15 14:36:58 -04:00
Unknwon
149d62a648 #13 fix admin can't search private repos
- update glide info
2016-03-15 14:23:12 -04:00
Dan McGregor
db3905c0a3 Make go's build flags a variable
This allows the user to specify build flags from the make command
line. For example to force a complete rebuild one could use:

make BUILD_FLAGS='-v -a' TAGS="sqlite"
2016-03-15 07:55:06 -06:00
Odin Ugedal
3253e3c5aa Make user search look in username, name and email
Make user search function look in username (lower_name), full name
(full_name) and primary email (email). This will benefit searching after
user in "explore", admin panel and when adding new collaborators.
2016-03-15 14:16:58 +01:00
Odin Ugedal
c9321550e0 Add prorper escaping of url in issue form 2016-03-15 11:56:49 +01:00
Odin Ugedal
ac390d28b8 Fix problems with '#' in branchname
Add proper escaping of '#' in branchname in compare when doing pull
requests. This addresses issue #2822.
2016-03-15 11:36:23 +01:00
Odin Ugedal
561e5f9ccb Set description meta tag correctly
Set the description meta tag correctly when there is no repo
description. Also use the  ability to trim trailing whitespaces,
to make the template cleaner.
2016-03-15 10:17:23 +01:00
Unknwon
9df5c39bca Merge pull request #2824 from odinuge/repo-metadata
Set HTML meta values corresponding to repository
2016-03-14 16:47:23 -04:00
Unknwon
9976fc6782 Generate bindata for #2823 2016-03-14 16:46:36 -04:00
Unknwon
8966f5635d Merge pull request #2823 from zacheryph/feature/local-only-password-reset
Prevent `Forgot Password` for non local users
2016-03-14 16:44:05 -04:00
Odin Ugedal
85d7afeba0 Set HTML meta values corresponding to repository
Use the authors name, and the description of the repo in HTML meta.
Pages without repository context will display as before.
2016-03-14 17:32:24 +01:00
Zachery Hostens
63e21c146a ensure we don’t try changing LDAP passswords 2016-03-14 09:40:16 -05:00
Unknwon
9bd9ad4205 #1692 add CRUD issue APIs
- Fix go-gogs-client#10
- Related to #809
2016-03-13 23:20:22 -04:00
Unknwon
dd6faf7f9b Convert all API handers to use *context.APIContext 2016-03-13 18:49:16 -04:00
Unknwon
db4da7beec Add APIContext 2016-03-13 17:37:44 -04:00
Unknwon
b4f47a7623 #1891 attempt to fix invalid csrf token 2016-03-12 20:56:03 -05:00
Unknwon
af8eccc02e Update glide.lock 2016-03-12 14:44:28 -05:00
Unknwon
820be19cf5 Merge pull request #2796 from saboya/custom_app_data_path
Making AppDataPath customizable.
2016-03-12 13:53:37 -05:00
Unknwon
d733efc1cc #1286 #2098 Alpha support for custom templates
No guarantee for compatibility with future changes
2016-03-12 13:48:34 -05:00
Unknwon
985a0f3450 Generate css for #2816 2016-03-11 18:59:26 -05:00
Unknwon
322515a50b Merge pull request #2816 from MATTENN/custom_gogs_branch
Add Japanese Fonts
2016-03-11 18:58:45 -05:00
MATTENN
13e1fa6789 Add Japanese Fonts
By adding a Japanese font in the less file, easier to see the display in
Japanese.
2016-03-12 08:49:24 +09:00
Unknwon
c6277cce51 Minor fixes for #2761 2016-03-11 17:57:44 -05:00
Unknwon
6530375dbf Merge pull request #2761 from soudy/grey-out-merge-commit
Grey out merge commits
2016-03-11 17:51:17 -05:00
Unknwon
449a6e490b Merge pull request #2815 from allonsy/develop
remove errant debug statement
2016-03-11 17:49:13 -05:00
Alec S
ebea20b4e7 remove errant debug statement 2016-03-11 16:44:09 -06:00
Unknwon
f76d821bda fix #2804 2016-03-11 17:12:37 -05:00
Unknwon
263304b6b7 #13 fix postgres aggregate 2016-03-11 16:11:33 -05:00
Unknwon
73e98c91c3 Update locales 2016-03-11 15:47:49 -05:00
Unknwon
2bf8494332 #13 finish user and repository search
Both are possible on explore and admin panel
2016-03-11 15:33:12 -05:00
Unknwon
df2bdf7ea3 Use glide 2016-03-11 12:18:27 -05:00
Unknwon
514382e2eb Rename module: middleware -> context 2016-03-11 11:56:52 -05:00
Unknwon
cb1eadc276 Merge pull request #2810 from maxlazio/fix_updated_and_created
Update uses of updated and created
2016-03-11 10:15:55 -05:00
Marin Jankovski
1314ba219e Updated and created were appended with _unix. Fresh databases have only the newly named fields. 2016-03-11 12:43:35 +01:00
Unknwon
5267dce210 Fix ref comment from commit create empty feed 2016-03-11 05:11:58 -05:00
Unknwon
97c48da49f Merge pull request #2803 from Rukenshia/develop
Using HTML Description of repositories in the 'Explore' view. Fixes #…
2016-03-10 16:17:40 -05:00
Jan Christophersen
1e74ee51ff Using HTML Description of repositories in the 'Explore' view. Fixes #2800 2016-03-10 21:31:13 +01:00
Unknwon
067edcdb90 Merge pull request #2802 from allonsy/develop
readd 'dashboard' to title
2016-03-10 13:52:33 -05:00
Alec S
792c13cf0a readd 'dashboard' to title 2016-03-10 12:10:03 -06:00
Unknwon
3bd7d3b1c5 Merge pull request #2797 from allonsy/develop
Create custom dashboard title
2016-03-10 08:37:11 -05:00
Alec S
af847ef94e Merge branch 'develop' of github.com:gogits/gogs into develop 2016-03-09 22:56:52 -06:00
Alec S
bfed3ea7d3 fix indentation 2016-03-09 22:56:03 -06:00
Unknwon
b44e4d7cb0 Merge pull request #2785 from Rukenshia/develop
Allowing site admins to view private repositories in org/home
2016-03-09 23:20:08 -05:00
Unknwon
eed9966ad6 #2727 fix incompatible SQL in PostgreSQL 2016-03-09 23:18:39 -05:00
Alec S
affa3c2dbf Remove dashboard keyword from title 2016-03-09 21:01:43 -06:00
Alec S
6775ac7334 change page titles for user and org dashes 2016-03-09 20:46:36 -06:00
Rodrigo Saboya
2c626371b0 Adding APP_DATA_PATH entry to the default app.ini. 2016-03-09 23:16:43 -03:00
Rodrigo Saboya
3cacec9163 Making AppDataPath customizable. 2016-03-09 22:53:42 -03:00
Unknwon
ad513a20e9 #2302 Replace time.Time with Unix Timestamp (int64) 2016-03-09 19:53:30 -05:00
Jan Christophersen
72a8fa3bc8 Allowing site admins to view private repositories in org/home 2016-03-08 18:20:00 +01:00
Unknwon
0c9a616326 Update frontend resources 2016-03-07 00:11:12 -05:00
Unknwon
0e9bc2d410 Fix pull request availability check 2016-03-06 23:57:46 -05:00
Steven Oud
1d3ec27cb7 Put if statement of grey merge commits on one line 2016-03-05 17:59:07 +01:00
Steven Oud
a0cd59bd0e Grey out merge commits 2016-03-05 17:00:38 +01:00
346 changed files with 75618 additions and 4924 deletions

View File

@@ -1,7 +1,5 @@
.git
.git/**
conf
conf/**
packager
packager/**
scripts
@@ -9,13 +7,13 @@ scripts/**
.github/
.github/**
config.codekit
LICENSE
Makefile
.dockerignore
*.yml
*.md
.bra.toml
.editorconfig
.gitignore
.gopmfile
Dockerfile*
vendor
vendor/**
gogs

View File

@@ -12,7 +12,7 @@ For bug reports, please give the relevant info:
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at http://try.gogs.io:
- [ ] Yes
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant
- Log gist:

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ output*
gogs.sublime-project
gogs.sublime-workspace
/release
vendor

View File

@@ -3,51 +3,55 @@ path = github.com/gogits/gogs
[deps]
github.com/bradfitz/gomemcache = commit:fb1f79c
github.com/codegangsta/cli = commit:a294348
github.com/go-macaron/binding = commit:a68f342
github.com/codegangsta/cli = commit:1efa31f
github.com/go-macaron/binding = commit:9440f33
github.com/go-macaron/cache = commit:5617353
github.com/go-macaron/captcha = commit:8aa5919
github.com/go-macaron/csrf = commit:546646c
github.com/go-macaron/csrf = commit:6a9a7df
github.com/go-macaron/gzip = commit:cad1c65
github.com/go-macaron/i18n = commit:d2d3329
github.com/go-macaron/i18n = commit:ef57533
github.com/go-macaron/inject = commit:c5ab7bf
github.com/go-macaron/session = commit:66031fc
github.com/go-macaron/toolbox = commit:82b5115
github.com/go-sql-driver/mysql = commit:0f2db9e
github.com/go-xorm/core = commit:5021584
github.com/go-xorm/xorm = commit:1045aa0
github.com/gogits/chardet = commit:2404f77725
github.com/gogits/cron = commit:3abc0f8
github.com/gogits/git-module = commit:76e8cce
github.com/gogits/go-gogs-client = commit:d584b1e
github.com/issue9/identicon = commit:f8c0d2c
github.com/go-sql-driver/mysql = commit:3654d25
github.com/go-xorm/core = commit:bc1b7f8
github.com/go-xorm/xorm = commit:b8b1711
github.com/gogits/chardet = commit:2404f77
github.com/gogits/cron = commit:96040e4
github.com/gogits/git-module = commit:db93fa5
github.com/gogits/go-gogs-client = commit:ee68cd9
github.com/issue9/identicon = commit:d36b545
github.com/jaytaylor/html2text = commit:52d9b78
github.com/kardianos/minwinsvc = commit:cad6b2b
github.com/klauspost/compress = commit:2d3d403
github.com/klauspost/compress = commit:14eb9c4
github.com/klauspost/cpuid = commit:09cded8
github.com/klauspost/crc32 = commit:19b0b33
github.com/lib/pq = commit:165a352
github.com/mattn/go-sqlite3 = commit:45f056c
github.com/lib/pq = commit:ee1442b
github.com/mattn/go-sqlite3 = commit:38ee283
github.com/mcuadros/go-version = commit:d52711f
github.com/microcosm-cc/bluemonday = commit:4ac6f27
github.com/msteinert/pam = commit:02ccfbf
github.com/nfnt/resize = commit:4d93a29
github.com/russross/blackfriday = commit:006144a
github.com/satori/go.uuid = commit:e673fdd
github.com/russross/blackfriday = commit:4e6f303
github.com/satori/go.uuid = commit:879c588
github.com/sergi/go-diff = commit:ec7fdbb
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:3b48b66
github.com/Unknwon/i18n = commit:39d6f27
github.com/Unknwon/paginater = commit:7748a72
golang.org/x/net = commit:a4bbce9
golang.org/x/text = commit:a71fd10
golang.org/x/crypto = commit:5dc8cb4
golang.org/x/crypto = commit:77f4136
golang.org/x/net = commit:3f122ce
golang.org/x/sys = commit:7f918dd
golang.org/x/text = commit:e477511
gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
gopkg.in/asn1-ber.v1 = commit:4e86f43
gopkg.in/gomail.v2 = commit:5ceb8e6
gopkg.in/ini.v1 = commit:776aa73
gopkg.in/ldap.v2 = commit:07a7330
gopkg.in/macaron.v1 = commit:b9eee38
gopkg.in/redis.v2 = commit:e617904962
gopkg.in/bufio.v1 = commit:567b2bf
gopkg.in/gomail.v2 = commit:81ebce5
gopkg.in/ini.v1 = commit:72ba3e6
gopkg.in/ldap.v2 = commit:0e7db8e
gopkg.in/macaron.v1 = commit:2133042
gopkg.in/redis.v2 = commit:e617904
[res]
include = public|scripts|templates

View File

@@ -2,9 +2,9 @@ FROM alpine:3.3
MAINTAINER jp@roemer.im
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64 /usr/sbin/gosu
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-amd64 /usr/sbin/gosu
RUN chmod +x /usr/sbin/gosu \
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat tzdata
ENV GOGS_CUSTOM /data/gogs

View File

@@ -2,12 +2,12 @@ FROM hypriot/rpi-alpine-scratch:v3.2
MAINTAINER jp@roemer.im, raxetul@gmail.com
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.7/gosu-armhf /usr/sbin/gosu
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-armhf /usr/sbin/gosu
RUN chmod +x /usr/sbin/gosu \
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/main/" | tee /etc/apk/repositories \
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/community/" | tee -a /etc/apk/repositories \
&& apk -U --no-progress upgrade && rm -f /var/cache/apk/APKINDEX.* \
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat tzdata
ENV GOGS_CUSTOM /data/gogs

View File

@@ -6,6 +6,7 @@ LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
GENERATED := modules/bindata/bindata.go public/css/gogs.css
TAGS = ""
BUILD_FLAGS = "-v"
RELEASE_ROOT = "release"
RELEASE_GOGS = "release/gogs"
@@ -16,14 +17,14 @@ NOW = $(shell date -u '+%Y%m%d%I%M%S')
.IGNORE: public/css/gogs.css
build: $(GENERATED)
go install -v -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
go install $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
govet:
go tool vet -composites=false -methods=false -structtags=false .
build-dev: $(GENERATED) govet
go install -v -race -tags '$(TAGS)'
go install $(BUILD_FLAGS) -race -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
pack:

View File

@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
##### Current version: 0.9.0
##### Current tip version: 0.9.46 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
| Web | UI | Preview |
|:-------------:|:-------:|:-------:|
@@ -49,7 +49,7 @@ The goal of this project is to make the easiest, fastest, and most painless way
- Mail service
- Administration panel
- Supports MySQL, PostgreSQL, SQLite3 and [TiDB](https://github.com/pingcap/tidb) (experimental)
- Multi-language support ([15 languages](https://crowdin.com/project/gogs))
- Multi-language support ([18 languages](https://crowdin.com/project/gogs))
## System Requirements
@@ -96,6 +96,7 @@ There are 5 ways to install Gogs:
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
- [DPlatform](https://github.com/j8r/DPlatform)
## Software and Service Support
@@ -105,6 +106,7 @@ There are 5 ways to install Gogs:
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT)
- [Kanboard](http://kanboard.net/plugin/gogs-webhook) (Project Management)
- [BearyChat](https://bearychat.com/) (Team Communication)
- [HiWork](http://www.hiwork.cc/) (Team Communication)
### Product Support

View File

@@ -30,7 +30,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([15 种语言]([more](https://crowdin.com/project/gogs))
- 支持多语言本地化([18 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求
@@ -68,6 +68,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
- [DPlatform](https://github.com/j8r/DPlatform)
## 软件及服务支持
@@ -77,6 +78,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)IT
- [Kanboard](http://kanboard.net/plugin/gogs-webhook)(项目管理)
- [BearyChat](https://bearychat.com/)(团队交流)
- [HiWork](http://www.hiwork.cc/)(团队交流)
### 产品支持

View File

@@ -59,7 +59,7 @@ func pemBlockForKey(priv interface{}) *pem.Block {
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
if err != nil {
log.Fatal("unable to marshal ECDSA private key: %v", err)
log.Fatalf("Unable to marshal ECDSA private key: %v\n", err)
}
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
default:
@@ -67,7 +67,7 @@ func pemBlockForKey(priv interface{}) *pem.Block {
}
}
func runCert(ctx *cli.Context) {
func runCert(ctx *cli.Context) error {
if len(ctx.String("host")) == 0 {
log.Fatal("Missing required --host parameter")
}
@@ -153,9 +153,11 @@ func runCert(ctx *cli.Context) {
keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatal("failed to open key.pem for writing: %v", err)
log.Fatalf("Failed to open key.pem for writing: %v\n", err)
}
pem.Encode(keyOut, pemBlockForKey(priv))
keyOut.Close()
log.Println("Written key.pem")
return nil
}

View File

@@ -20,7 +20,9 @@ var CmdCert = cli.Command{
Action: runCert,
}
func runCert(ctx *cli.Context) {
func runCert(ctx *cli.Context) error {
fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.")
os.Exit(1)
return nil
}

View File

@@ -28,11 +28,12 @@ It can be used for backup and capture Gogs server image to send to maintainer`,
Action: runDump,
Flags: []cli.Flag{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
boolFlag("verbose, v", "show process details"),
boolFlag("verbose, v", "Show process details"),
stringFlag("tempdir, t", os.TempDir(), "Temporary dir path"),
},
}
func runDump(ctx *cli.Context) {
func runDump(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
@@ -40,7 +41,11 @@ func runDump(ctx *cli.Context) {
models.LoadConfigs()
models.SetEngine()
TmpWorkDir, err := ioutil.TempDir(os.TempDir(), "gogs-dump-")
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
log.Fatalf("Path does not exist: %s", tmpDir)
}
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gogs-dump-")
if err != nil {
log.Fatalf("Fail to create tmp work directory: %v", err)
}
@@ -68,21 +73,21 @@ func runDump(ctx *cli.Context) {
log.Fatalf("Fail to create %s: %v", fileName, err)
}
if err := z.AddFile("gogs-repo.zip", reposDump); err !=nil {
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 {
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 {
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 {
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err)
}
// FIXME: SSH key file.
@@ -94,4 +99,6 @@ func runDump(ctx *cli.Context) {
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
os.RemoveAll(TmpWorkDir)
log.Printf("Finish dumping in file %s", fileName)
return nil
}

View File

@@ -129,7 +129,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
}
}
func runServ(c *cli.Context) {
func runServ(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
@@ -138,7 +138,7 @@ func runServ(c *cli.Context) {
if setting.SSH.Disabled {
println("Gogs: SSH has been disabled")
return
return nil
}
if len(c.Args()) < 1 {
@@ -149,7 +149,7 @@ func runServ(c *cli.Context) {
if len(cmd) == 0 {
println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
println("If this is unexpected, please log in with password and setup Gogs under another user.")
return
return nil
}
verb, args := parseCmd(cmd)
@@ -290,4 +290,6 @@ func runServ(c *cli.Context) {
fail("Internal error", "UpdatePublicKey: %v", err)
}
}
return nil
}

View File

@@ -24,7 +24,7 @@ var CmdUpdate = cli.Command{
},
}
func runUpdate(c *cli.Context) {
func runUpdate(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
@@ -33,7 +33,7 @@ func runUpdate(c *cli.Context) {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
return
return nil
}
args := c.Args()
@@ -53,4 +53,6 @@ func runUpdate(c *cli.Context) {
if err := models.AddUpdateTask(&task); err != nil {
log.GitLogger.Fatal(2, "AddUpdateTask: %v", err)
}
return nil
}

View File

@@ -34,8 +34,8 @@ import (
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/context"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template"
"github.com/gogits/gogs/routers"
@@ -78,21 +78,24 @@ func checkVersion() {
// Check dependency version.
checkers := []VerChecker{
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.2.0304"},
{"github.com/go-macaron/binding", binding.Version, "0.2.1"},
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.5"},
{"github.com/go-macaron/binding", binding.Version, "0.3.2"},
{"github.com/go-macaron/cache", cache.Version, "0.1.2"},
{"github.com/go-macaron/csrf", csrf.Version, "0.0.5"},
{"github.com/go-macaron/i18n", i18n.Version, "0.2.0"},
{"github.com/go-macaron/csrf", csrf.Version, "0.1.0"},
{"github.com/go-macaron/i18n", i18n.Version, "0.3.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.8.4"},
{"gopkg.in/macaron.v1", macaron.Version, "0.8.0"},
{"github.com/gogits/git-module", git.Version, "0.2.9"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.7.3"},
{"gopkg.in/macaron.v1", macaron.Version, "1.1.4"},
{"github.com/gogits/git-module", git.Version, "0.3.2"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.7.4"},
}
for _, c := range checkers {
if !version.Compare(c.Version(), c.Expected, ">=") {
log.Fatal(4, "Package '%s' version is too old (%s -> %s), did you forget to update?", c.ImportPath, c.Version(), c.Expected)
log.Fatal(4, `Dependency outdated!
Package '%s' current version (%s) is below requirement (%s),
please use following command to update this package and recompile Gogs:
go get -u %[1]s`, c.ImportPath, c.Version(), c.Expected)
}
}
}
@@ -123,11 +126,16 @@ func newMacaron() *macaron.Macaron {
SkipLogging: setting.DisableRouterLog,
},
))
funcMap := template.NewFuncMap()
m.Use(macaron.Renderer(macaron.RenderOptions{
Directory: path.Join(setting.StaticRootPath, "templates"),
Funcs: template.NewFuncMap(),
IndentJSON: macaron.Env != macaron.PROD,
Directory: path.Join(setting.StaticRootPath, "templates"),
AppendDirectories: []string{path.Join(setting.CustomPath, "templates")},
Funcs: funcMap,
IndentJSON: macaron.Env != macaron.PROD,
}))
models.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
path.Join(setting.CustomPath, "templates/mail"), funcMap)
localeNames, err := bindata.AssetDir("conf/locale")
if err != nil {
@@ -157,6 +165,7 @@ func newMacaron() *macaron.Macaron {
m.Use(session.Sessioner(setting.SessionConfig))
m.Use(csrf.Csrfer(csrf.Options{
Secret: setting.SecretKey,
Cookie: setting.CSRFCookieName,
SetCookie: true,
Header: "X-Csrf-Token",
CookiePath: setting.AppSubUrl,
@@ -169,11 +178,11 @@ func newMacaron() *macaron.Macaron {
},
},
}))
m.Use(middleware.Contexter())
m.Use(context.Contexter())
return m
}
func runWeb(ctx *cli.Context) {
func runWeb(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
@@ -182,10 +191,10 @@ func runWeb(ctx *cli.Context) {
m := newMacaron()
reqSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true})
ignSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: setting.Service.RequireSignInView})
ignSignInAndCsrf := middleware.Toggle(&middleware.ToggleOptions{DisableCsrf: true})
reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true})
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView})
ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
bindIgnErr := binding.BindIgnErr
@@ -193,17 +202,17 @@ func runWeb(ctx *cli.Context) {
// Especially some AJAX requests, we can reduce middleware number to improve performance.
// Routers.
m.Get("/", ignSignIn, routers.Home)
m.Get("/explore", ignSignIn, routers.Explore)
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubUrl + "/explore/repos")
})
m.Get("/repos", routers.ExploreRepos)
m.Get("/users", routers.ExploreUsers)
}, ignSignIn)
m.Combo("/install", routers.InstallInit).Get(routers.Install).
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
// ***** START: API *****
m.Group("/api", func() {
apiv1.RegisterRoutes(m)
}, ignSignIn)
// ***** END: API *****
// ***** START: User *****
m.Group("/user", func() {
m.Get("/login", user.SignIn)
@@ -231,7 +240,7 @@ func runWeb(ctx *cli.Context) {
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)
m.Post("/applications/delete", user.SettingsDeleteApplication)
m.Route("/delete", "GET,POST", user.SettingsDelete)
}, reqSignIn, func(ctx *middleware.Context) {
}, reqSignIn, func(ctx *context.Context) {
ctx.Data["PageIsUserSettings"] = true
})
@@ -246,7 +255,7 @@ func runWeb(ctx *cli.Context) {
})
// ***** END: User *****
adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
// ***** START: Admin *****
m.Group("/admin", func() {
@@ -295,7 +304,7 @@ func runWeb(ctx *cli.Context) {
m.Get("/stars", user.Stars)
})
m.Get("/attachments/:uuid", func(ctx *middleware.Context) {
m.Get("/attachments/:uuid", func(ctx *context.Context) {
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
if err != nil {
if models.IsErrAttachmentNotExist(err) {
@@ -332,8 +341,8 @@ func runWeb(ctx *cli.Context) {
m.Get("/template/*", dev.TemplatePreview)
}
reqRepoAdmin := middleware.RequireRepoAdmin()
reqRepoWriter := middleware.RequireRepoWriter()
reqRepoAdmin := context.RequireRepoAdmin()
reqRepoWriter := context.RequireRepoWriter()
// ***** START: Organization *****
m.Group("/org", func() {
@@ -347,14 +356,14 @@ func runWeb(ctx *cli.Context) {
m.Get("/members/action/:action", org.MembersAction)
m.Get("/teams", org.Teams)
}, middleware.OrgAssignment(true))
}, context.OrgAssignment(true))
m.Group("/:org", func() {
m.Get("/teams/:team", org.TeamMembers)
m.Get("/teams/:team/repositories", org.TeamRepositories)
m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction)
m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction)
}, middleware.OrgAssignment(true, false, true))
}, context.OrgAssignment(true, false, true))
m.Group("/:org", func() {
m.Get("/teams/new", org.NewTeam)
@@ -384,7 +393,7 @@ func runWeb(ctx *cli.Context) {
})
m.Route("/invitations/new", "GET,POST", org.Invitation)
}, middleware.OrgAssignment(true, true))
}, context.OrgAssignment(true, true))
}, reqSignIn)
// ***** END: Organization *****
@@ -423,7 +432,7 @@ func runWeb(ctx *cli.Context) {
m.Get("", repo.GitHooks)
m.Combo("/:name").Get(repo.GitHooksEdit).
Post(repo.GitHooksEditPost)
}, middleware.GitHookService())
}, context.GitHookService())
})
m.Group("/keys", func() {
@@ -432,15 +441,15 @@ func runWeb(ctx *cli.Context) {
m.Post("/delete", repo.DeleteDeployKey)
})
}, func(ctx *middleware.Context) {
}, func(ctx *context.Context) {
ctx.Data["PageIsSettings"] = true
})
}, reqSignIn, middleware.RepoAssignment(), reqRepoAdmin, middleware.RepoRef())
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
m.Get("/:username/:reponame/action/:action", reqSignIn, middleware.RepoAssignment(), repo.Action)
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
m.Group("/:username/:reponame", func() {
m.Group("/issues", func() {
m.Combo("/new", repo.MustEnableIssues).Get(middleware.RepoRef(), repo.NewIssue).
m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
@@ -460,7 +469,7 @@ 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)
}, reqRepoWriter, middleware.RepoRef())
}, reqRepoWriter, context.RepoRef())
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
@@ -468,7 +477,7 @@ func runWeb(ctx *cli.Context) {
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Get("/:id/:action", repo.ChangeMilestonStatus)
m.Post("/delete", repo.DeleteMilestone)
}, reqRepoWriter, middleware.RepoRef())
}, reqRepoWriter, context.RepoRef())
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
@@ -476,11 +485,11 @@ func runWeb(ctx *cli.Context) {
m.Get("/edit/:tagname", repo.EditRelease)
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
m.Post("/delete", repo.DeleteRelease)
}, reqRepoWriter, middleware.RepoRef())
}, reqRepoWriter, context.RepoRef())
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
}, reqSignIn, middleware.RepoAssignment(), repo.MustBeNotBare)
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
m.Group("/:username/:reponame", func() {
m.Group("", func() {
@@ -489,7 +498,7 @@ func runWeb(ctx *cli.Context) {
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
m.Get("/milestones", repo.Milestones)
}, middleware.RepoRef())
}, context.RepoRef())
// m.Get("/branches", repo.Branches)
@@ -504,13 +513,13 @@ func runWeb(ctx *cli.Context) {
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
m.Post("/:page/delete", repo.DeleteWikiPagePost)
}, reqSignIn, reqRepoWriter)
}, repo.MustEnableWiki, middleware.RepoRef())
}, repo.MustEnableWiki, context.RepoRef())
m.Get("/archive/*", repo.Download)
m.Group("/pulls/:index", func() {
m.Get("/commits", middleware.RepoRef(), repo.ViewPullCommits)
m.Get("/files", middleware.RepoRef(), repo.ViewPullFiles)
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
m.Get("/files", context.RepoRef(), repo.ViewPullFiles)
m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
}, repo.MustAllowPulls)
@@ -518,22 +527,23 @@ func runWeb(ctx *cli.Context) {
m.Get("/src/*", repo.Home)
m.Get("/raw/*", repo.SingleDownload)
m.Get("/commits/*", repo.RefCommits)
m.Get("/commit/*", repo.Diff)
m.Get("/commit/:sha([a-z0-9]{40})$", repo.Diff)
m.Get("/forks", repo.Forks)
}, middleware.RepoRef())
}, context.RepoRef())
m.Get("/commit/:sha([a-z0-9]{40})\\.:ext(patch|diff)", repo.RawDiff)
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.CompareDiff)
}, ignSignIn, middleware.RepoAssignment(), repo.MustBeNotBare)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers)
}, ignSignIn, middleware.RepoAssignment(), middleware.RepoRef())
}, ignSignIn, context.RepoAssignment(), context.RepoRef())
m.Group("/:username", func() {
m.Group("/:reponame", func() {
m.Get("", repo.Home)
m.Get("\\.git$", repo.Home)
}, ignSignIn, middleware.RepoAssignment(true), middleware.RepoRef())
}, ignSignIn, context.RepoAssignment(true), context.RepoRef())
m.Group("/:reponame", func() {
m.Any("/*", ignSignInAndCsrf, repo.HTTP)
@@ -542,8 +552,12 @@ func runWeb(ctx *cli.Context) {
})
// ***** END: Repository *****
m.Group("/api", func() {
apiv1.RegisterRoutes(m)
}, ignSignIn)
// robots.txt
m.Get("/robots.txt", func(ctx *middleware.Context) {
m.Get("/robots.txt", func(ctx *context.Context) {
if setting.HasRobotsTxt {
ctx.ServeFileContent(path.Join(setting.CustomPath, "robots.txt"))
} else {
@@ -578,4 +592,6 @@ func runWeb(ctx *cli.Context) {
if err != nil {
log.Fatal(4, "Fail to start server: %v", err)
}
return nil
}

View File

@@ -12,7 +12,7 @@ RUN_MODE = dev
ROOT =
SCRIPT_TYPE = bash
; Default ANSI charset
ANSI_CHARSET =
ANSI_CHARSET =
; Force every new repository to be private
FORCE_PRIVATE = false
; Global maximum creation limit of repository per user, -1 means no limit
@@ -31,6 +31,8 @@ FEED_MAX_COMMIT_NUM = 5
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#ff5343`
; Max size of files to be displayed (defaults is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608
[ui.admin]
; Number of users that are showed in one page
@@ -53,12 +55,12 @@ CUSTOM_URL_SCHEMES =
PROTOCOL = http
DOMAIN = localhost
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
HTTP_ADDR =
HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000
; Local (DMZ) URL for Gogs workers (such as SSH update) accessing web service.
; In most cases you do not need to change the default value.
; Alter it only if your SSH server node is not the same as HTTP node.
LOCAL_ROOT_URL = http://localhost:%(HTTP_PORT)s/
LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
; Disable SSH feature when not available
DISABLE_SSH = false
; Whether use builtin SSH server or not.
@@ -70,7 +72,7 @@ SSH_PORT = 22
; Port number builtin SSH server listens on
SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH =
SSH_ROOT_PATH =
; Directory to create temporary files when test publick key using ssh-keygen,
; default is system temporary directory.
SSH_KEY_TEST_PATH =
@@ -93,6 +95,8 @@ KEY_FILE = custom/https/key.pem
; Upper level of template and static file path
; default is the path where Gogs is executed
STATIC_ROOT_PATH =
; Default path for App data
APP_DATA_PATH = data
; Application level GZIP support
ENABLE_GZIP = false
; Landing page for non-logged users, can be "home" or "explore"
@@ -165,24 +169,26 @@ SEND_BUFFER_LEN = 100
SUBJECT = %(APP_NAME)s
; Mail server
; Gmail: smtp.gmail.com:587
; QQ: smtp.qq.com:25
; QQ: smtp.qq.com:465
; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
HOST =
HOST =
; Disable HELO operation when hostname are different.
DISABLE_HELO =
DISABLE_HELO =
; Custom hostname for HELO operation, default is from system.
HELO_HOSTNAME =
HELO_HOSTNAME =
; Do not verify the certificate of the server. Only use this for self-signed certificates
SKIP_VERIFY =
SKIP_VERIFY =
; Use client certificate
USE_CERTIFICATE = false
CERT_FILE = custom/mailer/cert.pem
KEY_FILE = custom/mailer/key.pem
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
FROM =
; Mailer user name and password
USER =
PASSWD =
; Use text/html as alternative format of content
ENABLE_HTML_ALTERNATIVE = false
[cache]
; Either "memory", "redis", or "memcache", default is "memory"
@@ -195,7 +201,7 @@ INTERVAL = 60
HOST =
[session]
; Either "memory", "file", "redis" or "mysql", default is "memory"
; Either "memory", "file", or "redis", default is "memory"
PROVIDER = memory
; Provider config options
; memory: not have any config yet
@@ -316,7 +322,7 @@ SCHEDULE = @every 24h
TIMEOUT = 60s
; Arguments for command 'git fsck', e.g. "--unreachable --tags"
; see more on http://git-scm.com/docs/git-fsck/1.7.5
ARGS =
ARGS =
; Check repository statistics
[cron.check_repo_stats]
@@ -324,10 +330,15 @@ RUN_AT_START = true
SCHEDULE = @every 24h
[git]
MAX_GIT_DIFF_LINES = 10000
; Max number of lines allowed of a single file in diff view.
MAX_GIT_DIFF_LINES = 1000
; Max number of characters of a line allowed in diff view.
MAX_GIT_DIFF_LINE_CHARACTERS = 500
; Max number of files shown in diff view.
MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/1.7.5
GC_ARGS =
GC_ARGS =
; Operation timeout in seconds
[git.timeout]
@@ -336,15 +347,20 @@ MIRROR = 300
CLONE = 300
PULL = 300
[api]
; Max number of items will response in a page
MAX_RESPONSE_ITEMS = 50
[i18n]
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština
; Used for datetimepicker
[i18n.datelang]
en-US = en
zh-CN = zh
zh-HK = zh-TW
zh-TW = zh-TW
de-DE = de
fr-FR = fr
nl-NL = nl
@@ -357,6 +373,8 @@ pl-PL = pl
bg-BG = bg
it-IT = it
fi-FI = fi
tr-TR = tr
cs-CZ = cs-CZ
; Extension mapping to highlight class
; e.g. .toml=ini

View File

@@ -1,6 +1,5 @@
ISC License:
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
Copyright (c) 1995-2003 by Internet Software Consortium
Copyright (c) Year(s), Company or Person's Name
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

View File

@@ -14,6 +14,7 @@ Antoine GIRARD <sapk AT sapk DOT fr>
Arthur Aslanyan <arthur DOT e DOT aslanyan AT gmail DOT com>
Aurelien Darragon <aurelien DOT darragon AT gmail DOT com>
Barış Arda Yılmaz <ardayilmazgamer AT gmail DOT com>
Camille Baronnet <gogs AT camillebaronnet DOT fr>
Christoph Kisfeld <christoph DOT kisfeld AT gmail DOT com>
Cysioland
Daniel Speichert <daniel AT speichert DOT pl>
@@ -21,18 +22,20 @@ David Yzaguirre <dvdyzag AT gmail DOT com>
Dmitriy Nogay <me AT catwhocode DOT ga>
Enrico Testori hypertesto AT gmail DOT com
Ezequiel Gonzalez Rial <gonrial AT gmail DOT com>
Gabriel Dugny <gabriel DOT dugny AT gmail DOT com>
Gregor Santner <gdev AT live DOT de>
Halil Kaya <halil AT halilkaya DOT net>
Hamid Feizabadi <hamidfzm AT gmail DOT com>
Huimin Wang <wanghm2009 AT hotmail DOT co DOT jp>
ilko <kontact-mr.k AT outlook DOT com">
Ilya Makarov
Robin Hübner <profan AT prfn DOT se>
Jamie Mansfield <dev AT jamierocks DOT uk>
Jean THOMAS <contact AT tibounise DOT com>
Juraj Bubniak <contact AT jbub DOT eu>
Lafriks <lafriks AT gmail DOT com>
Lauri Ojansivu <x AT xet7 DOT org>
Luc Stepniewski <luc AT stepniewski DOT fr>
Luca Bozzo <luca AT bozzo DOT it>
Luca Kröger <l DOT kroeger01 AT gmail DOT com>
Marc Schiller <marc AT schiller DOT im>
Marvin Menzerath <github AT marvin-menzerath DOT de>
@@ -44,6 +47,9 @@ Muhammad Fawwaz Orabi <mfawwaz93 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>
Richard Bukovansky <richard DOT bukovansky @ gmail DOT com>
Robert Nuske <robert DOT nuske AT web DOT de>
Robin Hübner <profan AT prfn DOT se>
SeongJae Park <sj38 DOT park AT gmail DOT com>
Thomas Fanninger <gogs DOT thomas AT fanninger DOT at>
Tilmann Bach <tilmann AT outlook DOT com>
@@ -52,3 +58,4 @@ Vladimir Jigulin mogaika AT yandex DOT ru
Vladimir Vissoultchev <wqweto AT gmail DOT com>
YJSoft <yjsoft AT yjsoft DOT pe DOT kr>
Łukasz Jan Niemier <lukasz AT niemier DOT pl>
Pablo Saavedra <psaavedra AT igalia DOT com>

29
conf/locale/locale_bg-BG.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Задачи
cancel=Отказ
[search]
search=Търсене...
repository=Хранилище
user=Потребител
issue=Задача
code=Код
[install]
install=Инсталация
title=Стъпки за инсталиране при първоначално стартиране
@@ -140,6 +133,8 @@ issues.in_your_repos=Във Вашите хранилища
[explore]
repos=Хранилища
users=Потребители
search=Търсене
[auth]
create_new_account=Създай нов профил
@@ -162,6 +157,7 @@ reset_password=Нулиране на паролата
invalid_code=За съжаление Вашия код за потвърждение е изтекъл или е невалиден.
reset_password_helper=Щракнете тук, за да нулирате паролата си
password_too_short=Размерът на паролата не може да бъде по-малък от 6 знака.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Моля активирайте Вашия профил
@@ -224,8 +220,7 @@ org_still_own_repo=Тази организация все още притежа
target_branch_not_exist=Целевият клон не съществува.
[user]
change_avatar=Сменете Вашия аватар на gravatar.com
change_custom_avatar=Сменете Вашия аватар в настройките
change_avatar=Change your avatar
join_on=Регистриран
repositories=Хранилища
activity=Публична дейност
@@ -355,6 +350,8 @@ readme_helper=Изберете шаблон на readme
auto_init=Инициализиране на това хранилище с избраните файлове и шаблон
create_repo=Създай хранилище
default_branch=Клон по подразбиране
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Интервал на отразяване (часове)
mirror_address=Адрес на огледало
mirror_address_desc=Моля включете потребител и парола в адреса ако са нужни.
@@ -566,6 +563,10 @@ wiki.last_updated=Последна модификация на %s
settings=Настройки
settings.options=Опции
settings.collaboration=Сътрудничество
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Уеб-куки
settings.githooks=Git куки
settings.basic_settings=Основни настройки
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Посетителите ще бъдат пре
settings.issues_desc=Включва вградена система за проследяване на задачи
settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи
settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
settings.danger_zone=Опасна зона
@@ -602,9 +606,7 @@ settings.delete=Изтрий това хранилище
settings.delete_desc=След като изтриете хранилището, няма връщане назад. Моля, бъдете сигурни.
settings.delete_notices_1=- Тази операция <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие.
settings.delete_notices_2=- Тази операция ще изтрие всичко от това хранилище, включително Git данни, задачи, коментари и достъпа на сътрудници.
settings.delete_notices_fork_1=- Ако това хранилище е публично, всички негови разклонения ще останат независими след изтриването му.
settings.delete_notices_fork_2=- Ако това хранилище е частно, всички негови разклонения ще бъдат премахнати по време на изтриването.
settings.delete_notices_fork_3=- Ако желаете да запазите всички разклонения след изтриването му, първо направете хранилището публично.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Хранилището е изтрито успешно!
settings.update_settings_success=Настройките на хранилището са запазени успешно.
settings.transfer_owner=Нов притежател
@@ -688,6 +690,8 @@ diff.show_unified_view=Обединен изглед
diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда
diff.bin=BIN
diff.view_file=Целия файл
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Версии
release.new_release=Нова версия
@@ -915,6 +919,7 @@ auths.enabled=Активно
auths.updated=Последна модификация
auths.auth_type=Тип на удостоверяване
auths.auth_name=Име на удостоверяване
auths.security_protocol=Security Protocol
auths.domain=Домейн
auths.host=Сървър
auths.port=Порт

1108
conf/locale/locale_cs-CZ.ini Normal file

File diff suppressed because it is too large Load Diff

229
conf/locale/locale_de-DE.ini Executable file → Normal file
View File

@@ -1,6 +1,6 @@
app_desc=Ein einfacher, selbst gehosteter Git-Service
home=Home
home=Startseite
dashboard=Übersicht
explore=Erkunden
help=Hilfe
@@ -20,7 +20,7 @@ signed_in_as=Angemeldet als
username=Benutzername
email=E-Mail
password=Passwort
re_type=Passwort bestätigen
re_type=Erneut eingeben
captcha=Captcha
repository=Repository
@@ -29,7 +29,7 @@ mirror=Mirror
new_repo=Neues Repository
new_migrate=Neue Migration
new_mirror=Neuer Mirror
new_fork=Neuer Fork
new_fork=Neues Fork-Repository
new_org=Neue Organisation
manage_org=Organisationen verwalten
admin_panel=Administration
@@ -44,13 +44,6 @@ issues=Issues
cancel=Abbrechen
[search]
search=Suchen...
repository=Repository
user=Benutzer
issue=Issue
code=Code
[install]
install=Installation
title=Installationsschritte für den ersten Start
@@ -65,9 +58,9 @@ db_name=Datenbankname
db_helper=Bitte verwenden Sie in MySQL die InnoDB-Engine mit dem Zeichensatz utf8_general_ci.
ssl_mode=SSL-Modus
path=Pfad
sqlite_helper=Der Dateipfad zur SQLite3- oder TiDB-Datenbank. <br> Bitte benutzen Sie eine absoluten Pfad, wenn Gogs als Service gestartet wird.
sqlite_helper=Der Dateipfad zur SQLite3- oder TiDB-Datenbank. <br>Bitte verwenden Sie einen absoluten Pfad, wenn Gogs als Service gestartet wird.
err_empty_db_path=SQLite3 oder TiDB Datenbankpfad darf nicht leer sein.
err_invalid_tidb_name=Der TiDB Datenbankname darf kein "." und kein "-" enthalten.
err_invalid_tidb_name=Der TiDB Datenbankname darf nicht "." und "-" enthalten.
no_admin_and_disable_registration=Sie können die Registrierung nicht deaktivieren, ohne ein Administratorkonto zu erstellen.
err_empty_admin_password=Das Administrator-Passwort darf nicht leer sein.
@@ -77,7 +70,7 @@ app_name_helper=Hier den Namen der Organisation einfügen!
repo_path=Repository-Verzeichnis
repo_path_helper=Alle Git-Repositories werden in diesem Verzeichnis gespeichert.
run_user=Ausführender Benutzer
run_user_helper=Der Benutzer muss die Zugriffsberechtigung für das Repository Root-Verzeichnis haben und der ausführende Benutzer von Gogs sein.
run_user_helper=Der Benutzer muss die Zugriffsberechtigung für das Repository-Verzeichnis haben und der ausführende Benutzer von Gogs sein.
domain=Domain
domain_helper=Dies hat Auswirkung auf die SSH Klon-URLs.
ssh_port=SSH Port
@@ -110,7 +103,7 @@ enable_captcha_popup=Captcha-Eingabe bei der Registrierung erforderlich.
require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich.
require_sign_in_view_popup=Nur angemeldete Benutzer können auf alle Seiten zugreifen. Gäste sehen nur die Seiten Anmelden/Registrieren.
admin_setting_desc=Sie müssen jetzt noch kein Administrator-Konto anlegen. Der erste Benutzer ("ID=1") erhält automatisch Administrator-Rechte.
admin_title=Konto-Einstellungen für den Administrator
admin_title=Administrator Einstellungen
admin_name=Benutzername
admin_password=Passwort
confirm_password=Passwort bestätigen
@@ -118,7 +111,7 @@ admin_email=Administrator E-Mail
install_gogs=Gogs installieren
test_git_failed=Fehler beim Test des 'git' Kommandos: %v
sqlite3_not_available=Ihre Gogs-Version unterstützt SQLite3 nicht. Bitte laden Sie die offizielle binäre Version von %s herunter, NICHT die gobuild-Version.
invalid_db_setting=Datenbank-Einstellungen sind nicht korrekt: %v
invalid_db_setting=Datenbankeinstellungen sind nicht korrekt: %v
invalid_repo_path=Repository Verzeichnis ist ungültig: %v
run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
save_config_failed=Fehler beim Speichern der Konfiguration: %v
@@ -140,10 +133,12 @@ issues.in_your_repos=In Ihren Repositories
[explore]
repos=Repositories
users=Benutzer
search=Suche
[auth]
create_new_account=Neues Konto erstellen
register_hepler_msg=Sie haben bereits ein Konto? Jetzt anmelden!
register_hepler_msg=Haben Sie bereits ein Konto? Jetzt anmelden!
social_register_hepler_msg=Haben Sie bereits ein Konto? Jetzt verknüpfen!
disable_register_prompt=Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wenden Sie sich an den Administrator.
disable_register_mail=Es tut uns leid, die Bestätigung der Registrierungs-E-Mail wurde deaktiviert.
@@ -162,6 +157,7 @@ reset_password=Passwort zurücksetzen
invalid_code=Es tut uns leid, der Bestätigungscode ist abgelaufen oder ungültig.
reset_password_helper=Hier klicken, um das Passwort zurückzusetzen
password_too_short=Das Passwort muss mindenstens 6 Zeichen lang sein.
non_local_account=Nicht-lokale Konten können Passwörter nicht via Gogs ändern.
[mail]
activate_account=Bitte aktivieren Sie Ihr Konto
@@ -185,7 +181,7 @@ SSHTitle=SSH-Schlüsselname
HttpsUrl=HTTPS URL
PayloadUrl=Payload URL
TeamName=Teamname
AuthName=Authentifizierungsname
AuthName=Name der Autorisierung
AdminEmail=Administrator E-Mail
require_error=` darf nicht leer sein.`
@@ -213,7 +209,7 @@ enterred_invalid_password=Bitte achten Sie darauf, dass das eingegebene Passwort
user_not_exist=Angegebener Benutzer existiert nicht.
last_org_owner=Entfernen des letzten Mitglieds aus einem Eigentümer-Team ist nicht zulässig, da es immer mindestens einen Eigentümer je Organisation geben muss.
invalid_ssh_key=Leider sind wir nicht in der Lage, deinen SSH-Schlüssel zu überprüfen: %s
invalid_ssh_key=Leider sind wir nicht in der Lage, Ihren SSH-Schlüssel zu überprüfen: %s
unable_verify_ssh_key=Gogs kann Ihren SSH-Schlüssel nicht überprüfen, nimmt aber an, dass er gültig ist. Bitte stellen Sie dies selbst sicher.
auth_failed=Authentifizierung fehlgeschlagen: %v
@@ -224,14 +220,13 @@ org_still_own_repo=Diese Organisation besitzt noch Repositories. Diese müssen z
target_branch_not_exist=Ziel-Branch existiert nicht
[user]
change_avatar=Ändern Sie Ihr Profilbild auf gravatar.com
change_custom_avatar=Ändern Sie Ihr Profilbild in den Einstellungen
change_avatar=Ändern Sie ihr Profilbild
join_on=Beigetreten am
repositories=Repositories
activity=Öffentliche Aktivität
followers=Followers
followers=Folgende
starred=Favorisierte Repositories
following=Folgt
following=Folge ich
follow=Folgen
unfollow=Nicht mehr folgen
@@ -250,14 +245,14 @@ uid=Uid
public_profile=Öffentliches Profil
profile_desc=Ihre E-Mail-Adresse ist öffentlich einsehbar und dient dazu, Ihnen Benachrichtigungen bezüglich Ihres Kontos und Aktivitäten auf der Webseite zu schicken.
password_username_disabled=Nicht-lokalen Benutzern ist es nicht erlaubt, ihren Usernamen zu ändern.
password_username_disabled=Nicht-lokalen Benutzern ist es nicht erlaubt, ihren Benutzernamen zu ändern.
full_name=Vollständiger Name
website=Webseite
location=Standort
update_profile=Profil aktualisieren
update_profile_success=Ihr Profil wurde erfolgreich aktualisiert.
change_username=Benutzername geändert
change_username_prompt=Diese Änderung wirkt sich auf die Links zu Ihrem Benutzerkonto aus
change_username_prompt=Diese Änderung wirkt sich auf die Links zu Ihrem Benutzerkonto aus.
continue=Weiter
cancel=Abbrechen
@@ -266,7 +261,7 @@ choose_new_avatar=Neues Profilbild auswählen
update_avatar=Profilbildeinstellungen aktualisieren
delete_current_avatar=Aktuelles Profilbild löschen
uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild.
update_avatar_success=Ihre Avatar-Einstellung wurde aktualisiert.
update_avatar_success=Ihre Profilbild-Einstellung wurden erfolgreich aktualisiert.
change_password=Passwort ändern
old_password=Aktuelles Passwort
@@ -278,7 +273,7 @@ password_change_disabled=Nicht-lokalen Benutzern ist es nicht erlaubt, ihr Passw
emails=E-Mail-Adressen
manage_emails=E-Mail-Adressen verwalten
email_desc=Ihre primäre E-Mail-Adresse wird für Benachrichtigungen und andere Funktionen verwendet werden.
email_desc=Ihre primäre E-Mail-Adresse wird für Benachrichtigungen und andere Funktionen verwendet.
primary=Primär
primary_email=Als primäre Adresse verwenden
delete_email=Löschen
@@ -293,7 +288,7 @@ add_email_success=Ihre neue E-Mail-Adresse wurde erfolgreich hinzugefügt.
manage_ssh_keys=SSH-Schlüssel verwalten
add_key=Schlüssel hinzufügen
ssh_desc=Dies ist eine Liste aller SSH-Schlüssel, die Ihrem Konto zugeordnet sind. Bitte entfernen Sie alle Schlüssel, die Ihnen nicht bekannt sind.
ssh_helper=<strong>Sie brauchen Hilfe?</strong> Hier ist eine Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Lösen einfacher SSH-Probleme</a>.
ssh_helper=<strong>Brauchen Sie Hilfe?</strong> Hier ist eine Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Lösen einfacher SSH-Probleme</a>.
add_new_key=SSH-Schlüssel hinzufügen
ssh_key_been_used=Inhalt des öffentlichen Schlüssels wurde verwendet.
ssh_key_name_used=Ein öffentlicher Schlüssel mit diesem Namen existiert bereits.
@@ -315,7 +310,7 @@ social_desc=Dies ist eine Liste verknüpfter sozialer Konten. Bitte entfernen Si
unbind=Verknüpfung entfernen
unbind_success=Die Verknüpfung zum sozialen Konto wurde entfernt.
manage_access_token=Verwaltung persönlicher Zugangs-Tokens
manage_access_token=Verwaltung persönlicher Zugangs-Token
generate_new_token=Neuen Token erzeugen
tokens_desc=Die von Ihnen erzeugten Token können zum Zugriff auf die Gogs-API verwendet werden.
new_token_desc=Jeder Token erlaubt vollen Zugriff auf ihr Konto.
@@ -323,7 +318,7 @@ token_name=Token-Name
generate_token=Token generieren
generate_token_succees=Ihr Zugangs-Token wurde erfolgreich generiert! Stellen Sie sicher, dass Sie den Token kopiert haben, da Sie ihn später nicht mehr ansehen können!
delete_token=Löschen
access_token_deletion=Entfernung von persönlichen Token
access_token_deletion=Persönlichen Token entfernen
access_token_deletion_desc=Das Löschen dieses persönlichen Zugangs-Tokens wird alle zugehörigen Zugriffe der Anwendung entfernen. Möchten Sie fortfahren?
delete_token_success=Persönlicher Zugriffs-Token wurde erfolgreich entfernt! Vergessen Sie nicht Ihre Anwendung zu aktualisieren.
@@ -331,7 +326,7 @@ delete_account=Konto löschen
delete_prompt=Diese Aktion wird Ihr Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
confirm_delete_account=Löschvorgang bestätigen
delete_account_title=Konto löschen
delete_account_desc=Sie sind dabei dieses Konto dauerhaft zu löschen, möchten Sie wirklich fortfahren?
delete_account_desc=Sie sind dabei dieses Konto dauerhaft zu löschen. Möchten Sie wirklich fortfahren?
[repo]
owner=Besitzer
@@ -347,7 +342,7 @@ fork_from=Fork von
fork_visiblity_helper=Die Sichtbarkeit von geforkten Repositories ist nicht veränderbar.
repo_desc=Beschreibung
repo_lang=Sprache
repo_lang_helper=.gitignore Dateien auswählen
repo_lang_helper=Wählen Sie eine .gitignore-Datei aus
license=Lizenz
license_helper=Wählen Sie eine Lizenz aus
readme=Readme
@@ -355,6 +350,8 @@ readme_helper=Readme Vorlage auswählen
auto_init=Repository mit ausgewählten Dateien und Vorlagen initialisieren
create_repo=Repository erstellen
default_branch=Standard-Branch
mirror_prune=Entfernen
mirror_prune_desc=Entferne alle Verweise auf nicht mehr existierende entfernte Repositories
mirror_interval=Mirror-Intervall (in Stunden)
mirror_address=Mirror-Adresse
mirror_address_desc=Bitte die nötigen Zugangsdaten in die Adresse mit aufnehmen.
@@ -364,7 +361,7 @@ forks=Forks
form.reach_limit_of_creation=Der Besitzer hat die maximale Anzahl von %d erstellbaren Repositories erreicht.
form.name_reserved=Repository-Name '%s' ist reserviert.
form.name_pattern_not_allowed=Repositoryname der Form '%s' sind nicht erlaubt.
form.name_pattern_not_allowed=Repository-Namen der Form '%s' sind nicht erlaubt.
need_auth=Authorisierung benötigt
migrate_type=Migrationstyp
@@ -377,13 +374,13 @@ migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder i
migrate.failed=Fehler bei Migration: %v
mirror_from=Mirror von
forked_from=Geforkt von
forked_from=geforkt von
fork_from_self=Sie können kein Repository forken, das Ihnen gehört!
copy_link=Kopieren
copy_link_success=Kopiert!
copy_link_error=Drücken Sie ⌘-C oder Strg-C zum Kopieren
copied=Kopiert OK
unwatch=Nicht mehr beobachten
copied=Erfolgreich kopiert
unwatch=Beobachten beenden
watch=Beobachten
unstar=Favorit entfernen
star=Favorit hinzufügen
@@ -394,7 +391,7 @@ quick_guide=Kurzanleitung
clone_this_repo=Dieses Repository klonen
create_new_repo_command=Erstellen Sie ein neues Repository mittels der Kommandozeile
push_exist_repo=Bestehendes Repository von der Kommandozeile pushen
repo_is_empty=Das Repository ist leer, bitte kommen Sie später wieder!
repo_is_empty=Dieses Repository ist leer. Bitte kommen Sie später wieder!
code=Code
branch=Branch
@@ -408,9 +405,9 @@ labels=Label
milestones=Meilensteine
commits=Commits
releases=Releases
file_raw=Roh
file_raw=Originalformat
file_history=Verlauf
file_view_raw=Ansicht Roh
file_view_raw=Ansicht im Originalformat
file_permalink=Permalink
commits.commits=Commits
@@ -448,9 +445,9 @@ issues.filter_assignee=Zuständig
issues.filter_assginee_no_select=Keine Zuständigkeit ausgewählt
issues.filter_type=Typ
issues.filter_type.all_issues=Alle Issues
issues.filter_type.assigned_to_you=Ihnen zugewiesenen
issues.filter_type.assigned_to_you=Ihnen zugewiesen
issues.filter_type.created_by_you=Von Ihnen erstellt
issues.filter_type.mentioning_you=Erwähnen Sie
issues.filter_type.mentioning_you=Erwähnt Sie
issues.filter_sort=Sortieren
issues.filter_sort.latest=Neueste
issues.filter_sort.oldest=Älteste
@@ -474,7 +471,7 @@ issues.reopen_comment_issue=Kommentieren und wieder öffnen
issues.create_comment=Kommentieren
issues.closed_at=`hat <a id="%[1]s" href="#%[1]s">%[2]s</a> geschlossen`
issues.reopened_at=`hat <a id="%[1]s" href="#%[1]s">%[2]s</a> wieder geöffnet`
issues.commit_ref_at=`referenzierte dieses Issue aus einem Commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`hat dieses Issue <a id="%[1]s" href="#%[1]s">%[2]s</a> aus einem Commit referenziert`
issues.poster=Ersteller
issues.collaborator=Mitarbeiter
issues.owner=Besitzer
@@ -510,14 +507,14 @@ pulls.merged_title_desc=hat %[1]d Commits von <code>%[2]s</code> nach <code>%[3]
pulls.tab_conversation=Diskussion
pulls.tab_commits=Commits
pulls.tab_files=Geänderte Dateien
pulls.reopen_to_merge=Bitte diese Pull-Anforderung wiedereröffnen, um die Merge-Operation auszuführen.
pulls.reopen_to_merge=Bitte diesen Pull-Request wieder eröffnen, um die Merge-Operation auszuführen.
pulls.merged=Zusammengeführt
pulls.has_merged=Dieser Pull-Request wurde erfolgreich zusammengeführt!
pulls.data_broken=Die Daten dieses Pull-Requests sind defekt, da Fork-Informationen gelöscht wurden.
pulls.is_checking=Die Konfliktprüfung ist in Arbeit. Bitte aktualisieren Sie die Seite in wenigen Momenten.
pulls.is_checking=Die Konfliktprüfung läuft noch. Bitte aktualisieren Sie die Seite in wenigen Augenblicken.
pulls.can_auto_merge_desc=Dieser Pull-Request kann automatisch zusammengeführt werden.
pulls.cannot_auto_merge_desc=Dieser Pull-Request kann nicht automatisch zusammengeführt werden, da es Konflikte gibt.
pulls.cannot_auto_merge_helper=Bitte manuell zusammenführen um die Konflikte zu lösen.
pulls.cannot_auto_merge_helper=Bitte manuell zusammenführen, um die Konflikte zu lösen.
pulls.merge_pull_request=Pull-Request zusammenführen
pulls.open_unmerged_pull_exists=`Sie können diesen Pull-Request nicht wieder öffnen, da bereits ein offener Pull-Request (#%d) aus dem selben Repository mit den gleichen Merge-Informationen existiert und auf das Zusammenführen wartet.`
@@ -528,16 +525,16 @@ milestones.closed=Geschlossen %s
milestones.no_due_date=Kein Fälligkeitsdatum
milestones.open=Offen
milestones.close=Geschlossen
milestones.new_subheader=Erstellen Sie Meilensteine um Ihre Issues zu organisieren.
milestones.new_subheader=Erstellen Sie Meilensteine, um ihre Issues zu organisieren.
milestones.create=Meilenstein erstellen
milestones.title=Titel
milestones.desc=Beschreibung
milestones.due_date=Fälligkeitsdatum (optional)
milestones.clear=Entfernen
milestones.clear=Feld leeren
milestones.invalid_due_date_format=Format des Fälligkeitsdatums ist ungültig. Es muss das Format 'JJJJ-mm-dd' haben.
milestones.create_success=Meilenstein '%s' wurde erfolgreich erstellt!
milestones.edit=Meilenstein bearbeiten
milestones.edit_subheader=Verwenden Sie eine aussagekräftige Beschreibung um Missverständnisse zu vermeiden.
milestones.edit_subheader=Verwenden Sie eine aussagekräftige Beschreibung für Meilensteine, um Missverständnisse zu vermeiden.
milestones.cancel=Abbrechen
milestones.modify=Meilenstein ändern
milestones.edit_success=Änderungen des Meilensteins '%s' wurden erfolgreich gespeichert!
@@ -547,7 +544,7 @@ milestones.deletion_success=Meilenstein erfolgreich gelöscht!
wiki=Wiki
wiki.welcome=Willkommen im Wiki!
wiki.welcome_desc=Das Wiki ist der Ort, an dem Sie Ihr Projekt mit einer gemeinsam erstellten Dokumentation noch ansprechender gestalten können.
wiki.welcome_desc=Das Wiki ist der Ort, an dem Sie ihr Projekt gemeinsam dokumentieren und verbessern können.
wiki.create_first_page=Erstellen Sie die erste Seite
wiki.page=Seite
wiki.filter_page=Seite filtern
@@ -558,7 +555,7 @@ wiki.last_commit_info=%s hat diese Seite bearbeitet %s
wiki.edit_page_button=Bearbeiten
wiki.new_page_button=Neue Seite
wiki.delete_page_button=Seite löschen
wiki.delete_page_notice_1=Die Seite <code>"%s"</code> wird gelöscht.
wiki.delete_page_notice_1=Die Seite <code>"%s"</code> wird gelöscht. Bitte seien Sie vorsichtig.
wiki.page_already_exists=Eine Wiki-Seite mit dem gleichen Namen existiert bereits.
wiki.pages=Seiten
wiki.last_updated=Zuletzt aktualisiert %s
@@ -566,6 +563,10 @@ wiki.last_updated=Zuletzt aktualisiert %s
settings=Einstellungen
settings.options=Optionen
settings.collaboration=Zusammenarbeit
settings.collaboration.admin=Adminrechte
settings.collaboration.write=Schreibrechte
settings.collaboration.read=Leserechte
settings.collaboration.undefined=Nicht definiert
settings.hooks=Webhooks
settings.githooks=Git-Hooks
settings.basic_settings=Grundeinstellungen
@@ -573,13 +574,16 @@ 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=Erweiterte Einstellungen
settings.wiki_desc=Wiki aktivieren damit Benutzer Seiten anlegen können
settings.wiki_desc=Wiki aktivieren, damit Benutzer Seiten anlegen können
settings.use_external_wiki=Externes Wiki verwenden
settings.external_wiki_url=Externe Wiki URL
settings.external_wiki_url_desc=Besucher werden auf diese URL umgeleitet, wenn sie auf den Tab klicken.
settings.issues_desc=Eingebautes einfaches Issue-System verwenden
settings.use_external_issue_tracker=Externes Issue-System verwenden
settings.tracker_url_format=URL-Format des externen Issue-Systems
settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers:
settings.tracker_issue_style.numeric=Numerisch <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumerisch <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Sie können die Platzhalter <code>{user} {repo} {index}</code> für den Benutzernamen, den Namen des Repositories und die Issue-Nummer verwenden.
settings.pulls_desc=Pull-Requests aktivieren, um öffentliche Mitwirkung zu ermöglichen
settings.danger_zone=Gefahrenzone
@@ -590,21 +594,19 @@ settings.convert_notices_1=- Dieser Vorgang wandelt das Mirror-Repository in ein
settings.convert_confirm=Umwandlung bestätigen
settings.convert_succeed=Das Repository wurde erfolgreich in ein normales Repository umgewandelt.
settings.transfer=Besitz übertragen
settings.transfer_desc=Übertragen Sie dieses Repository auf einen anderen Benutzer oder eine Organisation in der Sie Admin-Rechte haben.
settings.transfer_desc=Dieses Repository auf einen anderen Benutzer bzw. eine Organisation in der Sie Admin-Rechte haben übertragen.
settings.transfer_notices_1=- Sie werden keinen Zugriff mehr haben, wenn der neue Besitzer ein individueller Benutzer ist.
settings.transfer_notices_2=- Sie werden weiterhin Zugriff haben, wenn der neue Besitzer eine Organisation ist und Sie einer der Besitzer sind.
settings.transfer_form_title=Bitte geben Sie die folgenden Informationen ein, um die Operation zu bestätigen:
settings.wiki_delete=Wiki-Daten löschen
settings.wiki_delete_desc=Das Löschen von Wiki Daten kann nicht rückgängig gemacht werden.
settings.wiki_delete_desc=Das Löschen von Wiki Daten kann nicht rückgängig gemacht werden. Bitte seien Sie vorsichtig.
settings.wiki_delete_notices_1=- Dies löscht und deaktiviert das Wiki für %s
settings.wiki_deletion_success=Repository Wiki Daten erfolgreich gelöscht.
settings.delete=Dieses Repository löschen
settings.delete_desc=Wenn dieses Repository gelöscht wurde, gibt es keinen Weg zurück. Bitte seien Sie vorsichtig.
settings.delete_notices_1=- Diese Operation kann <strong>NICHT</strong> rückgängig gemacht werden.
settings.delete_notices_2=- Die Operation wird alles, was mit diesem Git-Repository verbunden ist, dauerhaft löschen, inklusive der Daten, Issues, Kommentare und Zugriffsrechte von Mitarbeitern.
settings.delete_notices_fork_1=- Wenn dies ein öffentliches Repository ist, werden nach dem Löschen alle Forks unabhängig.
settings.delete_notices_fork_2=- Wenn dies ein privates Repository ist, werden gleichzeitig alle Forks entfernt.
settings.delete_notices_fork_3=Wenn alle Forks erhalten bleiben sollen, dann muss zuerst die Sichtbarkeit des Repositories auf öffentlich gesetzt werden.
settings.delete_notices_fork_1=- Nach dem Löschen werden alle Forks unabhängig.
settings.deletion_success=Repository wurde erfolgreich gelöscht!
settings.update_settings_success=Repository-Optionen aktualisiert.
settings.transfer_owner=Neuer Besitzer
@@ -612,7 +614,7 @@ settings.make_transfer=Transfer starten
settings.transfer_succeed=Das Repository wurde erfolgreich übertragen.
settings.confirm_delete=Löschen
settings.add_collaborator=Mitarbeiter hinzufügen
settings.add_collaborator_success=Neuer Mitarbeiter hinzugefügt.
settings.add_collaborator_success=Neuer Mitarbeiter wurde hinzugefügt.
settings.delete_collaborator=Löschen
settings.collaborator_deletion=Mitarbeiter löschen
settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Benutzer keinen Zugriff mehr als Mitarbeiter auf dieses Repository haben. Möchten Sie fortfahren?
@@ -621,12 +623,12 @@ settings.search_user_placeholder=Benutzer suchen...
settings.org_not_allowed_to_be_collaborator=Eine Organisation kann nicht als Mitarbeiter hinzugefügt werden.
settings.user_is_org_member=Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden.
settings.add_webhook=Webhook hinzufügen
settings.hooks_desc=Webhooks erlauben es Ihnen, externe Dienste zu informieren, wenn etwas bestimmtes in Ihrem Repository passiert. Gogs sendet dann einen POST-Request an alle angegebenen URLs. Erfahren Sie mehr in unserem <a target="_blank" href="%s">Webhooks Guide</a>.
settings.hooks_desc=Webhooks erlauben es Ihnen, externe Dienste zu informieren, wenn etwas Bestimmtes in Ihrem Repository passiert. Gogs sendet dann einen POST-Request an alle angegebenen URLs. Erfahren Sie mehr in unserem <a target="_blank" href="%s">Webhooks Guide</a>.
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=Auslieferung testen
settings.webhook.test_delivery_desc=Sendet ein imitiertes Push-Ereignis um die Webhook-Einstellungen zu testen
settings.webhook.test_delivery=Senden testen
settings.webhook.test_delivery_desc=Sendet ein simuliertes Push-Ereignis, um die Webhook-Einstellungen zu testen
settings.webhook.test_delivery_success=Test-Webhook wurde zur Auslieferungswarteschlange hinzugefügt. Es kann einige Sekunden dauern, bevor es in der Auslieferungshistorie erscheint.
settings.webhook.request=Anfrage
settings.webhook.response=Antwort
@@ -639,7 +641,7 @@ settings.githook_name=Hook-Name
settings.githook_content=Hook-Inhalt
settings.update_githook=Hook aktualisieren
settings.add_webhook_desc=Gogs sendet einen <code>POST</code>-Request an die unten stehende URL mit Details aller abonnierten Ereignisse. Sie können auch angeben, welches Datenformat Sie empfangen wollen (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). Mehr Informationen finden Sie im <a target="_blank" href="%s">Webhooks Guide</a>.
settings.payload_url=Payload-URL
settings.payload_url=Payload URL
settings.content_type=Inhaltstyp
settings.secret=Secret
settings.slack_username=Benutzername
@@ -667,7 +669,7 @@ settings.slack_domain=Domain
settings.slack_channel=Kanal
settings.deploy_keys=Deploy-Schlüssel
settings.add_deploy_key=Deploy-Schlüssel hinzufügen
settings.deploy_key_desc=Deploy-Schlüssel haben nur lesenden Zugriff. Sie sind nicht identisch mit dem persönlichen SSH-Schlüssel des Kontos.
settings.deploy_key_desc=Deploy-Schlüssel haben nur lesenden Zugriff. Sie sind nicht identisch mit dem SSH-Schlüssel des persönlichen Kontos.
settings.no_deploy_keys=Sie haben noch keine Deploy-Schlüssel hinzugefügt.
settings.title=Titel
settings.deploy_key_content=Inhalt
@@ -675,7 +677,7 @@ settings.key_been_used=Deploy-Schlüssel wurde verwendet.
settings.key_name_used=Ein Deploy-Schlüssel mit diesem Namen existiert bereits.
settings.add_key_success=Der Deploy-Schlüssel '%s' wurde erfolgreich hinzugefügt!
settings.deploy_key_deletion=Deploy-Schlüssel löschen
settings.deploy_key_deletion_desc=Nach dem Löschen dieses Deploy-Schlüssels werden entsprechende Zugriffe auf diese Repository nicht mehr möglich sein. Möchten Sie wirklich fortfahren?
settings.deploy_key_deletion_desc=Nach dem Löschen dieses Deploy-Schlüssels werden entsprechende Zugriffe auf dieses Repository nicht mehr möglich sein. Möchten Sie wirklich fortfahren?
settings.deploy_key_deletion_success=Deploy-Schlüssel wurde erfolgreich gelöscht!
diff.browse_source=Quellcode durchsuchen
@@ -685,9 +687,11 @@ diff.data_not_available=Keine Diff-Daten verfügbar.
diff.show_diff_stats=Diff-Statistik anzeigen
diff.show_split_view=Geteilte Ansicht
diff.show_unified_view=Gesamtansicht
diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen Zeilen</strong> und <strong>%d gelöschten Zeilen</strong>
diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen</strong> und <strong>%d gelöschten</strong> Zeilen
diff.bin=BIN
diff.view_file=Datei anzeigen
diff.file_supressed=Datei-Diff unterdrückt, da es zu groß ist
diff.too_many_files=Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.
release.releases=Releases
release.new_release=Neues Release
@@ -697,11 +701,11 @@ release.stable=Stabil
release.edit=bearbeiten
release.ahead=<strong>%d</strong> Commits zu %s seit diesem Release
release.source_code=Quelltext
release.new_subheader=Versionen des Projekts veröffentlichen.
release.new_subheader=Neue Version des Projekts veröffentlichen.
release.edit_subheader=Eine detaillierte Liste aller Änderungen verrät Benutzern, was verbessert wurde.
release.tag_name=Tag-Name
release.target=Ziel
release.tag_helper=Wählen Sie einen neuen Tag oder erstellen Sie einen Tag beim Veröffentlichen.
release.tag_helper=Wählen Sie einen Tag oder erstellen Sie einen neuen Tag beim Veröffentlichen.
release.title=Titel
release.content=Inhalt
release.write=Schreiben
@@ -791,7 +795,7 @@ teams.delete_team_title=Team löschen
teams.delete_team_desc=Mitglieder dieses Teams verlieren möglicherweise ihren Zugang zu einigen Repositories, wenn dieses Team gelöscht wird. Möchten Sie fortfahren?
teams.delete_team_success=Team gelöscht
teams.read_permission_desc=Dieses Team hat <strong>Lesezugriff</strong>: Mitglieder können Team-Repositories einsehen und klonen.
teams.write_permission_desc=Dieses Team hat <strong>Schreibzugriff</strong>: Mitglieder können Team-Repositories einsehen und hinein pushen.
teams.write_permission_desc=Dieses Team hat <strong>Schreibzugriff</strong>: Mitglieder können Team-Repositories einsehen und darauf pushen.
teams.admin_permission_desc=Dieses Team hat <strong>Adminzugriff</strong>: Mitglieder dieses Teams können pullen, pushen und Mitarbeiter zu Team-Repositories hinzufügen.
teams.repositories=Team-Repositories
teams.search_repo_placeholder=Repository durchsuchen...
@@ -806,7 +810,7 @@ organizations=Organisationen
repositories=Repositories
authentication=Authentifizierung
config=Konfiguration
notices=System-Mitteilungen
notices=Systemmitteilungen
monitor=Monitoring
first_page=Erste
last_page=Letzte
@@ -829,8 +833,8 @@ dashboard.delete_missing_repos=Alle Repository-Datensätze mit verlorenen gegang
dashboard.delete_missing_repos_success=Alle Repository-Datensätze, mit verlorenen Git-Dateien wurden erfolgreich gelöscht.
dashboard.git_gc_repos=Garbage Collection auf Repositories ausführen
dashboard.git_gc_repos_success=Garbage Collection wurde auf allen Repositories erfolgreich ausgeführt.
dashboard.resync_all_sshkeys=Datei '.ssh/authorized_keys' neu anlegen (Achtung: Keys, die nicht zu Gogs gehören gehen verloren)
dashboard.resync_all_sshkeys_success=Alle öffentlichen Keys wurden erfolgreich neu angelegt.
dashboard.resync_all_sshkeys=Datei '.ssh/authorized_keys' neu anlegen (Achtung: Schlüssel, die nicht zu Gogs gehören gehen verloren)
dashboard.resync_all_sshkeys_success=Alle öffentlichen Keys wurden erfolgreich neu geschrieben.
dashboard.resync_all_update_hooks=Alle Aktualisierungs-Hooks von Repositories neu anlegen (wird benötigt, wenn der angepasste Konfigurationspfad geändert wurde)
dashboard.resync_all_update_hooks_success=Die Hooks aller Repositories wurden erfolgreich neu angelegt.
dashboard.reinit_missing_repos=Alle Repository-Datensätze mit verloren gegangenen Git-Dateien neu initialisieren
@@ -861,7 +865,7 @@ dashboard.gc_metadata_obtained=Erhaltene GC-Metadata
dashboard.other_system_allocation_obtained=Andere erhaltene System-Allokationen
dashboard.next_gc_recycle=Nächster GC-Zyklus
dashboard.last_gc_time=Seit letztem GC-Zyklus
dashboard.total_gc_time=Gesamte GC-Zeit
dashboard.total_gc_time=Gesamte GC-Pause
dashboard.total_gc_pause=Gesamte GC-Pause
dashboard.last_gc_pause=Letzte GC-Pause
dashboard.gc_times=GC-Takt
@@ -872,13 +876,13 @@ users.name=Name
users.activated=Aktiviert
users.admin=Admin
users.repos=Repositories
users.created=Erzeugt
users.created=Erstellt am
users.send_register_notify=Bei der Registrierung eine Benachrichtigung an den Benutzer senden
users.new_success=Das neue Konto '%s' wurde erfolgreich erstellt.
users.edit=Bearbeiten
users.auth_source=Authentifizierungsquelle
users.local=Lokal
users.auth_login_name=Authentifizierung-Login-Name
users.auth_login_name=Anmeldename zur Authentifizierung
users.password_helper=Leer lassen um es unverändert zu lassen.
users.update_profile_success=Kontoprofil wurde erfolgreich aktualisiert.
users.edit_account=Konto bearbeiten
@@ -886,9 +890,9 @@ users.max_repo_creation=Maximale Anzahl erstellbarer Repositories
users.max_repo_creation_desc=(Auf -1 setzen, um das globale Standardlimit zu verwenden)
users.is_activated=Dieses Konto ist aktiviert
users.is_admin=Dieses Konto hat Administratorrechte
users.allow_git_hook=Dieses Konto ist berechtigt, Git-Hooks zu erstellen
users.allow_git_hook=Dieses Konto ist berechtigt Git-Hooks zu erstellen
users.allow_import_local=Dieses Konto ist berechtigt, lokale Repositories zu importieren
users.update_profile=Kontoprofil aktualisieren
users.update_profile=Konto aktualisieren
users.delete_account=Dieses Konto löschen
users.still_own_repo=Dieses Konto besitzt noch Repositories. Sie müssen diese zuerst löschen oder übertragen.
users.still_has_org=Dieses Konto ist noch Mitglied einer Organisation. Sie müssen die Organisation erst löschen oder verlassen.
@@ -915,6 +919,7 @@ auths.enabled=Aktiviert
auths.updated=Aktualisiert
auths.auth_type=Authentifizierungstyp
auths.auth_name=Authentifizierungsname
auths.security_protocol=Sicherheitsprotokoll
auths.domain=Domain
auths.host=Host
auths.port=Port
@@ -923,17 +928,17 @@ auths.bind_password=Passwort binden
auths.bind_password_helper=Achtung: Das Passwort wird im Klartext gespeichert. Benutzen Sie kein Konto mit hoher Berechtigungsstufe.
auths.user_base=Basis für Benutzersuche
auths.user_dn=Benutzer DN
auths.attribute_username=Attribute des Benutzernamens
auths.attribute_username_placeholder=Leer lassen, um den Wert aus dem Anmelde-Formular als Benutzername zu verwenden.
auths.attribute_name=Vorname Attribut
auths.attribute_surname=Nachname Attribut
auths.attribute_mail=E-Mail Attribut
auths.attribute_username=Attribut Benutzername
auths.attribute_username_placeholder=Leer lassen, um den Wert aus dem Anmeldeformular als Benutzernamen zu verwenden.
auths.attribute_name=Attribut Vorname
auths.attribute_surname=Attribut Nachname
auths.attribute_mail=Attribut E-Mail
auths.attributes_in_bind=Hole Attribute im Bind-Kontext
auths.filter=Benutzer Filter
auths.filter=Benutzerfilter
auths.admin_filter=Admin Filter
auths.ms_ad_sa=Ms Ad SA
auths.smtp_auth=SMTP Authentifizierung
auths.smtphost=SMTP-Host
auths.smtp_auth=SMTP-Authentifizierung
auths.smtphost=SMTP Host
auths.smtpport=SMTP-Port
auths.allowed_domains=Erlaubte Domains
auths.allowed_domains_helper=Leer lassen für keine Einschränkungen. Mehrere Domains können durch Komma "," getrennt werden.
@@ -943,17 +948,17 @@ auths.pam_service_name=PAM Dienstname
auths.enable_auto_register=Automatische Registrierung aktivieren
auths.tips=Tipps
auths.edit=Authentifizierungseinstellungen bearbeiten
auths.activated=Diese Authentifizierung ist aktiviert
auths.activated=Diese Authentifizierung ist aktiv
auths.new_success=Neue Authentifizierung '%s' wurde erfolgreich hinzugefügt.
auths.update_success=Die Authentifizierungseinstellungen wurden erfolgreich aktualisiert.
auths.update=Authentifizierungseinstellungen aktualisieren
auths.delete=Diese Authentifizierung löschen
auths.delete_auth_title=Löschen der Authentifizierung
auths.delete_auth_title=Authentifizierung löschen
auths.delete_auth_desc=Diese Authentifizierung wird gelöscht. Möchten Sie fortfahren?
auths.still_in_used=Diese Authentifizierung wird noch von einigen Benutzer verwendet. Bitte löschen Sie diese Benutzer oder ändern Sie deren Anmeldetyp.
auths.deletion_success=Authentifizierung wurde erfolgreich entfernt!
auths.still_in_used=Diese Authentifizierung wird noch von einigen Benutzern verwendet. Bitte löschen Sie diese Benutzer oder ändern Sie deren Anmeldetyp.
auths.deletion_success=Authentifizierung wurde erfolgreich gelöscht!
config.server_config=Server-Konfiguration
config.server_config=Serverkonfiguration
config.app_name=Anwendungsname
config.app_ver=Anwendungsversion
config.app_url=Anwendungs-URL
@@ -970,14 +975,14 @@ config.reverse_auth_user=Nutzer bei Reverse-Authentifizierung
config.ssh_config=SSH Konfiguration
config.ssh_enabled=Aktiviert
config.ssh_start_builtin_server=Builtin-Server starten
config.ssh_start_builtin_server=Eingebauten Server starten
config.ssh_domain=Domain
config.ssh_port=Port
config.ssh_listen_port=Listen Port
config.ssh_root_path=Verzeichnis
config.ssh_key_test_path=Schlüssel-Test-Pfad
config.ssh_keygen_path=Keygen ('ssh-Keygen') Pfad
config.ssh_minimum_key_size_check=Prüfe minimale Schlüssellänge
config.ssh_keygen_path=Keygen ('ssh-keygen') Pfad
config.ssh_minimum_key_size_check=Prüfung der Mindestschlüssellänge
config.ssh_minimum_key_sizes=Minimale Schlüssellängen
config.db_config=Datenbankkonfiguration
@@ -987,9 +992,9 @@ config.db_name=Name
config.db_user=Benutzer
config.db_ssl_mode=SSL-Modus
config.db_ssl_mode_helper=(nur für "postgres")
config.db_path=Pfad
config.db_path=Verzeichnis
config.db_path_helper=(für "sqlite3" und "tidb")
config.service_config=Service-Einstellungen
config.service_config=Service-Konfiguration
config.register_email_confirm=E-Mail-Bestätigung bei Registrierung
config.disable_register=Registrierung deaktivieren
config.show_registration_button=Schaltfläche Registrieren anzeigen
@@ -999,11 +1004,11 @@ config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
config.enable_captcha=Captcha aktivieren
config.active_code_lives=Aktivierungscode Lebensdauer
config.reset_password_code_lives=Passwortcode Lebensdauer
config.webhook_config=Webhook-Einstellungen
config.webhook_config=Webhook-Konfiguration
config.queue_length=Warteschlangenlänge
config.deliver_timeout=Zeitlimit für Zustellung
config.skip_tls_verify=TLS verifikation überspringen
config.mailer_config=Mailer-Einstellungen
config.mailer_config=Mailer-Konfiguration
config.mailer_enabled=Aktiviert
config.mailer_disable_helo=HELO Deaktivieren
config.mailer_name=Name
@@ -1012,25 +1017,25 @@ config.mailer_user=Benutzer
config.send_test_mail=Test-E-Mail senden
config.test_mail_failed=Das Senden der Test-E-Mail an '%s': %v ist fehlgeschlagen
config.test_mail_sent=Test-E-Mail wurde an '%s' gesendet.
config.oauth_config=OAuth-Einstellungen
config.oauth_config=OAuth-Konfiguration
config.oauth_enabled=Aktiviert
config.cache_config=Cache-Einstellungen
config.cache_config=Cache-Konfiguration
config.cache_adapter=Cache-Adapter
config.cache_interval=Cache-Intervall
config.cache_conn=Cache-Anbindung
config.session_config=Session-Einstellungen
config.session_config=Session-Konfiguration
config.session_provider=Session-Provider
config.provider_config=Provider-Einstellungen
config.cookie_name=Cookie-Name
config.enable_set_cookie=Cookies verwenden
config.gc_interval_time=GC-Intervallzeit
config.gc_interval_time=GC-Intervall
config.session_life_time=Session-Lebensdauer
config.https_only=Nur HTTPS
config.cookie_life_time=Cookie-Lebensdauer
config.picture_config=Bildeinstellungen
config.picture_config=Konfiguration der Profilbilder
config.picture_service=Bildservice
config.disable_gravatar=Gravatar deaktivieren
config.log_config=Log-Einstellungen
config.log_config=Konfiguration des Loggings
config.log_mode=Log-Modus
monitor.cron=Cron-Tasks
@@ -1044,7 +1049,7 @@ monitor.desc=Beschreibung
monitor.start=Startzeit
monitor.execute_time=Ausführungszeit
notices.system_notice_list=System-Mitteilungen
notices.system_notice_list=Systemmitteilungen
notices.view_detail_header=Mitteilungsdetails ansehen
notices.actions=Aktionen
notices.select_all=Alles auswählen
@@ -1059,17 +1064,17 @@ notices.op=Op.
notices.delete_success=Systemmitteilungen wurden erfolgreich gelöscht.
[action]
create_repo=hat Repository <a href="%s">%s</a> erstellt
create_repo=hat das Repository <a href="%s">%s</a> erstellt
rename_repo=hat das Repository von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a> umbenannt
commit_repo=hat nach <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> gepusht
create_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> eröffnet`
close_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> geschlossen`
reopen_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> wieder geöffnet`
create_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> erstellt`
close_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> geschlossen`
reopen_pull_request=`hat Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> wieder geöffnet`
comment_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert`
merge_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> zuammengeführt`
commit_repo=hat auf <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> gepusht
create_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> geöffnet`
close_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> geschlossen`
reopen_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> wieder geöffnet`
create_pull_request=`hat Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> erstellt`
close_pull_request=`hat Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> geschlossen`
reopen_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> wieder geöffnet`
comment_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert`
merge_pull_request=`hat Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> zuammengeführt`
transfer_repo=hat Repository <code>%s</code> transferiert an <a href="%s">%s</a>
push_tag=hat Tag <a href="%s/src/%s">%[2]s</a> auf <a href="%[1]s">%[3]s</a> gepusht
compare_commits=Zeige Vergleich für diese %d Commits
@@ -1096,7 +1101,7 @@ raw_seconds=Sekunden
raw_minutes=Minuten
[dropzone]
default_message=Für den Upload klicken oder die Datei hier ablegen.
default_message=Zum Hochladen hier klicken oder Datei hier ablegen.
invalid_input_type=Dateien dieses Dateityps können nicht hochgeladen werden.
file_too_big=Dateigröße ({{filesize}} MB) überschreitet die Maximalgröße ({{maxFilesize}} MB).
remove_file=Datei entfernen

View File

@@ -44,13 +44,6 @@ issues = Issues
cancel = Cancel
[search]
search = Search...
repository = Repository
user = User
issue = Issue
code = Code
[install]
install = Installation
title = Install Steps For First-time Run
@@ -140,6 +133,8 @@ issues.in_your_repos = In your repositories
[explore]
repos = Repositories
users = Users
search = Search
[auth]
create_new_account = Create New Account
@@ -153,6 +148,8 @@ forget_password = Forgot password?
sign_up_now = Need an account? Sign up now.
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
prohibit_login = Login Prohibited
prohibit_login_desc = Your account is prohibited to login, please contact site admin.
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 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
@@ -162,6 +159,7 @@ 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
password_too_short = Password length cannot be less then 6.
non_local_account = Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account = Please activate your account
@@ -224,8 +222,7 @@ org_still_own_repo = This organization still has ownership of repositories, you
target_branch_not_exist = Target branch does not exist.
[user]
change_avatar = Change your avatar at gravatar.com
change_custom_avatar = Change your avatar in settings
change_avatar = Change your avatar
join_on = Joined on
repositories = Repositories
activity = Public Activity
@@ -355,6 +352,8 @@ readme_helper = Select a readme template
auto_init = Initialize this repository with selected files and template
create_repo = Create Repository
default_branch = Default Branch
mirror_prune = Prune
mirror_prune_desc = Remove any remote-tracking references that no longer exist on the remote
mirror_interval = Mirror Interval (hour)
mirror_address = Mirror Address
mirror_address_desc = Please include necessary user credentials in the address.
@@ -412,6 +411,7 @@ file_raw = Raw
file_history = History
file_view_raw = View Raw
file_permalink = Permalink
file_too_large = This file is too large to be shown
commits.commits = Commits
commits.search = Search commits
@@ -566,6 +566,10 @@ wiki.last_updated = Last updated %s
settings = Settings
settings.options = Options
settings.collaboration = Collaboration
settings.collaboration.admin = Admin
settings.collaboration.write = Write
settings.collaboration.read = Read
settings.collaboration.undefined = Undefined
settings.hooks = Webhooks
settings.githooks = Git Hooks
settings.basic_settings = Basic Settings
@@ -580,6 +584,9 @@ settings.external_wiki_url_desc = Visitors will be redirected to URL when they c
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_issue_style = External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric = Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric = Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
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
@@ -602,9 +609,7 @@ settings.delete = Delete This Repository
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
settings.delete_notices_1 = - This operation <strong>CANNOT</strong> be undone.
settings.delete_notices_2 = - This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
settings.delete_notices_fork_1 = - If this repository is public, all forks will become 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.delete_notices_fork_1 = - All forks will become independent after deletion.
settings.deletion_success = Repository has been deleted successfully!
settings.update_settings_success = Repository options has been updated successfully.
settings.transfer_owner = New Owner
@@ -688,6 +693,8 @@ diff.show_unified_view = Unified View
diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</strong> and <strong>%d deletions</strong>
diff.bin = BIN
diff.view_file = View File
diff.file_suppressed = File diff suppressed because it is too large
diff.too_many_files = Some files were not shown because too many files changed in this diff
release.releases = Releases
release.new_release = New Release
@@ -885,6 +892,7 @@ users.edit_account = Edit Account
users.max_repo_creation = Maximum Repository Creation Limit
users.max_repo_creation_desc = (Set -1 to use global default limit)
users.is_activated = This account is activated
users.prohibit_login = This account is prohibited to login
users.is_admin = This account has administrator permissions
users.allow_git_hook = This account has permissions to create Git hooks
users.allow_import_local = This account has permissions to import local repositories
@@ -915,6 +923,7 @@ auths.enabled = Enabled
auths.updated = Updated
auths.auth_type = Authentication Type
auths.auth_name = Authentication Name
auths.security_protocol = Security Protocol
auths.domain = Domain
auths.host = Host
auths.port = Port
@@ -943,7 +952,7 @@ auths.pam_service_name = PAM Service Name
auths.enable_auto_register = Enable Auto Registration
auths.tips = Tips
auths.edit = Edit Authentication Setting
auths.activated = This authentication is activate
auths.activated = This authentication is activated
auths.new_success = New authentication '%s' has been added successfully.
auths.update_success = Authentication setting has been updated successfully.
auths.update = Update Authentication Setting

55
conf/locale/locale_es-ES.ini Executable file → Normal file
View File

@@ -6,7 +6,7 @@ explore=Explorar
help=Ayuda
sign_in=Iniciar sesión
sign_out=Cerrar sesión
sign_up=Suscripción
sign_up=Registro
register=Registro
website=Página web
version=Versión
@@ -44,17 +44,10 @@ issues=Incidencias
cancel=Cancelar
[search]
search=Buscar...
repository=Repositorio
user=Usuario
issue=Incidencia
code=Código
[install]
install=Instalación
title=Pasos de la instalación por primera vez
docker_helper=Si está ejecutando Gogs usando Docker, por favor lea <a target="_blank" href="%s"> estas pautas</a> antes de cambiar nada en esta página!
docker_helper=Si está ejecutando Gogs usando Docker, ¡por favor lea <a target="_blank" href="%s"> estas pautas</a> antes de cambiar nada en esta página!
requite_db_desc=Gogs requiere una base de datos MySQL, PostgreSQL, SQLite3 o TiDB.
db_title=Configuración de base de datos
db_type=Tipo de base de datos
@@ -72,7 +65,7 @@ no_admin_and_disable_registration=No puede deshabilitar el registro sin crear un
err_empty_admin_password=La contraseña de administrador no puede estar vacía.
general_title=Configuración General de Gogs
app_name=Nombre de la Aplicación
app_name=Nombre de la aplicación
app_name_helper=Pon aquí el nombre de tu organización, ¡alto y claro!
repo_path=Ruta del repositorio de Raiz (Root)
repo_path_helper=Todos los repositorios remotos de Git se guardarán en este directorio.
@@ -140,9 +133,11 @@ issues.in_your_repos=En tus repositorios
[explore]
repos=Repositorios
users=Usuarios
search=Buscar
[auth]
create_new_account=Crear una Nueva Cuenta
create_new_account=Crear una nueva cuenta
register_hepler_msg=¿Ya tienes una cuenta? ¡Inicia sesión!
social_register_hepler_msg=¿Ya tienes una cuenta? ¡Enlázala!
disable_register_prompt=Lo sentimos, el registro está deshabilitado. Por favor, contacta con el administrador del sitio.
@@ -162,6 +157,7 @@ reset_password=Restablecer su contraseña
invalid_code=Lo sentimos, su código de confirmación ha expirado o no es valido.
reset_password_helper=Haga Clic aquí para restablecer su contraseña
password_too_short=La longitud de la contraseña no puede ser menor a 6.
non_local_account=Cuentas que no son locales no pueden cambiar las contraseñas a través de Gogs.
[mail]
activate_account=Por favor, active su cuenta
@@ -224,9 +220,8 @@ org_still_own_repo=Esta organización es dueña de uno o más repositorios, tien
target_branch_not_exist=La rama de destino no existe
[user]
change_avatar=Cambia tu avatar en gravatar.com
change_custom_avatar=Cambia tu avatar en la configuración
join_on=Registrado en
change_avatar=Change your avatar
join_on=Registrado el
repositories=Repositorios
activity=Actividad pública
followers=Seguidores
@@ -346,7 +341,7 @@ fork_repo=Hacer Fork del repositorio
fork_from=Crear un Fork desde
fork_visiblity_helper=No es posible cambiar la visibilidad de un Fork
repo_desc=Descripción
repo_lang=Lenguaje
repo_lang=Idioma
repo_lang_helper=Seleccione archivo .gitignore
license=Licencia
license_helper=Selecciona un fichero de licencia
@@ -355,6 +350,8 @@ readme_helper=Seleccione una plantilla de archivo readme
auto_init=Inicializar los archivos seleccionados y plantillas de este repositorio
create_repo=Crear repositorio
default_branch=Rama por defecto
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Intervalo de la réplica (en horas)
mirror_address=Dirección de la réplica
mirror_address_desc=Por favor, incluya las credenciales de usuario necesarias en la dirección.
@@ -378,18 +375,18 @@ migrate.failed=Migración fallida: %v
mirror_from=espejo de
forked_from=forked de
fork_from_self=Eres el propietario del repositorio, ¡no puedes hacer fork!
fork_from_self=¡No puedes crear un fork de un repositorio que ya es tuyo!
copy_link=Copiar
copy_link_success=¡Copiado!
copy_link_error=Presione ⌘ + C o Ctrl-C para copiar
copied=Copiado correctamente
unwatch=Dejar de vigilar
watch=Vigilar
watch=Seguir
unstar=Eliminar destacado
star=Destacar
fork=Fork
no_desc=Sin Descripción
no_desc=Sin descripción
quick_guide=Guía Rápida
clone_this_repo=Clonar este repositorio
create_new_repo_command=Crear un nuevo repositorio desde línea de comandos
@@ -496,7 +493,7 @@ issues.label_deletion_success=Etiqueta borrada con éxito!
issues.num_participants=%d participantes
pulls.new=Nuevo Pull Request
pulls.compare_changes=Comparar Cambios
pulls.compare_changes=Comparar cambios
pulls.compare_changes_desc=Comparar dos ramas y generar un pull request con las diferencias.
pulls.compare_base=base
pulls.compare_compare=comparar con
@@ -566,6 +563,10 @@ wiki.last_updated=Última actualización %s
settings=Configuración
settings.options=Opciones
settings.collaboration=Colaboración
settings.collaboration.admin=Administrador
settings.collaboration.write=Escritura
settings.collaboration.read=Lectura
settings.collaboration.undefined=Indefinido
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Configuración Básica
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Los visitantes serán redireccionados a la URL c
settings.issues_desc=Habilitar tracker ligero de incidencias
settings.use_external_issue_tracker=Usar tracker externo de incidencias
settings.tracker_url_format=Formato URL del tracker de incidencias externo
settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias:
settings.tracker_issue_style.numeric=Numérico <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alfanumérico <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Puedes usar las plantillas <code>{user} {repo} {index}</code> para el nombre de usuario, nombre del repositorio e índice de la incidencia.
settings.pulls_desc=Habilitar Pull Requests para aceptar contribuciones públicas
settings.danger_zone=Zona de Peligro
@@ -602,9 +606,7 @@ settings.delete=Eliminar este repositorio
settings.delete_desc=Una vez has eliminado un repositorio, no hay vuelta atrás. Por favor, asegúrate de que es lo que quieres.
settings.delete_notices_1=- Esta operación <strong>NO PUEDE</strong> revertirse.
settings.delete_notices_2=- Esta operación eliminará de manera permanente todo el contenido de este repositorio, incluyendo los datos de git, las incidencias, los comentarios y los permisos de acceso de los colaboradores.
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.delete_notices_fork_1=- Todos los forks se convertirán en independientes tras el borrado.
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
@@ -682,12 +684,14 @@ diff.browse_source=Explorar el Código
diff.parent=padre
diff.commit=commit
diff.data_not_available=Los datos del Diff no están disponibles.
diff.show_diff_stats=Mostrar Estadísticas de Diff
diff.show_diff_stats=Mostrar estadísticas de diff
diff.show_split_view=Dividir vista
diff.show_unified_view=Unificar vista
diff.stats_desc=Se han <strong>modificado %d ficheros</strong> con <strong>%d adiciones</strong> y <strong>%d borrados</strong>
diff.bin=BIN
diff.view_file=Ver Fichero
diff.view_file=Ver fichero
diff.file_supressed=El diff del archivo ha sido suprimido porque es demasiado grande
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Releases
release.new_release=Nueva Release
@@ -705,7 +709,7 @@ release.tag_helper=Escoge una etiqueta o crea una nueva al publicar.
release.title=Título
release.content=Contenido
release.write=Escribir
release.preview=Vista Previa
release.preview=Vista previa
release.loading=Cargando...
release.prerelease_desc=Esta es una pre-release
release.prerelease_helper=Esta release está marcada como no apta para producción.
@@ -915,6 +919,7 @@ auths.enabled=Activo
auths.updated=Actualizado
auths.auth_type=Tipo de autenticación
auths.auth_name=Nombre de autenticación
auths.security_protocol=Protocolo de seguridad
auths.domain=Dominio
auths.host=Host
auths.port=Puerto

29
conf/locale/locale_fi-FI.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Ongelmat
cancel=Peruuta
[search]
search=Etsi...
repository=Repo
user=Käyttäjä
issue=Ongelma
code=Koodi
[install]
install=Asennus
title=Asennusvaiheet ottaessa ensi kertaa käyttöön
@@ -140,6 +133,8 @@ issues.in_your_repos=Repoissasi
[explore]
repos=Repot
users=Users
search=Search
[auth]
create_new_account=Luo uusi tili
@@ -162,6 +157,7 @@ reset_password=Nollaa salasanasi
invalid_code=Sori, varmistuskoodisi on vanhentunut tai väärä.
reset_password_helper=Klikkaa tästä nollataksesi salasanasi
password_too_short=Salasanan pituus ei voi olla vähemmän kuin 6 merkkiä.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Ole hyvä ja aktivoi tilisi
@@ -224,8 +220,7 @@ org_still_own_repo=Tällä organisaatiolla on yhä omistajuus repoon, sinun täy
target_branch_not_exist=Kohde branchia ei ole olemassa.
[user]
change_avatar=Vaihda avatarisi osoitteeessa gravatar.com
change_custom_avatar=Vaihda avatar asetuksissa
change_avatar=Change your avatar
join_on=Liitytty
repositories=Repot
activity=Julkinen toiminta
@@ -355,6 +350,8 @@ readme_helper=Valitse Lueminut-malli
auto_init=Alusta tämä repo valituilla tiedostoilla ja mallilla
create_repo=Luo repo
default_branch=Oletus branch
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Peili aikaväli (tuntia)
mirror_address=Peili osoite
mirror_address_desc=Ole hyvä ja liitä osoitteeseen tarvittavat käyttäjätunnukset.
@@ -566,6 +563,10 @@ wiki.last_updated=Viimeksi päivitetty: %s
settings=Asetukset
settings.options=Valinnaiset
settings.collaboration=Yhteistyö
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Webkoukut
settings.githooks=Git koukut
settings.basic_settings=Perusasetukset
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Vierailijat uudelleenohjataan URL-osoitteeseen k
settings.issues_desc=Ota käyttöön sisäänrakennettu kevyt vikaseuranta
settings.use_external_issue_tracker=Käytä ulkoista vikaseurantaa
settings.tracker_url_format=Ulkoisen vikaseurannan URL muoto
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Voit käyttää paikkamerkkiä <code>{user} {repo} {index}</code> käyttäjänimelle, reponimelle ja vikanumerolle.
settings.pulls_desc=Ota käyttöön pull-pyynnöt salliaksesi julkiset koodilahjoitukset
settings.danger_zone=Vaaravyöhyke
@@ -602,9 +606,7 @@ settings.delete=Poista tämä repo
settings.delete_desc=Huomio, kun kerran poistat repon, niin ei ole paluuta. Varmista että haluat todella tehdä tämän.
settings.delete_notices_1=- Tätä toimintoa <strong>EI VOI</strong> peruuttaa myöhemmin.
settings.delete_notices_2=- Tämä toiminto poistaa pysyvästi kaikki tästä reposta, mukaanlukien Git tiedot, ongelmat, kommentit ja yhteistyökumppanien pääsyoikeudet.
settings.delete_notices_fork_1=- Jos tämä repo on julkinen, kaikki forkit tulevat itsenäiseksi poiston jälkeen.
settings.delete_notices_fork_2=- Jos tämä repo on yksityinen, kaikki forkit poistetaan samalla.
settings.delete_notices_fork_3=- Jos haluat pitää kaikki forkit poistamisen jälkeen, ole hyvä ja muuta tämän repon näkyvyys julkiseksi ensin.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Repo on poistettu onnistuneesti!
settings.update_settings_success=Repom asetukset on päivitetty onnistuneesti.
settings.transfer_owner=Uusi omistaja
@@ -688,6 +690,8 @@ diff.show_unified_view=Yhdistetty näkymä
diff.stats_desc=<strong>%d muutettua tiedostoa</strong> jossa <strong>%d lisäystä</strong> ja <strong>%d poistoa</strong>
diff.bin=BIN
diff.view_file=Näytä tiedosto
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Julkaisut
release.new_release=Uusi julkaisu
@@ -915,6 +919,7 @@ auths.enabled=Käytössä
auths.updated=Päivitetty
auths.auth_type=Todennustyyppi
auths.auth_name=Todennusnimi
auths.security_protocol=Security Protocol
auths.domain=Verkkotunnus
auths.host=Isäntä
auths.port=Portti

117
conf/locale/locale_fr-FR.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Tickets
cancel=Annuler
[search]
search=Rechercher...
repository=Dépôt
user=Utilisateur
issue=Ticket
code=Code
[install]
install=Installation
title=Instructions pour la première exécution
@@ -64,7 +57,7 @@ password=Mot de passe
db_name=Nom de base de données
db_helper=Veuillez utiliser le moteur INNODB avec le jeu de caractères utf8_general_ci pour MySQL.
ssl_mode=Mode SSL
path=Chemin
path=Emplacement
sqlite_helper=Le chemin du fichier de base de données SQLite3 ou TiDB. <br>Utilisez un chemin absolu lorsque vous démarrez en tant que service.
err_empty_db_path=Le chemin de la base de données SQLite3 ou TiDB ne peut être vide.
err_invalid_tidb_name=Le nom de la base de données TiDB ne peut contenir les caractères "." ou "-".
@@ -90,7 +83,7 @@ log_root_path=Chemin des fichiers log
log_root_path_helper=Répertoire d'écriture des fichiers de log.
optional_title=Paramètres facultatifs
email_title=Paramètres du Service de Messagerie
email_title=Paramètres du service de messagerie
smtp_host=Hôte SMTP
smtp_from=Provenant de
smtp_from_helper=Adresse de l'expéditeur, RFC 5322. Soit une adresse courriel simple, soit au format "Nom" <email@example.com>.
@@ -107,7 +100,7 @@ disable_registration=Désactiver le formulaire d'inscription
disable_registration_popup=Désactiver le formulaire d'inscription, seuls les administrateurs peuvent créer des comptes.
enable_captcha=Activez le Captcha
enable_captcha_popup=Demande la validation Captcha pour l'auto-enregistrement de l'utilisateur.
require_sign_in_view=Demander une connexion pour afficher des pages
require_sign_in_view=Exiger l'identification pour afficher les pages
require_sign_in_view_popup=Seules les personnes connectées peuvent voir les pages. Les visiteurs anonymes ne pourront voir que les pages de connexion/enregistrement.
admin_setting_desc=Vous n'avez pas besoin de créer un compte administrateur. L'utilisateur ayant l'ID = 1 aura automatiquement accès à l'administration.
admin_title=Paramètres du compte administrateur
@@ -127,19 +120,21 @@ install_success=Bienvenue ! Nous sommes heureux que vous ayez choisi Gogs, amuse
invalid_log_root_path=Le chemin principal des fichiers logs est invalide: %v
[home]
uname_holder=Nom d'Utilisateur ou E-mail
uname_holder=Nom d'utilisateur ou e-mail
password_holder=Mot de passe
switch_dashboard_context=Basculer le Contexte du Tableau de Bord
my_repos=Mes dépôts
collaborative_repos=Dépôts collaboratifs
my_orgs=Mes Organisations
my_mirrors=Mes Miroirs
my_orgs=Mes organisations
my_mirrors=Mes miroirs
view_home=Voir %s
issues.in_your_repos=Dans vos dépôts
[explore]
repos=Dépôts
users=Utilisateurs
search=Rechercher
[auth]
create_new_account=Créer un nouveau compte
@@ -148,11 +143,11 @@ social_register_hepler_msg=Déjà enregistré ? Associez-le !
disable_register_prompt=Désolé, les enregistrements ont été désactivés. Veuillez contacter l'administrateur du site.
disable_register_mail=Désolé, la Confirmation par Mail des Enregistrements a été désactivée.
remember_me=Se souvenir de moi
forgot_password=Mot de Passe oublié
forget_password=Mot de Passe oublié ?
forgot_password=Mot de passe oublié
forget_password=Mot de passe oublié ?
sign_up_now=Pas de compte ? Inscrivez-vous maintenant.
confirmation_mail_sent_prompt=Un nouveau mail de confirmation à été envoyé à <b>%s</b>. Veuillez vérifier votre boîte de réception dans un délai de %d heures pour compléter votre enregistrement.
active_your_account=Activer votre Compte
active_your_account=Activer votre compte
resent_limit_prompt=Désolé, vos tentatives d'activation sont trop fréquentes. Veuillez réessayer dans 3 minutes.
has_unconfirmed_mail=Bonjour %s, votre adresse e-mail (<b>%s</b>) n'a pas été confirmée. Si vous n'avez reçu aucun mail de confirmation ou souhaitez renouveler l'envoi, cliquez sur le bouton ci-dessous.
resend_mail=Cliquez ici pour renvoyer un mail de confirmation
@@ -162,6 +157,7 @@ reset_password=Réinitialiser le mot de passe
invalid_code=Désolé, votre code de confirmation est invalide ou a expiré.
reset_password_helper=Cliquez ici pour réinitialiser votre mot de passe
password_too_short=Le mot de passe doit contenir 6 caractères minimum.
non_local_account=Les comptes non-locaux ne peuvent pas changer leur mot de passe via Gogs.
[mail]
activate_account=Veuillez activer votre compte
@@ -217,15 +213,14 @@ invalid_ssh_key=Désolé, impossible de valider votre clé SSH : %s
unable_verify_ssh_key=Gogs n'a pu vérifier la validité de votre clé SSH, même si nous partons du principe qu'elle le soit. Cela-dit, veuillez vous en assurer.
auth_failed=Échec d'authentification : %s
still_own_repo=Votre compte comporte toujours des propriétés du dépôt. Vous devez d'abord les supprimer ou les transférer.
still_has_org=Votre compte contient toujours au moins une adhésion à une organisation, vous devez quitter ou supprimer votre adhésion.
org_still_own_repo=Cette organisation comporte toujours des propriétés du dépôt. Vous devez d'abord les supprimer ou les transférer.
still_own_repo=Votre compte est toujours propriétaire d'un ou plusieurs dépôts. Vous devez d'abord les supprimer ou les transférer.
still_has_org=Votre compte fait toujours partie d'une ou plusieurs organisations. Vous devez d'abord les quitter ou les supprimer.
org_still_own_repo=Cette organisation est toujours propriétaire d'un ou plusieurs dépôts. Vous devez d'abord les supprimer ou les transférer.
target_branch_not_exist=La branche cible n'existe pas.
[user]
change_avatar=Changez d'avatar via gravatar.com
change_custom_avatar=Changez votre avatar dans les paramètres
change_avatar=Changer votre avatar
join_on=Inscrit le
repositories=Dépôts
activity=Activité publique
@@ -245,7 +240,7 @@ ssh_keys=Clés SSH
social=Réseaux Sociaux
applications=Applications
orgs=Organisations
delete=Supprimer le Compte
delete=Supprimer le compte
uid=ID d'Utilisateur
public_profile=Profil public
@@ -261,30 +256,30 @@ change_username_prompt=Cette modification affectera la manière dont les liens s
continue=Continuer
cancel=Annuler
enable_custom_avatar=Activer l'Avatar personnalisé
enable_custom_avatar=Activer l'avatar personnalisé
choose_new_avatar=Sélectionner un nouvel avatar
update_avatar=Mettre à jour l'avatar
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Supprimer l'avatar actuel
uploaded_avatar_not_a_image=Le fichier téléchargé n'est pas une image.
update_avatar_success=Votre avatar a été mis à jour avec succès.
change_password=Modifier le mot de passe
old_password=Mot de passe actuel
new_password=Nouveau Mot de Passe
new_password=Nouveau mot de passe
retype_new_password=Retapez le nouveau mot de passe
password_incorrect=Mot de passe actuel incorrect.
change_password_success=Mot de passe modifié avec succès. Vous pouvez à présent vous connecter avec le nouveau mot de passe.
password_change_disabled=Les utilisateurs non-locaux n'ont pas le droit de modifier leur mot de passe.
emails=Adresses E-mail
emails=Adresses e-mail
manage_emails=Gérer les adresses e-mail
email_desc=Votre adresse e-mail principale sera utilisée pour les notifications et d'autres opérations.
primary=Principale
primary_email=Définir comme principale
delete_email=Supprimer
email_deletion=Suppression de l'adresse l
email_deletion=Suppression de l'adresse e-mail
email_deletion_desc=Supprimer cette adresse e-mail supprimera les informations associées à votre compte. Voulez-vous continuer ?
email_deletion_success=L'adresse l a été supprimée avec succès !
email_deletion_success=L'adresse e-mail a été supprimée avec succès !
add_new_email=Ajouter une nouvelle adresse e-mail
add_email=Ajouter un e-mail
add_email_confirmation_sent=Une nouvelle confirmation d'adresse e-mail a été envoyé à '%s', veuillez vérifier votre boîte de réception dans un délai de %d heures pour terminer le processus de confirmation.
@@ -335,7 +330,7 @@ delete_account_desc=Ce compte sera supprimé définitivement. Voulez-vous contin
[repo]
owner=Propriétaire
repo_name=Nom du Dépôt
repo_name=Nom du dépôt
repo_name_helper=Idéalement, le nom d'un dépot devrait être court, mémorable et <strong>unique</strong>.
visibility=Visibilité
visiblity_helper=Ce dépôt est <span class="ui red text"> privé</span>
@@ -355,6 +350,8 @@ readme_helper=Sélectionnez un modèle de readme
auto_init=Initialiser ce dépôt avec le modèle et les fichiers sélectionnés
create_repo=Créer un dépôt
default_branch=Branche par défaut
mirror_prune=Purger
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Intervalle du miroir (heure)
mirror_address=Adresse du miroir
mirror_address_desc=Veuillez inclure les informations d'identification nécessaires dans l'adresse.
@@ -377,7 +374,7 @@ migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas
migrate.failed=Echec de migration: %v
mirror_from=miroir de
forked_from=scindé depuis
forked_from=forké depuis
fork_from_self=Vous ne pouvez pas forker un dépôt que vous possédez déja !
copy_link=Copier
copy_link_success=Copié!
@@ -405,7 +402,7 @@ tags=Tags
issues=Tickets
pulls=Pull Requests
labels=Etiquettes
milestones=Étapes
milestones=Jalons
commits=Commits
releases=Publications
file_raw=Raw
@@ -430,7 +427,7 @@ issues.new.milestone=Étape
issues.new.no_milestone=Pas d'étape
issues.new.clear_milestone=Effacer l'étape
issues.new.open_milestone=Ouvrir l'étape
issues.new.closed_milestone=Étapes fermées
issues.new.closed_milestone=Jalons fermés
issues.new.assignee=Affecté à
issues.new.clear_assignee=Supprimer les assignataires
issues.new.no_assignee=Pas d'assignataire
@@ -442,7 +439,7 @@ issues.open_tab=%d Ouvert
issues.close_tab=%d Fermé
issues.filter_label=Étiquette
issues.filter_label_no_select=Aucun étiquette sélectionnée
issues.filter_milestone=Étape
issues.filter_milestone=Jalon
issues.filter_milestone_no_select=Aucun jalon sélectionné
issues.filter_assignee=Assigné
issues.filter_assginee_no_select=Pas d'assignataire selectionné
@@ -476,7 +473,7 @@ issues.closed_at=`fermé à <a id="%[1]s"href="#%[1]s"> %[2]s"</a>`
issues.reopened_at=`réouvert à <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.commit_ref_at=`a référencé ce problème à partir d'un commit <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.poster=Publier
issues.collaborator=Collaborator
issues.collaborator=Collaborateur
issues.owner=Propriétaire
issues.sign_up_for_free=Inscrivez-vous gratuitement
issues.sign_in_require_desc=pour rejoindre cette conversation. Vous avez déjà un compte ? <a href="%s">Connectez-vous commenter</a>
@@ -557,8 +554,8 @@ wiki.save_page=Enregistrer la page
wiki.last_commit_info=%s a édité cette page %s
wiki.edit_page_button=Modifier
wiki.new_page_button=Nouvelle Page
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Supprimer la page
wiki.delete_page_notice_1=Cela supprimera la page <code>"%s"</code>. Soyez-en sûr.
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
@@ -566,6 +563,10 @@ wiki.last_updated=Dernière mise à jour: %s
settings=Paramètres
settings.options=Options
settings.collaboration=Collaboration
settings.collaboration.admin=Administrateur
settings.collaboration.write=Écrire
settings.collaboration.read=Lire
settings.collaboration.undefined=Indéfini
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Paramètres de base
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Les visiteurs seront redirigés vers cette URL l
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_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
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
@@ -591,20 +595,18 @@ settings.convert_confirm=Confirmer la conversion
settings.convert_succeed=Le dépôt a été converti avec succès en dépôt ordinaire.
settings.transfer=Changer de propriétaire
settings.transfer_desc=Transférer ce dépôt à un autre utilisateur ou une organisation dont vous possédez des droits d'administrateur.
settings.transfer_notices_1=-Vous perdrez l'accès si le nouveau propriétaire est un utilisateur individuel.
settings.transfer_notices_1=- Vous perdrez l'accès si le nouveau propriétaire est un utilisateur individuel.
settings.transfer_notices_2=- Vous conserverez l'accès si le nouveau propriétaire est une organisation et que vous y appartenez.
settings.transfer_form_title=Veuillez recopier le texte suivant afin de confirmer votre opération :
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_delete=Effacer les données du Wiki
settings.wiki_delete_desc=Une fois que vous effacez les données du wiki, on ne peut revenir en arrière. Soyez-en sûr.
settings.wiki_delete_notices_1=- Cela va supprimer et désactiver le wiki pour %s
settings.wiki_deletion_success=Le dépôt de données wiki ont été effacés avec succès.
settings.delete=Supprimer ce dépôt
settings.delete_desc=Attention, cette action est action irréversible. Soyez sûr de vous.
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, les tickets, les commentaires et les accès des collaborateurs.
settings.delete_notices_fork_1=- Si ce dépôt est public, tous les forks vont devenir indépendant après sa 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=- All forks will become independent after deletion.
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
@@ -613,9 +615,9 @@ settings.transfer_succeed=Le contrôle du dépôt a été transféré avec succ
settings.confirm_delete=Confirmer la suppression
settings.add_collaborator=Ajouter un collaborateur
settings.add_collaborator_success=Nouveau collaborateur ajouté.
settings.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Supprimer
settings.collaborator_deletion=Suppression d'un collaborateur
settings.collaborator_deletion_desc=Cet utilisateur n'aura plus accès pour collaborer à ce dépôt après sa suppression. Voulez-vous continuer?
settings.remove_collaborator_success=Collaborateur supprimé.
settings.search_user_placeholder=Rechercher un utilisateur...
settings.org_not_allowed_to_be_collaborator=Une organisation n'est pas autorisée à être ajoutée en tant que collaborateur.
@@ -688,6 +690,8 @@ diff.show_unified_view=Vue unifiée
diff.stats_desc=<strong> %d fichiers modifiés</strong> avec <strong>%d ajouts</strong> et <strong>%d suppressions</strong>
diff.bin=BIN
diff.view_file=Voir le fichier
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Versions
release.new_release=Nouvelle version
@@ -713,7 +717,7 @@ release.cancel=Annuler
release.publish=Publier
release.save_draft=Sauvegarder le Brouillon
release.edit_release=Modifier la version
release.delete_release=Supprimer Cette Version
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 !
@@ -721,7 +725,7 @@ release.tag_name_already_exist=Une version avec ce nom de tag existe déjà.
release.downloads=Téléchargements
[org]
org_name_holder=Nom d'organisation
org_name_holder=Nom de l'organisation
org_full_name_holder=Nom complet de l'organisation
org_name_helper=Idéalement, un nom d'organisation devrait être court et facilement mémorisable.
create_org=Créer une organisation
@@ -731,7 +735,7 @@ invite_someone=Inviter quelqu'un
teams=Équipes
lower_members=Membres
lower_repositories=dépôts
create_new_team=Créer une Nouvelle Équipe
create_new_team=Créer une nouvelle équipe
org_desc=Description
team_name=Nom d'Équipe
team_desc=Description
@@ -836,7 +840,7 @@ dashboard.resync_all_update_hooks_success=Tous les hooks de mises à jour des d
dashboard.reinit_missing_repos=Réinitialiser tous les dépôts qui ont perdu des fichiers Git
dashboard.reinit_missing_repos_success=Tous les enregistrements de dépôts qui ont perdu des fichiers Git ont été réinitialisés avec succès.
dashboard.server_uptime=Durée de Marche Serveur
dashboard.server_uptime=Uptime du serveur
dashboard.current_goroutine=Goroutines actuelles
dashboard.current_memory_usage=Utilisation Mémoire actuelle
dashboard.total_memory_allocated=Mémoire totale allouée
@@ -915,6 +919,7 @@ auths.enabled=Activé
auths.updated=Mis à jour
auths.auth_type=Type d'authentification
auths.auth_name=Nom de l'authentification
auths.security_protocol=Protocole de sécurité
auths.domain=Domaine
auths.host=Hôte
auths.port=Port
@@ -950,7 +955,7 @@ auths.update=Mettre à jour les paramètres d'authentifications
auths.delete=Supprimer cette authentification
auths.delete_auth_title=Suppression de l'authentification
auths.delete_auth_desc=Cette authentification va être supprimée. voulez-vous continuer ?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.still_in_used=Cette authentification est encore utilisée par d'autres utilisateurs, supprimez-les ou convertir ces utilisateurs vers un autre type de session, avant.
auths.deletion_success=L'authentification a été supprimée avec succès !
config.server_config=Configuration du Serveur
@@ -975,9 +980,9 @@ config.ssh_domain=Domaine
config.ssh_port=Port
config.ssh_listen_port=Port d'écoute
config.ssh_root_path=Emplacement racine
config.ssh_key_test_path=Emplacement de test des clés
config.ssh_key_test_path=Chemin de test des clés
config.ssh_keygen_path=Chemin vers le générateur de clefs ("ssh-keygen")
config.ssh_minimum_key_size_check=Minimum Key Size Check
config.ssh_minimum_key_size_check=Vérification de la longueur de clé minimale
config.ssh_minimum_key_sizes=Tailles de clé minimales
config.db_config=Configuration de la Base de Données
@@ -1066,8 +1071,8 @@ create_issue=`a ouvert un problème <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`tickets clos <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`tickets ré-ouverts <a href="%s/issues/%s">%s#%[2]s</a>`
create_pull_request=`pull request créée le <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`pull request fermé <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`pull request ré-ouverte <a href="%s/pulls/%s">%s#%[2]s</a>`
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>

251
conf/locale/locale_it-IT.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Problemi
cancel=Annulla
[search]
search=Ricerca...
repository=Repository
user=Utente
issue=Problema
code=Codice
[install]
install=Installazione
title=Passi d'installazione per il primo avvio
@@ -65,7 +58,7 @@ 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. <br>Please use absolute path when you start as service.
sqlite_helper=Il path assoluto per il database SQLite3 o TiDB. <br>Per favore usa il path assoluto quando lo avvii come servizio.
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.
@@ -79,7 +72,7 @@ repo_path_helper=Tutti i repository Git remoti saranno salvati in questa directo
run_user=Esegui con l'utente
run_user_helper=L'utente deve avere accesso al percorso root del repository e avviare Gogs.
domain=Dominio
domain_helper=Questo modifica lo SSH clone URLs.
domain_helper=Questo influisce sugli URL per il clonaggio via SSH.
ssh_port=Porta SSH
ssh_port_helper=Numero di porta utilizzato dal server SSH, lasciare vuoto per disabilitare l'integrazione SSH.
http_port=Porta HTTP
@@ -140,6 +133,8 @@ issues.in_your_repos=Nei tuoi repository
[explore]
repos=Repository
users=Utenti
search=Cerca
[auth]
create_new_account=Crea un nuovo Account
@@ -162,6 +157,7 @@ reset_password=Reimposta la tua Password
invalid_code=Siamo spiacenti, il codice di conferma è scaduto o non valido.
reset_password_helper=Clicca qui per reimpostare la password
password_too_short=La lunghezza della password non può essere meno 6 caratteri.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Per favore attiva il tuo account
@@ -224,8 +220,7 @@ org_still_own_repo=Questa organizzazione ha ancora la proprietà del repository,
target_branch_not_exist=Il ramo (branch) di destinazione non esiste.
[user]
change_avatar=Cambia il tuo avatar su gravatar.com
change_custom_avatar=Cambia il tuo avatar nelle impostazioni
change_avatar=Change your avatar
join_on=Si è unito il
repositories=Repository
activity=Attività pubblica
@@ -264,7 +259,7 @@ cancel=Annulla
enable_custom_avatar=Abilita avatar personalizzato
choose_new_avatar=Scegli un nuovo avatar
update_avatar=Aggiorna le impostazioni avatar
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Elimina Avatar attuale
uploaded_avatar_not_a_image=Il file caricato non è un'immagine.
update_avatar_success=Le tue impostazioni avatar sono state aggiornate con successo.
@@ -355,6 +350,8 @@ readme_helper=Seleziona un template per il readme
auto_init=Inizializzare questo repository con i file e il modello selezionati
create_repo=Crea Repository
default_branch=Ramo (Branch) predefinito
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Intervallo Mirror (in ore)
mirror_address=Indirizzo del mirror
mirror_address_desc=Si prega di includere nell'indirizzo le credenziali utente necessarie.
@@ -466,22 +463,22 @@ issues.open_title=Aperto
issues.closed_title=Chiuso
issues.num_comments=%d commenti
issues.commented_at=`commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.no_content=There is no content yet.
issues.no_content=Non ci sono ancora contenuti.
issues.close_issue=Chiudi
issues.close_comment_issue=Commenta e chiudi
issues.reopen_issue=Riapri
issues.reopen_comment_issue=Commenta e riapri
issues.create_comment=Commento
issues.closed_at=`closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.closed_at=`chiuso <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`riaperto <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster=Autore
issues.collaborator=Collaborator
issues.collaborator=Collaboratori
issues.owner=Proprietario
issues.sign_up_for_free=Registrati gratuitamente
issues.sign_in_require_desc=to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>
issues.sign_in_require_desc=per partecipare a questa conversazione. Possiedi già un account?<a href="%s">Fai il login per commentare</a>
issues.edit=Modifica
issues.cancel=Cancel
issues.cancel=Annulla
issues.save=Salva
issues.label_title=Nome etichetta
issues.label_color=Colore etichetta
@@ -500,40 +497,40 @@ pulls.compare_changes=Confronta le modifiche
pulls.compare_changes_desc=Confronta due branch e fai una pull request per le modifiche.
pulls.compare_base=base
pulls.compare_compare=confronta
pulls.filter_branch=Filter branch
pulls.filter_branch=Filtra branch
pulls.no_results=Nessun risultato trovato.
pulls.nothing_to_compare=There is nothing to compare because base and head branches are even.
pulls.has_pull_request=`There is already a pull request between these two targets: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.nothing_to_compare=Non c'è niente da confrontare perchè i branch base e head uguali.
pulls.has_pull_request=`E' già presente una pull request tra questi due trargets: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=Crea Pull Request
pulls.title_desc=wants to merge %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code>
pulls.merged_title_desc=merged %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code> %[4]s
pulls.title_desc=vorrebbe unire %[1]d commit da <code>%[2]s</code> a <code>%[3]s</code>
pulls.merged_title_desc=ha unito %[1]d commit da <code>%[2]s</code> a <code>%[3]s</code> %[4]s
pulls.tab_conversation=Conversazione
pulls.tab_commits=Commit
pulls.tab_files=File modificati
pulls.reopen_to_merge=Riapri questa pull request per effettuare il merge.
pulls.merged=Merged
pulls.has_merged=This pull request has been merged successfully!
pulls.data_broken=Data of this pull request has been broken due to deletion of fork information.
pulls.merged=Unito
pulls.has_merged=Questa pull reqeust è stata mergiata con successo!
pulls.data_broken=I dati di questa pull request si sono rotti causa dell'eliminazione delle informazioni di fork.
pulls.is_checking=Il controllo dei conflitti è ancora in corso, per favore aggiorna pagina tra qualche istante.
pulls.can_auto_merge_desc=This pull request can be merged automatically.
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
pulls.can_auto_merge_desc=La pull request non può essere mergiata automaticamente.
pulls.cannot_auto_merge_desc=Questa pull request non può essere mergiata automaticamente perchè ci sono dei conflitti.
pulls.cannot_auto_merge_helper=Effettua il merge manualmente per risolvere i conflitti.
pulls.merge_pull_request=Unisci Pull Request
pulls.open_unmerged_pull_exists=`You can't perform reopen operation because there is already an open pull request (#%d) from same repository with same merge information and is waiting for merging.`
milestones.new=Nuova Milestone
milestones.open_tab=%d Open
milestones.close_tab=%d Closed
milestones.closed=Closed %s
milestones.no_due_date=No due date
milestones.open=Open
milestones.close=Close
milestones.new_subheader=Create milestones to organize your issues.
milestones.open_tab=%d Aperti
milestones.close_tab=%d Chiusi
milestones.closed=Chiuso %s
milestones.no_due_date=Nessuna data di scadenza
milestones.open=Apri
milestones.close=Chiudi
milestones.new_subheader=Crea delle milestones per organizzare le tue issues.
milestones.create=Crea Milestone
milestones.title=Titolo
milestones.desc=Descrizione
milestones.due_date=Data di scadenza (opzionale)
milestones.clear=Clear
milestones.clear=Pulisci
milestones.invalid_due_date_format=Il formato della data di scadenza non è valido, deve essere 'yyyy-mm-dd'.
milestones.create_success=La Milestone '%s' è stata creata con successo!
milestones.edit=Modifica Milestone
@@ -557,8 +554,8 @@ wiki.save_page=Salva pagina
wiki.last_commit_info=%s ha modificato questa pagina %s
wiki.edit_page_button=Modifica
wiki.new_page_button=Nuova pagina
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Cancella Pagina
wiki.delete_page_notice_1=Questo cancellerà lapagina <code>"%s"</code>. Si prega di esserne certi.
wiki.page_already_exists=Esiste già una pagina Wiki con questo stesso nome.
wiki.pages=Pagine
wiki.last_updated=Ultimo aggiornamento: %s
@@ -566,6 +563,10 @@ wiki.last_updated=Ultimo aggiornamento: %s
settings=Impostazioni
settings.options=Opzioni
settings.collaboration=Collaborazione
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Impostazioni di Base
@@ -577,34 +578,35 @@ settings.wiki_desc=Abilitare il wiki per consentire alle persone di scrivere doc
settings.use_external_wiki=Usa Wiki esterno
settings.external_wiki_url=URL Wiki esterno
settings.external_wiki_url_desc=I visitatori verranno reindirizzati all'URL quando cliccano sulla scheda.
settings.issues_desc=Enable builtin lightweight issue tracker
settings.issues_desc=Abilita l'issue tracker builtin leggero
settings.use_external_issue_tracker=Utilizza gestore di problemi esterno
settings.tracker_url_format=External Issue Tracker URL Format
settings.tracker_url_format=Formato URL Gestore Problemi Esterno
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
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.pulls_desc=Abilita le pull requests per accettare contributi pubblici
settings.danger_zone=Zona Pericolosa
settings.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
settings.convert=Convert To Regular Repository
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
settings.convert=Converti in Repository Regolare
settings.convert_desc=Puoi convertire questo mirror in un repository regolare. Questa operazione non può essere annullata.
settings.convert_notices_1=- Questa operazione non potrà essere annullata e convertirà questo mirror in un repository regolare.
settings.convert_confirm=Conferma la conversione
settings.convert_succeed=Repository has been converted to regular type successfully.
settings.convert_succeed=Il repository è stato convertito con successo al formato normale.
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.transfer_notices_1=- You will lose access if new owner is a individual user.
settings.transfer_notices_2=- You will conserve access if new owner is an organization and if you're one of the owners.
settings.transfer_form_title=Per favore inserisci le informazioni seguenti per confermare l'operazione:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete=Elimina i dati della Wiki
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_delete_notices_1=Questo eliminerà e disabiliterà la wiki per %s
settings.wiki_deletion_success=I dati della wiki del repository sono stati eliminati con successo.
settings.delete=Elimina questo repository
settings.delete_desc=Una volta che hai cancellato il repository, non puoi tornare indietro. Si prega di fare attenzione.
settings.delete_notices_1=-Questa operazione <strong>NON PUÒ</strong> essere annullata.
settings.delete_notices_2=-Questa operazione eliminerà definitivamente il tutto il contenuto del repository, inclusi i dati di Git, incidenti, commenti e accessi dei collaboratori.
settings.delete_notices_fork_1=-Se questo repository è pubblico, tutti i fork diventeranno indipendenti dopo la sua cancellazione.
settings.delete_notices_fork_2=-Se questo repository è privato, tutti fork verranno rimossi assieme ad esso.
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Il repository è stato eliminato con successo!
settings.update_settings_success=Le opzioni repository sono state aggiornate con successo.
settings.transfer_owner=Nuovo Proprietario
@@ -613,9 +615,9 @@ settings.transfer_succeed=Proprietà del repository trasferita con successo.
settings.confirm_delete=Conferma eliminazione
settings.add_collaborator=Aggiungi nuovo collaboratore
settings.add_collaborator_success=Il nuovo collaboratore è stato aggiunto.
settings.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Elimina
settings.collaborator_deletion=Eliminazione collaboratore
settings.collaborator_deletion_desc=Questo utente non potrà più collaborare a questo repository dopo l'eliminazione. Si desidera continuare?
settings.remove_collaborator_success=Il collaboratore è stato rimosso.
settings.search_user_placeholder=Cerca utente...
settings.org_not_allowed_to_be_collaborator=Un'organizzazione non può essere aggiunta come collaboratore.
@@ -624,12 +626,12 @@ settings.add_webhook=Aggiungi Webhook
settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HTTP POST. Ogni volta che qualcosa si verifica in Gogs, tratteremo la notifica all'host di destinazione specificato. Ulteriori informazioni in questa <a target="_blank" href="%s">Guida ai Webhooks</a>.
settings.webhook_deletion=Elimina 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_deletion_success=Il Webhook è stato eliminato con successo!
settings.webhook.test_delivery=Test di consegna
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 take few seconds before it shows up in the delivery history.
settings.webhook.request=Request
settings.webhook.response=Response
settings.webhook.request=Richiesta
settings.webhook.response=Risposta
settings.webhook.headers=Headers
settings.webhook.payload=Payload
settings.webhook.body=Body
@@ -642,17 +644,17 @@ settings.add_webhook_desc=Gogs manderà una richiesta <code>POST</code> all'URL
settings.payload_url=Payload URL
settings.content_type=Content Type
settings.secret=Secret
settings.slack_username=Username
settings.slack_username=Nome utente
settings.slack_icon_url=URL icona
settings.slack_color=Colore
settings.event_desc=Quali eventi dovrebbero innescare questo webhook?
settings.event_push_only=Solo l'evento <code>push</code>.
settings.event_send_everything=I need <strong>everything</strong>.
settings.event_choose=Let me choose what I need.
settings.event_send_everything=Ho bisogno di <strong>tutto</strong>.
settings.event_choose=Lasciami scegliere ciò di cui ho bisogno.
settings.event_create=Crea
settings.event_create_desc=Branch, or tag created
settings.event_create_desc=Branch, o tag creato
settings.event_push=Push
settings.event_push_desc=Git push to a repository
settings.event_push_desc=Git push in un repository
settings.active=Attivo
settings.active_helper=Anche i dettagli riguardanti l'evento che ha innescato l'hook saranno inviati.
settings.add_hook_success=Il nuovo webhook è stato aggiunto.
@@ -666,28 +668,30 @@ settings.slack_token=Token
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 keys have read-only access. They are not the same as personal account SSH keys.
settings.no_deploy_keys=You haven't added any deploy keys.
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 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=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!
settings.add_deploy_key=Aggiungi Deploy Key
settings.deploy_key_desc=Le deploy keys hanno accesso in sola lettura. Non equivalgono alle chiavi SSH personali.
settings.no_deploy_keys=Non hai aggiunto alcuna deploy key.
settings.title=Titolo
settings.deploy_key_content=Contenuto
settings.key_been_used=La deploy key è già in uso.
settings.key_name_used=Esiste già una deploy key con questo nome.
settings.add_key_success=La nuova deploy key '%s' è stata aggiunta con successo!
settings.deploy_key_deletion=Elimina Deploy Key
settings.deploy_key_deletion_desc=Cancellando questa deploy key verrà rismosso ogni accesso relativo a questa repository. Vuoi continuare?
settings.deploy_key_deletion_success=Deploy key eliminata con successo!
diff.browse_source=Sfoglia il codice sorgente
diff.parent=parent
diff.commit=commit
diff.data_not_available=Diff Data non disponibile.
diff.show_diff_stats=Mostra Diff Stats
diff.show_split_view=Split View
diff.show_unified_view=Unified View
diff.show_split_view=Visualizzazione separata
diff.show_unified_view=Visualizzazione unificata
diff.stats_desc=<strong>%d ha cambiato i file</strong> con <strong>%d aggiunte</strong> e <strong>%d eliminazioni</strong>
diff.bin=BIN
diff.view_file=Vedi File
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Rilasci
release.new_release=Nuovo Rilascio
@@ -702,21 +706,21 @@ release.edit_subheader=Detailed change log can help users understand what has be
release.tag_name=Nome tag
release.target=Obbiettivo
release.tag_helper=Scegli un tag esistente o crea un nuovo tag una volta pubblicato.
release.title=Title
release.content=Content
release.title=Titolo
release.content=Contenuto
release.write=Scrivi
release.preview=Anteprima
release.loading=Caricamento...
release.prerelease_desc=Questo è un pre-rilascio
release.prerelease_helper=Precisiamo che questo rilascio non è pronta per la produzione.
release.cancel=Cancel
release.cancel=Annulla
release.publish=Pubblica Rilascio
release.save_draft=Salva Bozza
release.edit_release=Modifica Rilascio
release.delete_release=Delete This Release
release.deletion=Release Deletion
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.delete_release=Cancela questa Release
release.deletion=Eliminazione Release
release.deletion_desc=Eliminando questa release cancellarai anche i tag Git corrispondenti. Vuoi continuare?
release.deletion_success=La release è stata eliminata con successo!
release.tag_name_already_exist=Un rilascio con questo tag esiste già.
release.downloads=Download
@@ -749,7 +753,7 @@ settings.website=Sito Web
settings.location=Residenza
settings.update_settings=Aggiorna Impostazioni
settings.update_setting_success=Impostazioni dell'organizzazione aggiornate con successo.
settings.change_orgname_prompt=This change will affect how links relate to the organization.
settings.change_orgname_prompt=Questa operazione modificherà il modo in cui i links sono in relazione con l'organizzazione.
settings.update_avatar_success=Organization avatar setting has been updated successfully.
settings.delete=Elimina organizzazione
settings.delete_account=Elimina questa organizzazione
@@ -764,7 +768,7 @@ members.public=Pubblico
members.public_helper=rendi privato
members.private=Privato
members.private_helper=rendi pubblico
members.member_role=Member Role:
members.member_role=Ruolo del membro:
members.owner=Proprietario
members.member=Membro
members.remove=Rimuovere
@@ -794,7 +798,7 @@ teams.read_permission_desc=Questo Team concede accesso di <strong>Lettura</stron
teams.write_permission_desc=Questo Team concede accesso di <strong>Scrittura</strong>: i membri possono leggere e pushare i repository del Team.
teams.admin_permission_desc=Questo Team concede accesso di <strong>Amministratore</strong>: i membri possono leggere i, pushare a, e aggiungere collaboratori ai repository del Team.
teams.repositories=Repository di Squadra
teams.search_repo_placeholder=Search repository...
teams.search_repo_placeholder=Cerca repository...
teams.add_team_repository=Aggiungere Repository di Squadra
teams.remove_repo=Rimuovi
teams.add_nonexistent_repo=Il repository che stai tentando di aggiungere non esiste, crealo prima.
@@ -882,8 +886,8 @@ users.auth_login_name=Authentication Login Name
users.password_helper=Leave it empty to remain unchanged.
users.update_profile_success=Profilo dell'account aggiornato con successo.
users.edit_account=Modifica Account
users.max_repo_creation=Maximum Repository Creation Limit
users.max_repo_creation_desc=(Set -1 to use global default limit)
users.max_repo_creation=Limite massimo per la creazione di Repository
users.max_repo_creation_desc=(Inserire -1 per usare il limite globale di default)
users.is_activated=Questo account è attivato
users.is_admin=Questo account ha permessi di amministratore
users.allow_git_hook=Questo account ha il permesso di creare hooks di Git
@@ -908,31 +912,32 @@ repos.stars=Voti
repos.issues=Problemi
auths.auth_manage_panel=Authentication Manage Panel
auths.new=Add New Source
auths.new=Aggiungi Nuova Origine
auths.name=Nome
auths.type=Tipo
auths.enabled=Attivo
auths.updated=Aggiornato
auths.auth_type=Authentication Type
auths.auth_name=Authentication Name
auths.auth_type=Tipo di autenticazione
auths.auth_name=Nome di autenticazione
auths.security_protocol=Security Protocol
auths.domain=Dominio
auths.host=Host
auths.port=Porta
auths.bind_dn=Bind DN
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.bind_dn=Binda DN
auths.bind_password=Binda Password
auths.bind_password_helper=Attenzione: Questa password è salvata in chiaro. Non usare su un acount con alti privilegi.
auths.user_base=User Search Base
auths.user_dn=User DN
auths.attribute_username=Username attribute
auths.user_dn=DN dell'utente
auths.attribute_username=Attributo username
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
auths.attributes_in_bind=Fetch attributes in Bind DN context
auths.filter=User Filter
auths.admin_filter=Admin Filter
auths.filter=Fitro utente
auths.admin_filter=Filtro Amministratore
auths.ms_ad_sa=Ms Ad SA
auths.smtp_auth=SMTP Authentication Type
auths.smtp_auth=Tipo di autenticazione SMTP
auths.smtphost=Host SMTP
auths.smtpport=Porta SMTP
auths.allowed_domains=Domini consentiti
@@ -942,12 +947,12 @@ auths.skip_tls_verify=Salta verifica TLS
auths.pam_service_name=Nome del Servizio PAM
auths.enable_auto_register=Abilitare Registrazione Automatica
auths.tips=Consigli
auths.edit=Edit Authentication Setting
auths.edit=Modifica impostazioni di autenticazione
auths.activated=Questa Autenticazione è stata attivata
auths.new_success=New authentication '%s' has been added successfully.
auths.update_success=Authentication setting has been updated successfully.
auths.update=Update Authentication Setting
auths.delete=Delete This Authentication
auths.update=Aggiornare le impostazioni di autenticazione
auths.delete=Elimina questa autenticazione
auths.delete_auth_title=Authentication Deletion
auths.delete_auth_desc=This authentication is going to be deleted, do you want to continue?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
@@ -969,16 +974,16 @@ config.script_type=Tipo di Script
config.reverse_auth_user=Autenticazione Utente Inversa
config.ssh_config=Configurazione SSH
config.ssh_enabled=Enabled
config.ssh_start_builtin_server=Start Builtin Server
config.ssh_domain=Domain
config.ssh_enabled=Attivo
config.ssh_start_builtin_server=Avvia server builtin
config.ssh_domain=Dominio
config.ssh_port=Porta
config.ssh_listen_port=Porta in ascolto
config.ssh_root_path=Root Path
config.ssh_key_test_path=Key Test Path
config.ssh_keygen_path=Keygen ('ssh-keygen') Path
config.ssh_minimum_key_size_check=Minimum Key Size Check
config.ssh_minimum_key_sizes=Minimum Key Sizes
config.ssh_root_path=Percorso Root
config.ssh_key_test_path=Percorso chiave di test
config.ssh_keygen_path=Percorso Keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Verifica delle dimensioni minime della chiave
config.ssh_minimum_key_sizes=Dimensioni minime della chiave
config.db_config=Configurazione Database
config.db_type=Tipo
@@ -995,12 +1000,12 @@ config.disable_register=Disabilita Registrazione
config.show_registration_button=Mostra Pulsane Registrazione
config.require_sign_in_view=Richiesto Accesso per Vedere
config.mail_notify=Email di Notifica
config.disable_key_size_check=Disable Minimum Key Size Check
config.disable_key_size_check=Disabilita controllo sulle dimensioni minime della chiave
config.enable_captcha=Abilita Captcha
config.active_code_lives=Attiva Vita del Codice
config.reset_password_code_lives=Reimpostare Password della Vita del Codice
config.webhook_config=Configurazione Webhook
config.queue_length=Queue Length
config.queue_length=Lunghezza della coda
config.deliver_timeout=Tempo Limite di Consegna
config.skip_tls_verify=Salta verifiche TLS
config.mailer_config=Configurazione Mailer
@@ -1010,8 +1015,8 @@ config.mailer_name=Nome
config.mailer_host=Host
config.mailer_user=Utente
config.send_test_mail=Invia email di test
config.test_mail_failed=Fail to send test email to '%s': %v
config.test_mail_sent=Test email has been sent to '%s'.
config.test_mail_failed=Impossibile inviare mail a '%s': %v
config.test_mail_sent=Una mail di prova è stata inviata a '%s'.
config.oauth_config=Configurazione OAuth
config.oauth_enabled=Attivo
config.cache_config=Configurazione Cache
@@ -1045,18 +1050,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.view_detail_header=Visualizza dettagli dell'avviso
notices.actions=Azioni
notices.select_all=Seleziona tutto
notices.deselect_all=Deseleziona tutto
notices.inverse_selection=Inverti selezione
notices.delete_selected=Elimina selezionati
notices.delete_all=Delete All Notices
notices.delete_all=Elimina tutti gli avvisi
notices.type=Tipo
notices.type_1=Repository
notices.desc=Descrizione
notices.op=Op.
notices.delete_success=System notices have been deleted successfully.
notices.delete_success=Gli avvisi di sistema sono stati successivamente eliminati.
[action]
create_repo=ha creato il repository <a href="%s">%s</a>
@@ -1072,7 +1077,7 @@ comment_issue=`ha commentato il problema <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=ha trasferito il repository <code>%s</code> a <a href="%s">%s</a>
push_tag=ha pushato il tag <a href="%s/src/%s">%[2]s</a> a <a href="%[1]s">%[3]s</a>
compare_commits=View comparison for these %d commits
compare_commits=Visualizza comparazione tra questi %d commit
[tool]
ago=fa
@@ -1096,8 +1101,8 @@ raw_seconds=secondi
raw_minutes=minuti
[dropzone]
default_message=Drop files here or click to upload.
invalid_input_type=You can't upload files of this type.
file_too_big=File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
remove_file=Remove file
default_message=Trascina i file qui o clicca per caricare.
invalid_input_type=Non è possibile caricare file di questo tipo.
file_too_big=La dimensione del file ({{filesize}} MB) supera la dimensione massima ({{maxFilesize}} MB).
remove_file=Rimuovi file

139
conf/locale/locale_ja-JP.ini Executable file → Normal file
View File

@@ -2,7 +2,7 @@ app_desc=Go言語で実装したセルフホストGitサービス
home=ホーム
dashboard=ダッシュボード
explore=クプローラ
explore=エクプローラ
help=ヘルプ
sign_in=サインイン
sign_out=サインアウト
@@ -21,7 +21,7 @@ username=ユーザ名
email=E-mail
password=パスワード
re_type=再入力
captcha=キャプチャ
captcha=CAPTCHA
repository=リポジトリ
organization=組織
@@ -35,26 +35,19 @@ manage_org=組織を管理
admin_panel=管理者パネル
account_settings=アカウント設定
settings=設定
your_profile=あなたのプロファイ
your_settings=あなたの設定
your_profile=プロフィー
your_settings=設定
activities=Activities
activities=アクティビティ
pull_requests=プルリクエスト
issues=課題
cancel=キャンセル
[search]
search=検索...
repository=リポジトリ
user=ユーザ
issue=課題
code=コード
[install]
install=インストール
title=初回実行のインストール手順
docker_helper=DockerでGogsを稼動する場合、このページに変更を加えるまえに、 <a target="_blank" href="%s">Guidelines</a>をよく読んでください!
title=インストールをする前に必要な準備をしましょう
docker_helper=DockerでGogsを稼動する場合、このページに変更を加えるに、 <a target="_blank" href="%s">ガイドライン</a>をよく読んでください!
requite_db_desc=Gogs は、MySQL、PostgreSQL、SQLite3 または TiDB が必要です。
db_title=データベース設定
db_type=データベースの種類
@@ -62,10 +55,10 @@ host=ホスト
user=ユーザ
password=パスワード
db_name=データベース名
db_helper=Mysql INNODB エンジン utf8_general_ci の文字セットを使用してください
db_helper=MySQLではエンジンがINNODB、文字セットがutf8_general_ciである必要があります
ssl_mode=SSL モード
path=パス
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
sqlite_helper=SQLite3かTiDBのデータベースのファイルパス。<br>サービスとして開始する際には絶対パスを利用してください。
err_empty_db_path=SQLite3 または TiDB データベースのパスを空にすることはできません。
err_invalid_tidb_name=TiDB データベース名は文字"."と"-"を許可しない。
no_admin_and_disable_registration=管理者アカウントを作成せずに登録を無効にすることはできません。
@@ -79,18 +72,18 @@ repo_path_helper=すべての Git リモート リポジトリはこのディレ
run_user=実行ユーザ
run_user_helper=ユーザーはリポジトリ ルートパスへのアクセス、及びGogs を実行する権限を所有する必要があります。
domain=ドメイン
domain_helper=これはSSHクローンURLに影響す
domain_helper=これはSSHクローンURLに影響します。
ssh_port=SSH ポート
ssh_port_helper=あならのSSHサーバおポート番号、SSH機能を無効するにはここを空白のままにしてください
ssh_port_helper=SSHサーバーを使用する場合はポート番号を入力してください。 空白にした場合は無効化されます
http_port=HTTP ポート
http_port_helper=アプリケーションが待ち受けするポート番号。
app_url=アプリケーションの URL
app_url_helper=この設定は、HTTP / HTTPSのクローンURLおよび、一部のメールボックスへのリンクに影響を与えます。
log_root_path=Log Path
log_root_path_helper=Directory to write log files to.
log_root_path=ログのパス
log_root_path_helper=ログファイルを書き込むディレクトリ。
optional_title=オプション設定
email_title=E-mailサービス設定
email_title=メールサービス設定
smtp_host=SMTP ホスト
smtp_from=差出人
smtp_from_helper=送信者メールアドレス、RFC 5322。フォーマットはメールアドレスのみ、または"Name" <email@example.com>。
@@ -99,10 +92,10 @@ mailer_password=送信者のパスワード
register_confirm=登録の確認を有効にする
mail_notify=メール通知を有効にする
server_service_title=サーバーとその他のサービスの設定
offline_mode=オフラインモード有効
offline_mode_popup=プロダクション モードでCDN を無効にし、すべてのリソースファイルをローカルで提供します
offline_mode=オフラインモード有効にする
offline_mode_popup=プロダクションモードでは、CDNを使用せずにローカルからリソースファイルを使用します。
disable_gravatar=Gravatarのサービスを無効にします
disable_gravatar_popup=Disable Gravatar and custom sources, all avatars are uploaded by users or default.
disable_gravatar_popup=Gravatarとカスタムソースを無効にして、全てのアバターをユーザーによってアップロードされたものかデフォルトなものにします。
disable_registration=自己登録を無効にする
disable_registration_popup=自己登録を無効にし、管理者のみがアカウント作成できる
enable_captcha=Captchaを有効にする
@@ -124,35 +117,37 @@ run_user_not_match=実行ユーザーは、現在のユーザーではない: %s
save_config_failed=構成の保存に失敗した: %v
invalid_admin_setting=管理者アカウントの設定が無効です: %v
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
invalid_log_root_path=Log root path is invalid: %v
invalid_log_root_path=ログのルートパスがむこうです: %v
[home]
uname_holder=ユーザー名またはEメール
password_holder=パスワード
switch_dashboard_context=ダッシュ ボードのコンテキストを切替
my_repos=のリポジトリ
my_repos=自分のリポジトリ
collaborative_repos=共同リポジトリ
my_orgs=の組織
my_mirrors=のミラー
my_orgs=自分の組織
my_mirrors=自分のミラー
view_home=ビュー %s
issues.in_your_repos=あなたのリポジトリ
[explore]
repos=リポジトリ
users=ユーザ
search=検索
[auth]
create_new_account=新規アカウントを作成
register_hepler_msg=すでにアカウントをお持ちですか?今すぐログイン
social_register_hepler_msg=すでにアカウントをお持ちですか?今すぐバインド
disable_register_prompt=申し訳ありませんが、登録が無効になっています。サイト管理者に問い合わせください。
register_hepler_msg=にアカウントをお持ちですか?今すぐログインしましょう
social_register_hepler_msg=にアカウントをお持ちですか?連携しましょう
disable_register_prompt=申し訳ありませんが、現在登録は受け付けておりません。サイト管理者に問い合わせください。
disable_register_mail=申し訳ありませんが、登録メールの確認機能が無効になっています。
remember_me=ログイン状態を保持する
remember_me=ログインしたままにする
forgot_password=パスワードを忘れた
forget_password=パスワードを忘れ
sign_up_now=アカウントが必要ですか?今すぐサインアップ
forget_password=パスワードを忘れましたか
sign_up_now=アカウントが必要ですか?今すぐ登録しましょう!
confirmation_mail_sent_prompt=新しい確認メールを <b>%s</b> に送りました。登録を完了させるために、%d時間以内にあなたのメールボックスを確認してください。
active_your_account=アカウントをアクティブ
active_your_account=アカウントを有効化
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
resend_mail=アクティベーションメールを再送信するにはここをクリック
@@ -162,13 +157,14 @@ reset_password=パスワードリセット
invalid_code=申し訳ありませんが、確認用コードが期限切れまたは無効です。
reset_password_helper=パスワードをリセットするにはここをクリック
password_too_short=6文字未満のパスワードは設定できません。
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=あなたのアカウントを有効にしてください。
activate_email=電子メール アドレスを確認します。
reset_password=パスワードをリセットします.
register_success=ようこそ、登録成功
register_notify=Welcome on board
register_notify=ボードへようこそ
[modal]
yes=はい
@@ -224,8 +220,7 @@ org_still_own_repo=この組織はまだリポジトリの所有しています
target_branch_not_exist=ターゲットブランチが存在しない
[user]
change_avatar=gravatar.com で自分のアバターを変更
change_custom_avatar=設定で自分のアバターを変更
change_avatar=アバターを変更
join_on=参加しました
repositories=リポジトリ
activity=パブリック・アクティビティ
@@ -264,7 +259,7 @@ cancel=キャンセル
enable_custom_avatar=カスタムのアバターを有効にする
choose_new_avatar=新しいアバターを選択
update_avatar=アバターの設定を更新
delete_current_avatar=Delete Current Avatar
delete_current_avatar=現在のアバターを削除
uploaded_avatar_not_a_image=アップロードされたファイルは画像ではない。
update_avatar_success=あなたのアバターの設定が更新されました。
@@ -315,7 +310,7 @@ social_desc=これは関連付けられたソーシャルアカウントのリ
unbind=バインド解除
unbind_success=SNSアカウントがバインドされていない。
manage_access_token=個人のアクセス トークンを管理
manage_access_token=パーソナルアクセス トークンを管理
generate_new_token=新しいトークンを生成
tokens_desc=生成したトークンを利用して Gogs の API にアクセスすることができます。
new_token_desc=今のところ、全てのトークンはあなたのアカウントにフルアクセスできます。
@@ -328,7 +323,7 @@ access_token_deletion_desc=パーソナルアクセストークンを削除す
delete_token_success=パーソナルアクセストークンは正常に削除されました!同時にあなたのアプリケーションを更新することを忘れないでください。
delete_account=アカウントを削除
delete_prompt=この操作はあなたのアカウント完全に削除し、復旧<strong>できない</strong>
delete_prompt=この操作をするとアカウント完全に削除され、<strong>二度と元に戻すことができなくなります</strong>
confirm_delete_account=削除の確認
delete_account_title=アカウントの削除
delete_account_desc=このアカウントは永久に削除しようとしている、継続しますか?
@@ -336,15 +331,15 @@ delete_account_desc=このアカウントは永久に削除しようとしてい
[repo]
owner=オーナー
repo_name=リポジトリ名
repo_name_helper=偉大なリポジトリ名は短い。思い出に残り、そして<strong>一意</strong>
visibility=ビジビリティ
repo_name_helper=短くて分かりやすく<strong>重複しない</strong>リポジトリ名を決めてください
visibility=公開/非公開
visiblity_helper=このリポジトリは<span class="ui red text">プライベート</span>です。
visiblity_helper_forced=サイト管理者は、強制的にすべての新しいリポジトリを<span class="ui red text"> プライベート</span> にしています。
visiblity_fork_helper=(この値の変更はすべてのフォークに適用されます)
clone_helper=クローニングのヘルプが必要ですか?<a target="_blank"href="%s"> ヘルプ</a> を参照してください!
fork_repo=フォークのリポジトリ
clone_helper=クローンに関してお困りであれば<a target="_blank"href="%s"> ヘルプ</a> を参照しましょう。
fork_repo=リポジトリをフォーク
fork_from=フォーク元
fork_visiblity_helper=フォークされたリポジトリ可視状態変更できません
fork_visiblity_helper=フォークされたリポジトリ可視状態変更できません
repo_desc=説明
repo_lang=言語
repo_lang_helper=.gitignoreファイルを選択
@@ -355,6 +350,8 @@ readme_helper=Readme ファイルのテンプレートを選択
auto_init=選択されたファイルおよびテンプレートでリポジトリを初期化
create_repo=リポジトリを作成
default_branch=デフォルトのブランチ
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=ミラー 間隔(時)
mirror_address=ミラー アドレス
mirror_address_desc=Please include necessary user credentials in the address.
@@ -363,8 +360,8 @@ stargazers=Stargazers
forks=フォーク
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
form.name_reserved=リポジトリ名 '%s' は予約されています。
form.name_pattern_not_allowed=リポジトリ名のパターン '%s' は許可されていません。
form.name_reserved=リポジトリ名 '%s' は使用されています。
form.name_pattern_not_allowed=リポジトリ名 '%s' は使用できません。
need_auth=認証が必要
migrate_type=マイグレーションの種類
@@ -376,7 +373,7 @@ migrate.permission_denied=ローカル リポジトリをインポートする
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
migrate.failed=移行に失敗しました: %v
mirror_from=mirror of
mirror_from=同期ミラー
forked_from=フォーク元
fork_from_self=すでにあなたの所有しているリポジトリはフォークできません
copy_link=コピー
@@ -408,9 +405,9 @@ labels=ラベル
milestones=マイルストーン
commits=コミット
releases=リリース
file_raw=生データ
file_raw=Raw
file_history=履歴
file_view_raw=データを見る
file_view_raw=Rawデータを見る
file_permalink=パーマリンク
commits.commits=コミット
@@ -448,8 +445,8 @@ issues.filter_assignee=アサインされた人
issues.filter_assginee_no_select=選択可能な担当者がいない
issues.filter_type=タイプ
issues.filter_type.all_issues=すべての問題
issues.filter_type.assigned_to_you=あなたに割り当てられました。
issues.filter_type.created_by_you=あなたが作成しました。
issues.filter_type.assigned_to_you=担当中のリポジトリ
issues.filter_type.created_by_you=作成したリポジトリ
issues.filter_type.mentioning_you=あなたに伝える
issues.filter_sort=並べ替え
issues.filter_sort.latest=最新
@@ -468,7 +465,7 @@ issues.num_comments=%d コメント
issues.commented_at=`コメント <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.no_content=まだコンテンツがありません
issues.close_issue=閉じる
issues.close_comment_issue=コメントと閉じる
issues.close_comment_issue=コメントしてクローズ
issues.reopen_issue=Reopen
issues.reopen_comment_issue=コメントと再開
issues.create_comment=コメント 
@@ -476,7 +473,7 @@ issues.closed_at=`closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster=ポスター
issues.collaborator=Collaborator
issues.collaborator=コラボレータ
issues.owner=オーナー
issues.sign_up_for_free=無料でサインアップ
issues.sign_in_require_desc=to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>
@@ -566,6 +563,10 @@ wiki.last_updated=最終更新 %s
settings=設定
settings.options=オプション
settings.collaboration=コラボレーション
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git のフック
settings.basic_settings=基本設定
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Visitors will be redirected to URL when they cli
settings.issues_desc=組み込み簡易課題トラッカーを有効
settings.use_external_issue_tracker=外部課題トラッキングシステムを使用
settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
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=危険地帯
@@ -602,15 +606,13 @@ settings.delete=このリポジトリを削除
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
settings.delete_notices_1=-この操作は<strong>元に戻せません</strong> 。
settings.delete_notices_2=- This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
settings.delete_notices_fork_1=- If this repository is public, all forks will become independent after deletion.
settings.delete_notices_fork_2=もしプライペートリポジトリの場合、全てのフォークも同時に削除されます。
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Repository has been deleted successfully!
settings.update_settings_success=リポジトリ オプションが更新されました。
settings.transfer_owner=新しいオーナー
settings.make_transfer=転送
settings.transfer_succeed=リポジトリの所有権は正常に転送されました。
settings.confirm_delete=削除確認
settings.confirm_delete=削除確認
settings.add_collaborator=新しい共同編集者を追加
settings.add_collaborator_success=新しい共同編集者が追加されました。
settings.delete_collaborator=Delete
@@ -688,6 +690,8 @@ diff.show_unified_view=Unified View
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
diff.bin=BIN
diff.view_file=ファイルの表示
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=リリース
release.new_release=新しいリリース
@@ -725,7 +729,7 @@ org_name_holder=組織名
org_full_name_holder=組織のフルネーム
org_name_helper=偉大な組織の名は短く覚えやすいです。
create_org=組織を作成
repo_updated=更新した
repo_updated=最終更新
people=人々
invite_someone=誰かを招待
teams=チーム
@@ -753,8 +757,8 @@ settings.change_orgname_prompt=This change will affect how links relate to the o
settings.update_avatar_success=組織のアバター画像が正常に更新されました。
settings.delete=組織を削除
settings.delete_account=この組織を削除
settings.delete_prompt=操作はこの組織完全に削除し、復旧<strong>できない</strong>
settings.confirm_delete_account=削除確認
settings.delete_prompt=この操作をすると組織完全に削除され、<strong>二度と元に戻すことができなくなります</strong>
settings.confirm_delete_account=削除確認
settings.delete_org_title=組織の削除
settings.delete_org_desc=この組織は完全に削除されます、継続しますか?
settings.hooks_desc=この組織のもとで <strong>すべてのリポジトリ</strong> に対してトリガーされる webhook を追加します。
@@ -912,9 +916,10 @@ auths.new=新しいソースを追加
auths.name=名前
auths.type=タイプ
auths.enabled=Enabled
auths.updated=Updated
auths.updated=更新しました
auths.auth_type=認証タイプ
auths.auth_name=認証名
auths.security_protocol=Security Protocol
auths.domain=ドメイン
auths.host=ホスト
auths.port=ポート
@@ -1021,7 +1026,7 @@ config.cache_conn=キャッシュ接続
config.session_config=セッションの構成
config.session_provider=セッション プロバイダー
config.provider_config=プロバイダーの構成
config.cookie_name=クッキー
config.cookie_name=クッキーの名前
config.enable_set_cookie=クッキーの設定を有効にする
config.gc_interval_time=GC 間隔
config.session_life_time=セッションのライフタイム
@@ -1059,8 +1064,8 @@ notices.op=Op。
notices.delete_success=システム通知が正常に削除されました。
[action]
create_repo=リポジトリ <a href="%s"> %s</a>を作成しました
rename_repo=<code>%[1]s</code> から <a href="%[2]s">[3]s</a> にリポジトリ名を変更した
create_repo=リポジトリ <a href="%s"> %s</a> を作成しました
rename_repo=<code>%[1]s</code> から <a href="%[2]s">[3]s</a> にリポジトリ名を変更しまし
commit_repo=<a href="%[1]s">%[4]s</a>を<a href="%[1]s/src/%[2]s">%[3]s</a>にプッシュしました
create_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> を開きました`
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
@@ -1086,7 +1091,7 @@ now=今
1mon=1 ヶ月 %s
1y=1 年間 %s
seconds=%d 秒 %s
minutes=%d 分の %s
minutes=%d%s
hours=%d 時間 %s
days=%d 日 %s
weeks=%d 週間 %s

57
conf/locale/locale_lv-LV.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Problēmas
cancel=Atcelt
[search]
search=Meklēt...
repository=Repozitorijs
user=Lietotājs
issue=Kļūda
code=Kods
[install]
install=Instalācija
title=Instalācijas soļi pirmo reizi palaižot
@@ -140,6 +133,8 @@ issues.in_your_repos=Jūsu repozitorijos
[explore]
repos=Repozitoriji
users=Lietotāji
search=Meklēt
[auth]
create_new_account=Izveidot jaunu kontu
@@ -162,6 +157,7 @@ reset_password=Atjaunot savu paroli
invalid_code=Atvainojiet, Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs.
reset_password_helper=Nospiediet šeit, lai atjaunotu paroli
password_too_short=Paroles garums nedrīkst būt mazāks par 6.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Lūdzu, aktivizējiet savu kontu
@@ -224,8 +220,7 @@ org_still_own_repo=Šī organizācija ir vismaz viena repozitorija īpašnieks,
target_branch_not_exist=Mērķa atzars neeksistē
[user]
change_avatar=Mainīt savu profila attēlu vietnē gravatar.com
change_custom_avatar=Mainīt savu profila attēlu iestatījumos
change_avatar=Change your avatar
join_on=Pievienojās
repositories=Repozitoriji
activity=Publiskā aktivitāte
@@ -264,7 +259,7 @@ cancel=Atcelt
enable_custom_avatar=Iespējot maināmu profila attēlu
choose_new_avatar=Izvēlēties jaunu profila attēlu
update_avatar=Saglabāt profila bildi
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Dzēst pašreizējo profila bildi
uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls.
update_avatar_success=Jūsu profila bilde tika veiksmīgi saglabāta.
@@ -355,6 +350,8 @@ readme_helper=Izvēlieties faila LasiMani sagatavi
auto_init=Inicializēt šo repozitoriju ar izvēlētajiem failiem un sagatavi
create_repo=Izveidot repozitoriju
default_branch=Noklusējuma atzars
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Spoguļošanas intervāls (stundās)
mirror_address=Spoguļa adrese
mirror_address_desc=Lūdzu iekļaujiet adresē nepieciešamo lietotājvārdu/paroli.
@@ -476,7 +473,7 @@ issues.closed_at=`aizvērts <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`atvērts atkārtoti <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`pieminēja šo problēmu revīzijā <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster=Autors
issues.collaborator=Collaborator
issues.collaborator=Līdzstrādnieks
issues.owner=Īpašnieks
issues.sign_up_for_free=Pievienojieties
issues.sign_in_require_desc=, lai piedalītos diskusijā. Jau ir konts? <a href="%s">Pierakstieties, lai komentētu</a>
@@ -557,8 +554,8 @@ 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.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Dzēst lapu
wiki.delete_page_notice_1=Tiks izdzēsta lapa <code>"%s"</code>. Pārliecinieties, ka patiešām to vēlaties.
wiki.page_already_exists=Vikivietnes lapa ar šādu nosaukumu jau eksistē.
wiki.pages=Lapas
wiki.last_updated=Pēdējo reizi labota %s
@@ -566,6 +563,10 @@ wiki.last_updated=Pēdējo reizi labota %s
settings=Iestatījumi
settings.options=Opcijas
settings.collaboration=Sadarbība
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Tīmekļa āķi
settings.githooks=Git āķi
settings.basic_settings=Pamatiestatījumi
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Apmeklētāji tiks novirzīti uz adresi, kad vi
settings.issues_desc=Iespējot iebūvētu vieglu problēmu sekotāju
settings.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju
settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Jūs varat izmantot <code>{user}{repo}{index}</code> lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram.
settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus
settings.danger_zone=Bīstamā zona
@@ -594,17 +598,15 @@ settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju
settings.transfer_notices_1=- Jūs pazaudēsiet piekļuvi, ja jaunais īpašnieks ir lietotājs.
settings.transfer_notices_2=- Jūs saglabāsiet piekļuvi, ja jaunais īpašnieks ir organizācija un Jūs esat viens no tās īpašniekiem.
settings.transfer_form_title=Lūdzu, ievadiet sekojošu informāciju, lai apstiprinātu šo darbību:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_delete=Dzēst Vikivietnes datus
settings.wiki_delete_desc=Vikivietnes datu dzēšana ir neatgriezeniska. Pārliecinieties vai patiešām to vēlaties.
settings.wiki_delete_notices_1=- Šī darbība dzēsīs un atspējos %s Vikivietni
settings.wiki_deletion_success=Repozitorija Vikivietnes dati tika veiksmīgi izdzēsti.
settings.delete=Dzēst šo repozitoriju
settings.delete_desc=Dzēšot repozitoriju, tā datus vairs nebūs iespējams atgūt. Pirms dzēšanas pārliecinieites vai patiešām vēlaties to darīt.
settings.delete_notices_1=- Šī darbība ir <strong>NEATGRIEZENISKA</strong>.
settings.delete_notices_2=- Šī darbība neatgriezeniski izdzēsīs visus šī repozitorija datus, tai skaitā Git datus, problēmu ziņojumus, komentārus un definētās piekļuves tiesības.
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.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Repozitorijs tika veiksmīgi dzēsts!
settings.update_settings_success=Repozitorija opcijas ir veiksmīgi saglabātas.
settings.transfer_owner=Jaunais īpašnieks
@@ -613,9 +615,9 @@ settings.transfer_succeed=Repozitorija īpašnieks ir veiksmīgi nomainīts.
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.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Dzēst
settings.collaborator_deletion=Līdzstrādnieka dzēšana
settings.collaborator_deletion_desc=Šim lietotājam pēc dzēšanas vairs nebūs sadarbības pieejas šai krātuvei. Vai vēlaties turpināt?
settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
settings.search_user_placeholder=Meklēt lietotāju...
settings.org_not_allowed_to_be_collaborator=Organizāciju nav atļauts pievienot kā līdzstrādnieku.
@@ -688,6 +690,8 @@ diff.show_unified_view=Apvienotais skats
diff.stats_desc=<strong>%d mainītis faili</strong> ar <strong>%d papildinājumiem</strong> un <strong>%d dzēšanām</strong>
diff.bin=BIN
diff.view_file=Parādīt failu
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Laidieni
release.new_release=Jauns laidiens
@@ -915,6 +919,7 @@ auths.enabled=Iespējota
auths.updated=Atjaunināta
auths.auth_type=Autentifikācijas tips
auths.auth_name=Autentifikācijas nosaukums
auths.security_protocol=Security Protocol
auths.domain=Domēns
auths.host=Resursdators
auths.port=Ports
@@ -950,7 +955,7 @@ auths.update=Mainīt autentifikācijas iestatījumus
auths.delete=Dzēst šo autentifikāciju
auths.delete_auth_title=Autentifikācijas dzēšana
auths.delete_auth_desc=Šī autentifikācija tiks dzēsta, vai vēlaties turpināt?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.still_in_used=Daži lietotāji joprojām izmanto šo autentifikācijas veidu. Nepieciešams veikt šo lietotāju konvertāciju vai dzēšanu.
auths.deletion_success=Autentifikācija tika veiksmīgi izdzēsta!
config.server_config=Servera konfigurācija
@@ -1066,8 +1071,8 @@ create_issue=`reģistrēja problēmu <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`slēdza problēmu <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`atkārtoti atvēra problēmu <a href="%s/issues/%s">%s#%[2]s</a>`
create_pull_request=`izveidoja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`aizvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`atkārtoti atvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`sapludināja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="%s">%s</a>

147
conf/locale/locale_nl-NL.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=Kwesties
cancel=Annuleren
[search]
search=Zoeken...
repository=Repository
user=Gebruiker
issue=Probleem
code=Code
[install]
install=Installatie
title=Installatiestappen voor de eerste keer opstarten
@@ -140,6 +133,8 @@ issues.in_your_repos=In uw repositories
[explore]
repos=Repositories
users=Gebruikers
search=Zoeken
[auth]
create_new_account=Maak nieuw account aan
@@ -162,6 +157,7 @@ reset_password=Reset uw wachtwoord
invalid_code=Sorry, uw bevestigingscode is verlopen of niet meer geldig.
reset_password_helper=Klik hier om uw wachtwoord opnieuw in te stellen.
password_too_short=De lengte van uw wachtwoord moet minimaal zes karakters zijn.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Activeer uw account
@@ -224,8 +220,7 @@ org_still_own_repo=De organisatie heeft nog eigendomen op repositories. U moet d
target_branch_not_exist=Doel branch bestaat niet
[user]
change_avatar=Verander uw avatar op Gravatar.com
change_custom_avatar=Wijzig uw avatar in de instellingen
change_avatar=Change your avatar
join_on=Aangemeld op
repositories=repositories
activity=Openbare activiteit
@@ -264,7 +259,7 @@ cancel=Annuleren
enable_custom_avatar=Aangepaste avatar inschakelen
choose_new_avatar=Kies een nieuwe avatar
update_avatar=Avatar instelling bijwerken
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Verwijder huidige avatar
uploaded_avatar_not_a_image=Geüpload bestand is geen afbeelding.
update_avatar_success=Instellingen voor avatar succesvol bijgewerkt.
@@ -355,6 +350,8 @@ readme_helper=Selecteer een sjabloon voor het Leesmij-bestand
auto_init=Initialiseer deze repositorie met de geselecteerde bestanden en sjabloon
create_repo=Nieuwe repository
default_branch=Standaard branch
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Mirror interval(uur)
mirror_address=Kopie-adres
mirror_address_desc=Gelieve noodzakelijke gebruikersgegevens in de adresbalk.
@@ -474,9 +471,9 @@ issues.reopen_comment_issue=Heropen en geef commentaar
issues.create_comment=Reageer
issues.closed_at=`gesloten om <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`heropend om <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at='verwees naar dit probleem vanuit een commit <a id="%[1]s" href="#%[1]s"> %[2]s'</a>
issues.commit_ref_at=`verwees naar dit probleem vanuit een commit <a id="%[1]s" href="#%[1]s"> %[2]s'</a>`
issues.poster=Poster
issues.collaborator=Collaborator
issues.collaborator=Medewerker
issues.owner=Eigenaar
issues.sign_up_for_free=Gratis aanmelden
issues.sign_in_require_desc=om deel te nemen in deze conversatie. Heeft u al een account? <a href="%s">Meld u aan om te reageren</a>
@@ -506,7 +503,7 @@ pulls.nothing_to_compare=Er is niets te vergelijken omdat base en head branches
pulls.has_pull_request=' Er is al een pull-aanvraag tussen deze twee targets: <a href="%[1]s/pulls/%[3]d"> %[2]s #% [3]d</a>'
pulls.create=Pull verzoek aanmaken
pulls.title_desc=wil %[1]d commits van <code>%[2]s</code> samenvoegen met <code>%[3]s</code>
pulls.merged_title_desc=%[1] commits samengevoegd van <code>%[2]s</code> naar <code>%[3]s</code> %[4]s
pulls.merged_title_desc=heeft %[1]d commits samengevoegd van <code>%[2]s</code> naar <code>%[3]s</code> %[4]s
pulls.tab_conversation=Discussie
pulls.tab_commits=Commits
pulls.tab_files=Bestanden gewijzigd
@@ -517,9 +514,9 @@ pulls.data_broken=Omdat informatie over de fork is verwijderd, zijn de gegevens
pulls.is_checking=Controle van conflicten is nog bezig, ververs deze pagina in enkele ogenblikken.
pulls.can_auto_merge_desc=Dit pull-request kan automatisch samengevoegd worden.
pulls.cannot_auto_merge_desc=Dit pull-request kan niet worden gemerged omdat er conflicten zijn.
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
pulls.cannot_auto_merge_helper=Gelieve beide versies manueel samen te voegen om de conflicten op te lossen.
pulls.merge_pull_request=Samenvoegen van pull verzoek
pulls.open_unmerged_pull_exists=`You can't perform reopen operation because there is already an open pull request (#%d) from same repository with same merge information and is waiting for merging.`
pulls.open_unmerged_pull_exists=U kan de bewerking 'heropenen' niet uitvoeren omdat er al een pull-aanvraag (#%d) is van dezelfde repository met dezelfde informatie. Voeg deze eerst samen.
milestones.new=Nieuwe mijlpaal
milestones.open_tab=%d geopend
@@ -557,8 +554,8 @@ wiki.save_page=Pagina opslaan
wiki.last_commit_info=%s heeft deze pagina aangepast %s
wiki.edit_page_button=Bewerken
wiki.new_page_button=Nieuwe pagina
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Verwijder pagina
wiki.delete_page_notice_1=Dit zal pagina <code>"%s"</code> verwijderen. Weet u het zeker?
wiki.page_already_exists=Er bestaat al een wiki-pagina met deze naam.
wiki.pages=Paginas
wiki.last_updated=Laatst bijgewerkt: %s
@@ -566,45 +563,50 @@ wiki.last_updated=Laatst bijgewerkt: %s
settings=Instellingen
settings.options=Opties
settings.collaboration=Samenwerking
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git-hooks
settings.basic_settings=Basis instellingen
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.change_reponame_prompt=Deze verandering zal gevolgen hebben voor hoe links zich verhouden tot de repository.
settings.advanced_settings=Geavanceerde opties
settings.wiki_desc=Enable wiki to allow people write documents
settings.wiki_desc=Wiki inschakelen, om mensen documenten te laten schrijven
settings.use_external_wiki=Externe wiki gebruiken
settings.external_wiki_url=Externe wiki-URL
settings.external_wiki_url_desc=Bezoekers worden doorgestuurd naar de URL als ze op het tabblad klikken.
settings.issues_desc=Ingebouwde compacte issuetracker inschakelen
settings.use_external_issue_tracker=Externe issuetracker gebruiken
settings.tracker_url_format=URL-formaat externe issuetracker
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.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=U kan de aanduidingen <code>{user} {repo} {index}</code> gebruiken voor de gebruikersnaam, de naam van de repository en de lijst van open tickets.
settings.pulls_desc=Schakel 'pull request' in om publieke bijdragen te mogelijk te maken
settings.danger_zone=Gevaren zone
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
settings.convert=Converteren naar gewone repository
settings.convert_desc=U kunt deze mirror converteren naar een gewone repository. Dit kan niet ongedaan worden gemaakt.
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
settings.convert_notices_1=- Deze operatie zet de mirror repository om in een gewone repository en dit kan niet ongedaan gemaakt worden.
settings.convert_confirm=Conversie bevestigen
settings.convert_succeed=Deze repository is geconverteerd naar een normale repository.
settings.transfer=Eigendom overdragen
settings.transfer_desc=Draag deze repo over aan een andere gebruiker of een organisatie waar u beheerders rechten heeft.
settings.transfer_notices_1=- You will lose access if new owner is a individual user.
settings.transfer_notices_2=- You will conserve access if new owner is an organization and if you're one of the owners.
settings.transfer_form_title=Please enter following information to confirm your operation:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.transfer_notices_1=- U verliest toegang als de nieuwe gebruiker een individuele gebruiker is.
settings.transfer_notices_2=- U behoudt toegang indien de nieuwe eigenaar een organisatie is en U één van de eigenaren van de organisatie bent.
settings.transfer_form_title=Voer de volgende informatie in om de bewerking te bevestigen:
settings.wiki_delete=Wiki gegevens verwijderen
settings.wiki_delete_desc=Als U wiki informatie wist gaat deze onherroepelijk verloren. Bent U zeker?
settings.wiki_delete_notices_1=- Deze operatie wist de wiki voor %s en schakelt de wiki uit
settings.wiki_deletion_success=De repository met wiki data is succesvol gewist.
settings.delete=Verwijder deze repositorie
settings.delete_desc=Als u eenmaal een repositorie verwijderd is er geen weg terug. Gelieve zeker te zijn van uw acties.
settings.delete_notices_1=- This operation <strong>CANNOT</strong> be undone.
settings.delete_notices_2=- This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
settings.delete_notices_fork_1=- If this repository is public, all forks will become 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.delete_notices_1=- Deze bewerking kan <strong>NIET</strong> ongedaan gemaakt worden.
settings.delete_notices_2=- Deze bewerking verwijdert permanent alle informatie van deze repository met inbegrip van Git gegevens, tickets, opmerkingen en de toegang van medewerkers.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Repository is succesvol verwijderd!
settings.update_settings_success=Repositorie instellingen zijn succesvol bijgewerkt.
settings.transfer_owner=Nieuwe eigenaar
@@ -613,21 +615,21 @@ settings.transfer_succeed=Eigendom repositorie succesvol overgedragen
settings.confirm_delete=Bevestig verwijdering
settings.add_collaborator=Nieuwe medewerker toevoegen
settings.add_collaborator_success=medewerker is toegevoegd.
settings.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Verwijderen
settings.collaborator_deletion=Verwijder Medewerker
settings.collaborator_deletion_desc=Deze gebruiker zal niet langer toegang hebben tot deze repository. Wilt U doorgaan?
settings.remove_collaborator_success=medewerker is verwijderd.
settings.search_user_placeholder=Zoek gebruiker...
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
settings.org_not_allowed_to_be_collaborator=De organisatie kan niet toegevoegd worden als medewerker.
settings.user_is_org_member=Gebruiker is lid van de organisatie die als een medewerker kan niet worden toegevoegd.
settings.add_webhook=Webhook toevoegen
settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvangen wanneer bepaalde gebeurtenissen op Gogs plaatsvinden. Wanneer de opgegeven gebeurtenissen plaatsvinden, sturen we een POST-aanvraag naar elk van de URL's die u opgeeft. Meer informatie vindt u in onze <a target="_blank" href="%s"> Webhooks gids</a>.
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_desc=Verwijderen van deze webhook zal de informatie en alle geschiedenis verwijderen. Wilt u doorgaan?
settings.webhook_deletion_success=Webhook is succesvol verwijderd!
settings.webhook.test_delivery=Test-bezorging
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 take few seconds before it shows up in the delivery history.
settings.webhook.test_delivery_desc=Stuur een nep push bericht om de webhook te testen
settings.webhook.test_delivery_success=De test webhook is toegevoegd aan de wachtrij. Het kan enkele seconden duren voor deze in de geschiedenis wordt weergegeven.
settings.webhook.request=Verzoek
settings.webhook.response=Antwoord
settings.webhook.headers=Headers
@@ -667,7 +669,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 keys have read-only access. They are not the same as personal account SSH keys.
settings.deploy_key_desc=Sleutels voor uitrol hebben enkel leesrechten. Ze zijn niet dezelfde als de SSH sleutels van persoonlijke accounts.
settings.no_deploy_keys=U hebt nog geen deploy sleutels toegevoegd.
settings.title=Titel
settings.deploy_key_content=Inhoud
@@ -683,11 +685,13 @@ diff.parent=bovenliggende
diff.commit=commit
diff.data_not_available=Diff gegevens niet beschikbaar.
diff.show_diff_stats=Toon Diff Stats
diff.show_split_view=Split View
diff.show_unified_view=Unified View
diff.show_split_view=Zij-aan-zij weergave
diff.show_unified_view=Gecombineerde weergave
diff.stats_desc=<strong>%d gewijzigde bestanden</strong> met <strong>toevoegingen van %d</strong> en <strong>%d verwijderingen</strong>
diff.bin=BIN
diff.view_file=Bestand weergeven
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Releases
release.new_release=Nieuwe release
@@ -697,7 +701,7 @@ release.stable=Stabiel
release.edit=bewerken
release.ahead=<strong>%d</strong> aanpassingen aan %s sinds deze versie
release.source_code=Broncode
release.new_subheader=Publish releases to iterate product.
release.new_subheader=Publiceer releases om te itereren.
release.edit_subheader=Een gedetailleerd changelog helpt gebruikers te begrijpen wat er is verbeterd in deze release.
release.tag_name=Tagnaam
release.target=Doel
@@ -715,7 +719,7 @@ release.save_draft=Concept opslaan
release.edit_release=Release bewerken
release.delete_release=Deze release verwijderen
release.deletion=Release verwijderen
release.deletion_desc=Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_desc=Als deze release verwijdert, worden de bijbehorende Git tag ook gewist. Wilt u doorgaan?
release.deletion_success=Release is verwijderd!
release.tag_name_already_exist=Versie met deze naam bestaat al.
release.downloads=Downloads
@@ -749,8 +753,8 @@ settings.website=Website
settings.location=Locatie
settings.update_settings=Instellingen bijwerken
settings.update_setting_success=Organisatie instellingen zijn succesvol bijgewerkt.
settings.change_orgname_prompt=This change will affect how links relate to the organization.
settings.update_avatar_success=Organization avatar setting has been updated successfully.
settings.change_orgname_prompt=Deze verandering beinvloed de verhouding tussen links en de organisatie.
settings.update_avatar_success=Organisatie avatar-instellingen zijn succesvol gewijzigd.
settings.delete=Verwijder organisatie
settings.delete_account=Verwijder deze organisatie
settings.delete_prompt=Deze actie zal de origanisatie permanent verwijderen. U kunt dit <strong>NIET</strong> terug draaien!
@@ -759,7 +763,7 @@ settings.delete_org_title=Verwijderen organsiatie
settings.delete_org_desc=Deze organisatie zal permanent worden verwijderd, wilt u doorgaan?
settings.hooks_desc=Een webhook toevoegen die door <strong>alle repositories</strong> in deze organisatie getriggerd kan worden.
members.membership_visibility=Membership Visibility:
members.membership_visibility=Zichtbaarheid lidmaatschap:
members.public=Openbaar
members.public_helper=maak prive
members.private=Prive
@@ -769,7 +773,7 @@ members.owner=Eigenaar
members.member=Lid
members.remove=Verwijderen
members.leave=Verlaat
members.invite_desc=Add a new member to %s:
members.invite_desc=Voeg nieuw lid toe aan %s:
members.invite_now=Nu uitnodigen
teams.join=Lid worden
@@ -825,16 +829,16 @@ dashboard.delete_inactivate_accounts=Verwijder alle inactieve accounts
dashboard.delete_inactivate_accounts_success=Alle inactivering van rekeningen hebben verwijderd.
dashboard.delete_repo_archives=Verwijderen van alle repositories archieven
dashboard.delete_repo_archives_success=Alle repositories archieven hebben verwijderd.
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=Verwijder alle repositories zonder Git files
dashboard.delete_missing_repos_success=Alle repositories zonder Git files verwijderd.
dashboard.git_gc_repos=Garbage collectie uitvoeren
dashboard.git_gc_repos_success=Garbage collectie met succes uitgevoerd.
dashboard.resync_all_sshkeys=Herschrijf '.ssh/authorized_keys' (Let op: alle sleutels die niet van Gogs zijn zullen verloren gaan!)
dashboard.resync_all_sshkeys_success=Alle publieke sleutels zijn herschreven.
dashboard.resync_all_update_hooks=Herschrijf alle repositorie-hooks (nodig als de configuratie bestandslocatie is gewijzigd)
dashboard.resync_all_update_hooks_success=Alle repositorie-hooks zijn herschreven.
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
dashboard.reinit_missing_repos=Alle repositories zonder Git files opnieuw initialiseren
dashboard.reinit_missing_repos_success=Alle repositories zonder Git files zijn succesvol opnieuw geinitializeerd.
dashboard.server_uptime=Uptime server
dashboard.current_goroutine=Huidige Goroutines
@@ -879,11 +883,11 @@ users.edit=Bewerken
users.auth_source=Authenticatiebron
users.local=Lokaal
users.auth_login_name=Authenticatie-loginnaam
users.password_helper=Leave it empty to remain unchanged.
users.password_helper=Laat leeg om ongewijzigd te blijven.
users.update_profile_success=Profiel is succesvol bijgewerkt.
users.edit_account=Bewerk account
users.max_repo_creation=Maximum Repository Creation Limit
users.max_repo_creation_desc=(Set -1 to use global default limit)
users.max_repo_creation=Maximum-limiet voor aanmaken van repositories
users.max_repo_creation_desc=(Zet op -1 om de globale limiet te gebruiken)
users.is_activated=Dit account is geactiveerd
users.is_admin=Dit account heeft beheerdersrechten
users.allow_git_hook=Deze account beschikt over machtigingen voor het maken van Git haken
@@ -907,7 +911,7 @@ repos.watches=Volgers
repos.stars=Sterren
repos.issues=Kwesties
auths.auth_manage_panel=Authentication Manage Panel
auths.auth_manage_panel=Authenticatie-beheer paneel
auths.new=Nieuwe bron toevoegen
auths.name=Naam
auths.type=Type
@@ -915,20 +919,21 @@ auths.enabled=Ingeschakeld
auths.updated=Bijgewerkt
auths.auth_type=Authenticatietype
auths.auth_name=Authenticatienaam
auths.security_protocol=Security Protocol
auths.domain=Domein
auths.host=Host
auths.port=Poort
auths.bind_dn=Binden DN
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.bind_password=Bind wachtwoord
auths.bind_password_helper=Opgelet: Dit wachtwoord wordt opgeslagen als leesbare tekst. Gebruik geen account met verhoogde rechten.
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_username=Gebruikersnaam attribuut
auths.attribute_username_placeholder=Laat leeg om het login veld van het formulier te gebruiken als gebruikersnaam.
auths.attribute_name=Voornaam attribuut
auths.attribute_surname=Achternaam attribuut
auths.attribute_mail=E-mail attribuut
auths.attributes_in_bind=Fetch attributes in Bind DN context
auths.attributes_in_bind=Verkrijg attributes van de Bind DN context
auths.filter=Gebruikersfilter
auths.admin_filter=Beheerdersfilter
auths.ms_ad_sa=MS Ad SA
@@ -936,20 +941,20 @@ auths.smtp_auth=SMTP-authenticatietype
auths.smtphost=SMTP host
auths.smtpport=SMTP poort
auths.allowed_domains=Toegelaten domeinen
auths.allowed_domains_helper=Leave it empty to not restrict any domains. Multiple domains should be separated by comma ','.
auths.allowed_domains_helper=Laat dit leeg om geen enkel domein te beperken. Meerdere domeinen moeten door een komma (',') gescheiden worden.
auths.enable_tls=Activeer TLS-encryptie
auths.skip_tls_verify=TLS-verificatie overslaan
auths.pam_service_name=PAM servicenaam
auths.enable_auto_register=Activeer automatische registratie
auths.tips=Tips
auths.edit=Edit Authentication Setting
auths.edit=Verificatie-instelling bewerken
auths.activated=Deze autorisatiemethode is geactiveerd
auths.new_success=New authentication '%s' has been added successfully.
auths.update_success=Authentication setting has been updated successfully.
auths.new_success=Nieuwe authenticatie '%s' werd toegevoegd.
auths.update_success=Authenticatie instellingen zijn succesvol gewijzigd.
auths.update=Authenticatie-instellingen bijwerken
auths.delete=Deze authenticatiewijze verwijderen
auths.delete_auth_title=Authentication Deletion
auths.delete_auth_desc=This authentication is going to be deleted, do you want to continue?
auths.delete_auth_title=Authenticatie verwijderd
auths.delete_auth_desc=Deze authenticatie zal verwijderd worden, wil je verdergaan?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success=Authentication has been deleted successfully!
@@ -1045,13 +1050,13 @@ monitor.start=Starttijd
monitor.execute_time=Uitvoertijd
notices.system_notice_list=Systeem aankondigingen
notices.view_detail_header=View Notice Detail
notices.view_detail_header=Bekijk bericht details
notices.actions=Acties
notices.select_all=Alles selecteren
notices.deselect_all=Alles deselecteren
notices.inverse_selection=Selectie omkeren
notices.delete_selected=Selectie verwijderen
notices.delete_all=Delete All Notices
notices.delete_all=Verwijder alle berichten
notices.type=Type
notices.type_1=Opslagplaats
notices.desc=Beschrijving

109
conf/locale/locale_pl-PL.ini Executable file → Normal file
View File

@@ -38,19 +38,12 @@ settings=Ustawienia
your_profile=Twój profil
your_settings=Twoje ustawienia
activities=Activities
activities=Aktywności
pull_requests=Oczekujące zmiany
issues=Problemy
cancel=Anuluj
[search]
search=Wyszukiwanie...
repository=Repozytorium
user=Użytkownik
issue=Problem
code=Kod
[install]
install=Instalacja
title=Kroki instalacyjne dla pierwszego uruchomienia
@@ -86,8 +79,8 @@ http_port=Port HTTP
http_port_helper=Numer portu na którym aplikacja jest dostępna.
app_url=Adres URL aplikacji
app_url_helper=To wpłynie na adresy klonowania HTTP/HTTPS i w wiadomościach e-mail.
log_root_path=Log Path
log_root_path_helper=Directory to write log files to.
log_root_path=Ścieżka dla logów
log_root_path_helper=Katalog do zapisu logów.
optional_title=Ustawienia opcjonalne
email_title=Ustawienia serwera e-mail
@@ -124,7 +117,7 @@ run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -
save_config_failed=Nie udało się zapisać konfiguracji: %v
invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
install_success=Cześć! Cieszymy się, że wybierałeś Gogs, baw się dobrze.
invalid_log_root_path=Log root path is invalid: %v
invalid_log_root_path=Ścieżka dla logów jest niepoprawna: %v
[home]
uname_holder=Nazwa użytkownika lub e-mail
@@ -140,6 +133,8 @@ issues.in_your_repos=W Twoich repozytoriach
[explore]
repos=Repozytoria
users=Użytkownicy
search=Wyszukiwanie
[auth]
create_new_account=Załóż nowe konto
@@ -162,6 +157,7 @@ reset_password=Resetowanie hasła
invalid_code=Niestety, Twój kod potwierdzający wygasł lub jest nieprawidłowy.
reset_password_helper=Kliknij tutaj, aby zresetować hasło
password_too_short=Długość hasła nie może być mniejsza niż 6 znaków.
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=Prosimy aktywować swoje konto
@@ -224,8 +220,7 @@ org_still_own_repo=Ta organizacja dalej jest właścicielem repozytorium, które
target_branch_not_exist=Gałąź docelowa nie istnieje.
[user]
change_avatar=Zmień swój avatar na gravatar.com
change_custom_avatar=Zmień awatar w ustawieniach
change_avatar=Change your avatar
join_on=Dołączył
repositories=Repozytoria
activity=Publiczna aktywność
@@ -264,7 +259,7 @@ cancel=Anuluj
enable_custom_avatar=Włącz niestandardowe awatary
choose_new_avatar=Wybierz nowy avatar
update_avatar=Zaktualizuj ustawienia awatara
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Usuń obecny Avatar
uploaded_avatar_not_a_image=Załadowany plik nie jest obrazem.
update_avatar_success=Ustawienia awatarów zostały pomyślnie zaktualizowane.
@@ -355,6 +350,8 @@ readme_helper=Wybierz szablon readme
auto_init=Zainicjuj to repozytorium używając wybranych plików i szablonu
create_repo=Utwórz repozytorium
default_branch=Domyślna gałąź
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Częstotliwość kopiowania (godziny)
mirror_address=Adres kopii lustrzanej
mirror_address_desc=Proszę podać wymagane poświadczenia użytkownika w adresie.
@@ -476,7 +473,7 @@ issues.closed_at=`zamyka <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`otwiera ponownie <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`wspomina ten problem w commicie <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster=Autor
issues.collaborator=Collaborator
issues.collaborator=Współpracownik
issues.owner=Właściciel
issues.sign_up_for_free=Zarejestruj się za darmo
issues.sign_in_require_desc=do przyłączenia się do tej rozmowy. Masz już konto? <a href="%s">Zaloguj się by komentować</a>
@@ -557,8 +554,8 @@ wiki.save_page=Zapisz stronę
wiki.last_commit_info=%s edytuje tę stronę %s
wiki.edit_page_button=Edytuj
wiki.new_page_button=Nowa strona
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Usuń stronę
wiki.delete_page_notice_1=Strona zostanie usunięta <code>"%s"</code>. Bądź ostrożny.
wiki.page_already_exists=Strona Wiki o tej samej nazwie już istnieje.
wiki.pages=Strony
wiki.last_updated=Ostatnia aktualizacja %s
@@ -566,6 +563,10 @@ wiki.last_updated=Ostatnia aktualizacja %s
settings=Ustawienia
settings.options=Opcje
settings.collaboration=Współpraca
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=Webhooki
settings.githooks=Hooki Git
settings.basic_settings=Ustawienia podstawowe
@@ -580,31 +581,32 @@ settings.external_wiki_url_desc=Odwiedzający zostaną przekierowani do adresu U
settings.issues_desc=Włącz wbudowany lekki system zgłaszania problemów
settings.use_external_issue_tracker=Użyj zewnętrznego systemu zgłaszania problemów
settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Symbole zastępcze <code>{user} {repo} {index}</code> mogą być użyte dla nazwy użytkownika, nazwy repozytorium i numeru problemu.
settings.pulls_desc=Włącz obsługę pull request, aby akceptować publiczny wkład
settings.danger_zone=Strefa niebezpieczeństwa
settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie.
settings.convert=Convert To Regular Repository
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
settings.convert_confirm=Confirm Conversion
settings.convert_succeed=Repository has been converted to regular type successfully.
settings.convert=Konwersja na repozytorium regularne
settings.convert_desc=Możesz przekonwertować ten mirror na repozytorium regularne. Ta czynność nie może być odwrócona.
settings.convert_notices_1=- Ta operacja przekonwertuje mirror tego repozytorium na repozytorium regularne. Ta czynność nie może być odwrócona.
settings.convert_confirm=Potwierdź konwers
settings.convert_succeed=Typ repozytorium został zamieniony na regularne.
settings.transfer=Przeniesienie własności
settings.transfer_desc=Przenieś to repozytorium do innego użytkownika lub organizacji gdzie masz uprawnienia administratora.
settings.transfer_notices_1=- Stracisz dostęp jeśli nowy właściciel jest indywidualnym użytkownikiem.
settings.transfer_notices_2=- Zachowasz dostęp jeśli nowym właścicielem jest organizacja, której jesteś współwłaścicielem.
settings.transfer_form_title=Proszę wpisz co następuje w celu potwierdzenia operacji:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_delete=Kasowanie danych Wiki
settings.wiki_delete_desc=Usunięcie danych z wiki jest nieodwracalne. Bądź ostrożny.
settings.wiki_delete_notices_1=- To usunie i wyłączy wiki dla %s
settings.wiki_deletion_success=Dane wiki zostały usunięte.
settings.delete=Usuń to repozytorium
settings.delete_desc=Po usunięciu repozytorium nie ma odwrotu. Upewnij się, że tego chcesz.
settings.delete_notices_1=- Ta operacja <strong>NIE MOŻE</strong> zostać cofnięta.
settings.delete_notices_2=- Ta operacja trwale usunie wszystko z tego repozytorium, w tym dane Git, problemy, komentarze i dostęp dla współpracowników.
settings.delete_notices_fork_1=- Jeśli to repozytorium jest publiczne, wszystkie forki staną się niezależne.
settings.delete_notices_fork_2=- Jeśli to repozytorium jest prywatne, forki zostaną usunięte wraz z usunięciem tego repozytorium.
settings.delete_notices_fork_3=- Jeśli chcesz zachować wszystkie forki po usunięciu, proszę najpierw uczyń to repozytorium publicznym.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=Repozytorium zostało pomyślnie usunięte!
settings.update_settings_success=Opcje repozytorium zostały pomyślnie zaktualizowane.
settings.transfer_owner=Nowy właściciel
@@ -613,12 +615,12 @@ settings.transfer_succeed=Własność repozytorium została przeniesiona pomyśl
settings.confirm_delete=Potwierdź usunięcie
settings.add_collaborator=Dodaj nowego współpracownika
settings.add_collaborator_success=Został dodany nowy współpracownik.
settings.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Usuń
settings.collaborator_deletion=Usunięcie współpracownika
settings.collaborator_deletion_desc=Ten użytkownik nie będzie miał dostępu współpracownika do repozytorium. Czy chcesz kontynuować?
settings.remove_collaborator_success=Współpracownik został usunięty.
settings.search_user_placeholder=Szukaj użytkownika...
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika.
settings.user_is_org_member=Użytkownik jest członkiem organizacji, który nie może być dodany jako współpracownik.
settings.add_webhook=Dodaj webhooka
settings.hooks_desc=Webooki działają tak jak proste wywołania HTTP POST. Jeśli cokolwiek zdarzy się w Gogs, wyślemy powiadomienie do wybranego hosta. Więcej informacji można znaleźć w <a target="_blank" href="%s">przewodniku webhooków</a>.
@@ -688,6 +690,8 @@ diff.show_unified_view=Zunifikowany widok
diff.stats_desc=<strong>%d zmienionych plików</strong> z <strong>%d dodań</strong> i <strong>%d usunięć</strong>
diff.bin=BIN
diff.view_file=Wyświetl plik
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Wydania
release.new_release=Nowe wydanie
@@ -915,6 +919,7 @@ auths.enabled=Włączono
auths.updated=Zaktualizowano
auths.auth_type=Typ uwierzytelniania
auths.auth_name=Nazwa uwierzytelniania
auths.security_protocol=Security Protocol
auths.domain=Domena
auths.host=Host
auths.port=Port
@@ -928,7 +933,7 @@ auths.attribute_username_placeholder=Zostaw puste aby użyć wartości podanej p
auths.attribute_name=Atrybut imienia
auths.attribute_surname=Atrybut nazwiska
auths.attribute_mail=Atrybut e-mail
auths.attributes_in_bind=Fetch attributes in Bind DN context
auths.attributes_in_bind=Pobierz atrybuty w kontekście Bind DN
auths.filter=Filtr użytkownika
auths.admin_filter=Filtr administratora
auths.ms_ad_sa=Ms Ad SA
@@ -950,7 +955,7 @@ auths.update=Aktualizuj ustawienia uwierzytelniania
auths.delete=Usuń to uwierzytelnienie
auths.delete_auth_title=Usunięcie uwierzytelnienia
auths.delete_auth_desc=To uwierzytelnienie zostanie usunięte, czy chcesz kontynuować?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.still_in_used=Ten rodzaj autentykacji jest wciąż wykorzystywany przez niektórych użytkowników. Usuń lub przekonwertuj użytkowników, aby wykorzystywali inny typ logowania.
auths.deletion_success=Uwierzytelnienie zostało usunięte pomyślnie!
config.server_config=Konfiguracja serwera
@@ -968,17 +973,17 @@ config.log_file_root_path=Ścieżka plików dziennika
config.script_type=Typ skryptu
config.reverse_auth_user=Użytkownik dostarczony przez odwrotne proxy
config.ssh_config=SSH Configuration
config.ssh_enabled=Enabled
config.ssh_start_builtin_server=Start Builtin Server
config.ssh_domain=Domain
config.ssh_config=Konfiguracja SSH
config.ssh_enabled=Aktywne
config.ssh_start_builtin_server=Uruchom serwer wbudowany
config.ssh_domain=Domena
config.ssh_port=Port
config.ssh_listen_port=Listen Port
config.ssh_root_path=Root Path
config.ssh_key_test_path=Key Test Path
config.ssh_keygen_path=Keygen ('ssh-keygen') Path
config.ssh_minimum_key_size_check=Minimum Key Size Check
config.ssh_minimum_key_sizes=Minimum Key Sizes
config.ssh_listen_port=Port nasłuchu
config.ssh_root_path=Ścieżka katalogu głównego
config.ssh_key_test_path=Ścieżka klucza testowego
config.ssh_keygen_path=Ścieżka generatora ('ssh-keygen')
config.ssh_minimum_key_size_check=Sprawdzanie minimalnej długości klucza
config.ssh_minimum_key_sizes=Minimalne rozmiary kluczy
config.db_config=Konfiguracja bazy danych
config.db_type=Typ
@@ -1009,9 +1014,9 @@ config.mailer_disable_helo=Wyłącz HELO
config.mailer_name=Nazwa
config.mailer_host=Host
config.mailer_user=Użytkownik
config.send_test_mail=Send Test Email
config.test_mail_failed=Fail to send test email to '%s': %v
config.test_mail_sent=Test email has been sent to '%s'.
config.send_test_mail=Wyślij email testowy
config.test_mail_failed=Nieudane wysłanie wiadomości email do '%s': %v
config.test_mail_sent=Testowa wiadomość email została wysłana do '%s'.
config.oauth_config=Konfiguracja OAuth
config.oauth_enabled=Aktywne
config.cache_config=Konfiguracja cache
@@ -1063,11 +1068,11 @@ create_repo=tworzy repozytorium <a href="%s">%s</a>
rename_repo=zmienia nazwę repozytorium <code>%[1]s</code> na <a href="%[2]s">%[3]s</a>
commit_repo=wypycha do <a href="%[1]s/src/%[2]s">%[3]s</a> w <a href="%[1]s">%[4]s</a>
create_issue=`zgłasza problem <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`zamknięcie problemu <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`ponowne otwarcie problemu <a href="%s/issues/%s">%s#%[2]s</a>`
create_pull_request=`tworzy pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`zamknięcie pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`ponowne otwarcie pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
comment_issue=`komentuje problem <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`scala pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=przenosi repozytorium <code>%s</code> do <a href="%s">%s</a>

63
conf/locale/locale_pt-BR.ini Executable file → Normal file
View File

@@ -11,7 +11,7 @@ register=Registrar
website=Site
version=Versão
page=Página
template=Modelo
template=Template
language=Idioma
create_new=Criar...
user_profile_and_more=Perfil do usuário e configurações
@@ -44,13 +44,6 @@ issues=Problemas
cancel=Cancelar
[search]
search=Pesquisar...
repository=Repositório
user=Usuário
issue=Problema
code=Código
[install]
install=Instalação
title=Etapas de instalação para primeira execução
@@ -140,6 +133,8 @@ issues.in_your_repos=Em seus repositórios
[explore]
repos=Repositórios
users=Usuários
search=Pesquisar
[auth]
create_new_account=Criar Nova Conta
@@ -162,6 +157,7 @@ reset_password=Redefinir Sua Senha
invalid_code=Desculpe, seu código de confirmação expirou ou não é válido.
reset_password_helper=Clique aqui para redefinir sua senha
password_too_short=O comprimento da senha não pode ser menor que 6.
non_local_account=Não é possível mudar a senha de contas não-locais pelo Gogs.
[mail]
activate_account=Por favor, ative sua conta
@@ -224,8 +220,7 @@ org_still_own_repo=Esta organização ainda tem a propriedade do repositório, v
target_branch_not_exist=O branch de destino não existe.
[user]
change_avatar=Altere o seu avatar em gravatar.com
change_custom_avatar=Altere seu avatar nas configurações
change_avatar=Mude seu avatar
join_on=Inscreveu-se em
repositories=Repositórios
activity=Atividade Pública
@@ -264,7 +259,7 @@ cancel=Cancelar
enable_custom_avatar=Habilitar Avatar Customizado
choose_new_avatar=Escolha um novo avatar
update_avatar=Atualizar configuração de Avatar
delete_current_avatar=Delete Current Avatar
delete_current_avatar=Excluir o Avatar atual
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
update_avatar_success=Sua configuração de avatar foi atualizada com sucesso.
@@ -355,6 +350,8 @@ readme_helper=Selecione um modelo de leia-me
auto_init=Inicializar este repositório com os arquivos selecionados e modelo
create_repo=Criar Repositório
default_branch=Branch padrão
mirror_prune=Varrer
mirror_prune_desc=Remova quaisquer referências que não existem mais no remote
mirror_interval=Intervalo de Espelho (hora)
mirror_address=Endereço do espelho
mirror_address_desc=Por favor, inclua as credenciais do usuário necessários no endereço.
@@ -476,7 +473,7 @@ issues.closed_at=`fechado em <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`reaberto em <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`citou este problema em um commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster=Autor
issues.collaborator=Collaborator
issues.collaborator=Colaboradores
issues.owner=Proprietário
issues.sign_up_for_free=Cadastre-se gratuitamente
issues.sign_in_require_desc=para participar nesta conversa. Já tem uma conta? <a href="%s">Faça login para comentar</a>
@@ -557,8 +554,8 @@ wiki.save_page=Salvar página
wiki.last_commit_info=%s editou esta página %s
wiki.edit_page_button=Editar
wiki.new_page_button=Nova página
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=Excluir Página
wiki.delete_page_notice_1=Isto irá apagar a página <code>"%s"</code>. Por favor, certifique-se.
wiki.page_already_exists=já existe uma página de wiki com o mesmo nome.
wiki.pages=Páginas
wiki.last_updated=Última atualização %s
@@ -566,11 +563,15 @@ wiki.last_updated=Última atualização %s
settings=Configurações
settings.options=Opções
settings.collaboration=Colaboração
settings.collaboration.admin=Administrador
settings.collaboration.write=Escrita
settings.collaboration.read=Leitura
settings.collaboration.undefined=Indefinido
settings.hooks=Webhooks
settings.githooks=Hooks do Git
settings.basic_settings=Configurações Básicas
settings.site=Site Oficial
settings.update_settings=Configurações de Atualização
settings.update_settings=Atualizar configurações
settings.change_reponame_prompt=Este mudanças vai afetar os links para este repositório.
settings.advanced_settings=Configurações avançadas
settings.wiki_desc=Habilitar o wiki para permitir que as pessoas escrevam documentos
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Os visitantes serão redirecionados para a URL q
settings.issues_desc=Habilitar gerenciamento de "problemas" nativo
settings.use_external_issue_tracker=Usar issue tracker externo
settings.tracker_url_format=Formato de URL do issue tracker externo
settings.tracker_issue_style=Estilo de nome de issue tracker externo:
settings.tracker_issue_style.numeric=Numérico <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alfanumérico <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=Você pode usar o espaço reservado <code>{user} {repo} {index}</code> para o nome do usuário, índice de nome e a questão do repositório.
settings.pulls_desc=Habilitar pull requests para aceitar contribuições públicas
settings.danger_zone=Zona de Perigo
@@ -594,17 +598,15 @@ settings.transfer_desc=Transferir este repositório para outro usuário ou para
settings.transfer_notices_1=- Você vai perder acesso se o novo dono for um usuário individual.
settings.transfer_notices_2=- Você vai continuar tendo acesso se o novo dono é uma organização e você é um dos membros.
settings.transfer_form_title=Informe a seguinte informação para confirmar a sua operação:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_delete=Apagar dados do Wiki
settings.wiki_delete_desc=Uma vez que você apague os dados da wiki, não há volta. Por favor, certifique-se.
settings.wiki_delete_notices_1=- Isso irá excluir e desativar o wiki para %s
settings.wiki_deletion_success=Dados de wiki do repositório foram deletados com sucesso.
settings.delete=Deletar Este Repositório
settings.delete_desc=Uma vez que você deleta um repositório, não tem volta. Por favor, tenha certeza.
settings.delete_notices_1=-Esta operação <strong>NÃO PODERÁ</strong> ser desfeita.
settings.delete_notices_2=- Esta operação irá apagar permanentemente o tudo deste repositório, incluindo os dados do Git, problemas, comentários e acessos dos colaboradores.
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.delete_notices_fork_1=-Todos os forks se tornarão independentes após a exclusão.
settings.deletion_success=Repositório excluído com sucesso!
settings.update_settings_success=As opções do repositório foram atualizadas com sucesso.
settings.transfer_owner=Novo Dono
@@ -613,9 +615,9 @@ settings.transfer_succeed=A posse do repositório foi transferido com sucesso.
settings.confirm_delete=Confirmar Deleção
settings.add_collaborator=Adicionar um Novo Colaborador
settings.add_collaborator_success=O novo colaborador foi adicionado.
settings.delete_collaborator=Delete
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.delete_collaborator=Deletar
settings.collaborator_deletion=Exclusão de colaborador
settings.collaborator_deletion_desc=Este usuário não terá mais acesso de colaboração neste repositório após a deleção. Você quer continuar?
settings.remove_collaborator_success=O colaborador foi removido.
settings.search_user_placeholder=Pesquisar usuário...
settings.org_not_allowed_to_be_collaborator=Organização não tem permissão para ser adicionada como um colaborador.
@@ -688,6 +690,8 @@ diff.show_unified_view=Visão unificada
diff.stats_desc=<strong> %d arquivos alterados</strong> com <strong>%d adições</strong> e <strong>%d exclusões</strong>
diff.bin=BIN
diff.view_file=Ver Arquivo
diff.file_supressed=Diff do arquivo suprimido porque é muito extenso
diff.too_many_files=Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff
release.releases=Versões
release.new_release=Nova Versão
@@ -763,7 +767,7 @@ 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.private_helper=tornar público
members.member_role=Categoria de membro:
members.owner=Dono
members.member=Membro
@@ -915,6 +919,7 @@ auths.enabled=Habilitado
auths.updated=Atualizado
auths.auth_type=Tipo de autenticação
auths.auth_name=Nome da autenticação
auths.security_protocol=Protocolo de segurança
auths.domain=Domínio
auths.host=Host
auths.port=Porta
@@ -950,7 +955,7 @@ auths.update=Atualizar a configuração da autenticação
auths.delete=Excluir esta autenticação
auths.delete_auth_title=Exclusão da autenticação
auths.delete_auth_desc=Esta autenticação esta prestes a ser deletada, deseja continuar?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.still_in_used=Esta autenticação ainda é usada por alguns usuários. Por favor delete ou converta esses usuários para outro tipo de login primeiro.
auths.deletion_success=Autenticação deletada com sucesso!
config.server_config=Configuração do Servidor
@@ -1066,8 +1071,8 @@ create_issue=`questão aberta <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`questão fechada <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`questão reaberta <a href="%s/issues/%s">%s#%[2]s</a>`
create_pull_request=`criou o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`fechou o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`reabriu o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
comment_issue=`comentou sobre a questão <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`mesclou o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=repositório transferido de <code>%s</code> para <a href="%s">%s</a>

37
conf/locale/locale_ru-RU.ini Executable file → Normal file
View File

@@ -1,4 +1,4 @@
app_desc=Удобная служба для собственного Git-репозитория, написанная на языке Go
app_desc=Удобная служба для собственного Git-репозитория
home=Главная
dashboard=Панель управления
@@ -14,7 +14,7 @@ page=Страница
template=Шаблон
language=Язык
create_new=Создать...
user_profile_and_more=Профиль и остальное
user_profile_and_more=Профиль пользователя и прочее
signed_in_as=Вы вошли как
username=Имя пользователя
@@ -44,13 +44,6 @@ issues=Задачи
cancel=Отмена
[search]
search=Поиск...
repository=Репозиторий
user=Пользователь
issue=Задача
code=Код
[install]
install=Установка
title=Установочные шаги для первого запуска
@@ -140,6 +133,8 @@ issues.in_your_repos=В ваших репозиториях
[explore]
repos=Репозитории
users=Пользователи
search=Поиск
[auth]
create_new_account=Создать новый аккаунт
@@ -162,6 +157,7 @@ reset_password=Сброс пароля
invalid_code=Извините, ваш код подтверждения истек или не является допустимым.
reset_password_helper=Нажмите здесь, чтобы сбросить свой пароль
password_too_short=Длина пароля не менее 6 символов.
non_local_account=Нелокальные аккаунты не могут изменить пароль через Gogs.
[mail]
activate_account=Пожалуйста активируйте свой аккаунт
@@ -224,8 +220,7 @@ org_still_own_repo=Данная организация все еще являе
target_branch_not_exist=Целевая ветка не существует
[user]
change_avatar=Измените ваш аватар на gravatar.com
change_custom_avatar=Измените ваш аватар в настройках
change_avatar=Изменить аватар
join_on=Присоединился
repositories=Репозитории
activity=Активность
@@ -355,6 +350,8 @@ readme_helper=Выберите шаблон для файла readme
auto_init=Инициализировать этот репозиторий выбранными файлами и шаблоном
create_repo=Создать репозиторий
default_branch=Ветка по умолчанию
mirror_prune=Очистить
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Интервал зеркалирования (час)
mirror_address=Адрес зеркала
mirror_address_desc=Укажите необходимые учетные данные в адрес.
@@ -566,6 +563,10 @@ wiki.last_updated=Последнее обновление %s
settings=Настройки
settings.options=Опции
settings.collaboration=Сотрудничество
settings.collaboration.admin=Администратор
settings.collaboration.write=Запись
settings.collaboration.read=Просмотр
settings.collaboration.undefined=Не определено
settings.hooks=Автоматическое обновление
settings.githooks=Git хуки
settings.basic_settings=Основные параметры
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=Посетители будут перенапр
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач:
settings.tracker_issue_style.numeric=Числовой <span class="ui light grey text"> (1234)</span>
settings.tracker_issue_style.alphanumeric=Буквенно-цифровой <span class="ui light grey text"> (ABC-123, DEF-234,...)</span>
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
settings.pulls_desc=Включить публичные запросы на слияние
settings.danger_zone=Опасная зона
@@ -602,9 +606,7 @@ settings.delete=Удалить этот репозиторий
settings.delete_desc=Будьте внимательны! Как только вы удалите репозиторий — пути назад не будет.
settings.delete_notices_1=- Эта операция <strong>НЕ МОЖЕТ</strong> быть отменена.
settings.delete_notices_2=- Эта операция навсегда удалит всё из этого репозитория, включая данные Git, связанные с ним задачи, комментарии и права доступа для сотрудников.
settings.delete_notices_fork_1=- Если данный репозиторий является публичным, все склонированные репозитории останутся независимыми, после его удаления.
settings.delete_notices_fork_2=- Если данный репозиторий является приватным, все его ответвления будут удалены вместе с ним.
settings.delete_notices_fork_3=- Если вы хотите сохранить все ответвления после удаления репозитория, то сначала сделайте его публичным.
settings.delete_notices_fork_1=- Все отвлетвления станут независимыми после удаления.
settings.deletion_success=Репозиторий был успешно удалён!
settings.update_settings_success=Настройка репозитория обновлена успешно.
settings.transfer_owner=Новый владелец
@@ -681,13 +683,15 @@ settings.deploy_key_deletion_success=Ключ развертывания усп
diff.browse_source=Просмотр исходного кода
diff.parent=Родитель
diff.commit=Сommit
diff.data_not_available=Данные Diff не доступны.
diff.data_not_available=Данные Diff недоступны.
diff.show_diff_stats=Показать статистику Diff
diff.show_split_view=Разделённый вид
diff.show_unified_view=Единый вид
diff.stats_desc=<strong> %d измененных файлов</strong> с <strong>%d добавлено</strong> и <strong>%d удалено</strong>
diff.bin=BIN
diff.view_file=Просмотреть файл
diff.file_supressed=Разница между файлами не показана из-за своего большого размера
diff.too_many_files=Некоторые файлы не были показать из-за большого количества измененных файлов
release.releases=Релизы
release.new_release=Новый релиз
@@ -915,6 +919,7 @@ auths.enabled=Включено
auths.updated=Обновлено
auths.auth_type=Тип аутентификации
auths.auth_name=Имя аутентификации
auths.security_protocol=Протокол безопасности
auths.domain=Домен
auths.host=Хост
auths.port=Порт
@@ -1060,7 +1065,7 @@ notices.delete_success=Системное уведомление успешно
[action]
create_repo=создал(а) репозиторий <a href="%s"> %s</a>
rename_repo=репозиторий переименован из <code>%[1]s</code>на <a href="%[2]s">%[3]s</a>
rename_repo=переименовал(а) репозиторий из <code>%[1]s</code> на <a href="%[2]s">%[3]s</a>
commit_repo=запушил(а) <a href="%[1]s/src/%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
create_issue=`открыл(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`закрыл(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`

1108
conf/locale/locale_tr-TR.ini Normal file

File diff suppressed because it is too large Load Diff

31
conf/locale/locale_zh-CN.ini Executable file → Normal file
View File

@@ -44,13 +44,6 @@ issues=工单管理
cancel=取消
[search]
search=搜索...
repository=仓库
user=用户
issue=工单
code=代码
[install]
install=安装页面
title=首次运行安装程序
@@ -139,7 +132,9 @@ view_home=访问 %s
issues.in_your_repos=属于该用户仓库的
[explore]
repos=探索仓库
repos=仓库
users=用户
search=搜索
[auth]
create_new_account=创建帐户
@@ -162,6 +157,7 @@ reset_password=重置密码
invalid_code=对不起,您的确认代码已过期或已失效。
reset_password_helper=单击此处重置密码
password_too_short=密码长度不能少于 6 位!
non_local_account=非本地类型的帐户无法通过 Gogs 修改密码。
[mail]
activate_account=请激活您的帐户
@@ -224,8 +220,7 @@ org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转
target_branch_not_exist=目标分支不存在。
[user]
change_avatar=到 gravatar.com 上修改您的头像
change_custom_avatar=到个人设置中修改头像
change_avatar=修改头像
join_on=加入于
repositories=仓库列表
activity=公开活动
@@ -355,6 +350,8 @@ readme_helper=请选择自述文档模板
auto_init=使用选定的文件和模板初始化仓库
create_repo=创建仓库
default_branch=默认分支
mirror_prune=修剪
mirror_prune_desc=当远程追踪的引用被删除时本地也同步删除
mirror_interval=镜像同步周期(小时)
mirror_address=镜像地址
mirror_address_desc=请在镜像地址中写入必要的用户凭据信息。
@@ -566,6 +563,10 @@ wiki.last_updated=最后更新于 %s
settings=仓库设置
settings.options=基本设置
settings.collaboration=管理协作者
settings.collaboration.admin=管理权限
settings.collaboration.write=可写权限
settings.collaboration.read=可读权限
settings.collaboration.undefined=未定义
settings.hooks=管理 Web 钩子
settings.githooks=管理 Git 钩子
settings.basic_settings=基本设置
@@ -580,6 +581,9 @@ settings.external_wiki_url_desc=当访问者单击分页标签时,将会被重
settings.issues_desc=启用内置的轻量级工单管理系统
settings.use_external_issue_tracker=使用外部的工单管理系统
settings.tracker_url_format=外部工单管理系统的 URL 格式
settings.tracker_issue_style=外部工单管理系统命名风格:
settings.tracker_issue_style.numeric=纯数字 <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=字母和数字结合 <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
settings.pulls_desc=启用合并请求以接受社区贡献
settings.danger_zone=危险操作区
@@ -602,9 +606,7 @@ settings.delete=删除本仓库
settings.delete_desc=删除仓库操作不可逆转,请三思而后行。
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滚。
settings.delete_notices_2=- 此操作将永久删除该仓库,包括 Git 数据、 工单、 评论和协作者的操作权限。
settings.delete_notices_fork_1=- 如果该仓库为公开的,则在删除仓库后所有的派生仓库都将转换独立的仓库。
settings.delete_notices_fork_2=- 如果该仓库为私有,则会同时删除所有的派生仓库。
settings.delete_notices_fork_3=- 如果您想要保留派生仓库,请先将可见性修改为公开的后再进行删除操作。
settings.delete_notices_fork_1=- 删除完成后所有的派生仓库都将转换独立的仓库。
settings.deletion_success=仓库删除成功!
settings.update_settings_success=仓库设置更新成功!
settings.transfer_owner=新拥有者
@@ -688,6 +690,8 @@ diff.show_unified_view=合并视图
diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二进制
diff.view_file=查看文件
diff.file_supressed=文件差异内容过多而无法显示
diff.too_many_files=部分文件因为文件数量过多而无法显示
release.releases=版本发布
release.new_release=发布新版
@@ -915,6 +919,7 @@ auths.enabled=已启用
auths.updated=最后更新时间
auths.auth_type=认证类型
auths.auth_name=认证名称
auths.security_protocol=安全协议
auths.domain=域名
auths.host=主机地址
auths.port=主机端口

87
conf/locale/locale_zh-HK.ini Executable file → Normal file
View File

@@ -38,19 +38,12 @@ settings=設定
your_profile=個人資料
your_settings=用戶設定
activities=Activities
activities=活動
pull_requests=合併請求
issues=問題
cancel=取消
[search]
search=搜尋...
repository=倉庫
user=用戶
issue=工單
code=程式碼
[install]
install=安裝頁面
title=首次安裝步驟
@@ -65,7 +58,7 @@ db_name=資料庫名稱
db_helper=如果您使用 MySQL請使用 INNODB 引擎以及 utf8_general_ci 字符集。
ssl_mode=SSL 模式
path=數據庫文件路徑
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
sqlite_helper=SQLite3 TiDB 資料庫檔案路徑。<br>作為以服務執行時,請使用絕對路徑。
err_empty_db_path=SQLite3 或 TiDB 的數據庫路徑不能為空。
err_invalid_tidb_name=TiDB 數據庫名稱不允許包含字符 "." 或 "-" 。
no_admin_and_disable_registration=您不能夠在未創建管理員用戶的情況下禁止註冊。
@@ -86,8 +79,8 @@ http_port=HTTP 端口號
http_port_helper=應用監聽的端口號
app_url=應用程式網址
app_url_helper=該設置影響 HTTP/HTTPS 複製地址和一些郵箱中的連結。
log_root_path=Log Path
log_root_path_helper=Directory to write log files to.
log_root_path=日誌路徑
log_root_path_helper=寫入日誌檔目錄
optional_title=可選設置
email_title=電子郵件服務設定
@@ -124,7 +117,7 @@ run_user_not_match=執行系統用戶非當前用戶:%s -> %s
save_config_failed=應用配置保存失敗:%v
invalid_admin_setting=管理員帳戶設置不正確:%v
install_success=您好!我們很高興您選擇使用 Gogs祝您使用愉快代碼從此無 BUG
invalid_log_root_path=Log root path is invalid: %v
invalid_log_root_path=日誌根目錄無效: %v
[home]
uname_holder=用戶名或郵箱
@@ -140,6 +133,8 @@ issues.in_your_repos=屬於該用戶倉庫的
[explore]
repos=探索倉庫
users=用戶
search=搜索
[auth]
create_new_account=創建帳戶
@@ -162,6 +157,7 @@ reset_password=重置密碼
invalid_code=對不起,您的確認代碼已過期或已失效。
reset_password_helper=單擊此處重置密碼
password_too_short=密碼長度不能少於 6 位!
non_local_account=Non-local accounts cannot change passwords through Gogs.
[mail]
activate_account=請激活您的帳戶
@@ -224,8 +220,7 @@ org_still_own_repo=該組織仍然是某些倉庫的擁有者,您必須先轉
target_branch_not_exist=目標分支不存在
[user]
change_avatar=到 gravatar.com 上修改您的頭像
change_custom_avatar=到個人設置中修改頭像
change_avatar=Change your avatar
join_on=加入於
repositories=倉庫列表
activity=公開活動
@@ -264,7 +259,7 @@ cancel=取消操作
enable_custom_avatar=啟動自定義頭像
choose_new_avatar=選擇新的頭像
update_avatar=更新頭像設置
delete_current_avatar=Delete Current Avatar
delete_current_avatar=刪除當前頭像
uploaded_avatar_not_a_image=上傳的文件不是一張圖片!
update_avatar_success=您的頭像設置更新成功!
@@ -355,6 +350,8 @@ readme_helper=請選擇readme模板
auto_init=使用選定的文件和模板初始化倉庫
create_repo=創建倉庫
default_branch=默認分支
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=鏡像同步周期(小時)
mirror_address=鏡像地址
mirror_address_desc=請在位址中包括必要的使用者憑據。
@@ -387,7 +384,7 @@ unwatch=取消關注
watch=關註
unstar=取消讚好
star=讚好
fork=派生
fork=複刻
no_desc=暫無描述
quick_guide=快速幫助
@@ -476,7 +473,7 @@ issues.closed_at=`於 <a id="%[1]s" href="#%[1]s">%[2]s</a> 關閉`
issues.reopened_at=`於 <a id="%[1]s" href="#%[1]s">%[2]s</a> 重新開啟`
issues.commit_ref_at=`在代碼提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中引用了該問題`
issues.poster=發佈者
issues.collaborator=Collaborator
issues.collaborator=協同者
issues.owner=所有者
issues.sign_up_for_free=免費註冊
issues.sign_in_require_desc=及加入到對話當中。如果您已經註冊,可以直接 <a href="%s">登錄及評論</a>
@@ -493,7 +490,7 @@ issues.label_modify=修改標籤
issues.label_deletion=刪除標籤
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
issues.label_deletion_success=標籤刪除成功!
issues.num_participants=%d Participants
issues.num_participants=%d 參與者
pulls.new=創建合併請求
pulls.compare_changes=對比文件變化
@@ -557,8 +554,8 @@ wiki.save_page=保存頁面
wiki.last_commit_info=%s 於 %s 修改了此頁面
wiki.edit_page_button=修改
wiki.new_page_button=新的頁面
wiki.delete_page_button=Delete Page
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.delete_page_button=刪除頁面
wiki.delete_page_notice_1=這將刪除頁面 <code>"%s"</code>。請三思而後行。
wiki.page_already_exists=相同名稱的 Wiki 頁面已經存在。
wiki.pages=所有頁面
wiki.last_updated=最後更新於 %s
@@ -566,6 +563,10 @@ wiki.last_updated=最後更新於 %s
settings=倉庫設置
settings.options=基本設置
settings.collaboration=管理協作者
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.hooks=管理 Web 鉤子
settings.githooks=管理 Git 鉤子
settings.basic_settings=基本設置
@@ -580,12 +581,15 @@ settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到
settings.issues_desc=啟用內置的輕量級問題管理系統
settings.use_external_issue_tracker=使用外部的問題管理系統
settings.tracker_url_format=外部問題管理系統的 URL 格式
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
settings.pulls_desc=啟用合併請求以接受社區貢獻
settings.danger_zone=危險操作區
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
settings.convert=Convert To Regular Repository
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
settings.convert=轉換為正規倉庫
settings.convert_desc=您可以將此鏡像轉成正規倉庫。此動做不可逆。
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
settings.convert_confirm=Confirm Conversion
settings.convert_succeed=Repository has been converted to regular type successfully.
@@ -594,17 +598,15 @@ settings.transfer_desc=您可以將倉庫轉移至您擁有管理員權限的帳
settings.transfer_notices_1=- 如果您將倉庫轉移給個人用戶,您將會丟失操作權限。
settings.transfer_notices_2=- 如果您將倉庫轉移給您是所有者的組織,您的操作權限將被保留。
settings.transfer_form_title=請輸入以下信息以確認您的操作:
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete=刪除 Wiki 資料
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_delete_notices_1=- 將刪除和停用 %s 的 wiki
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.delete=刪除本倉庫
settings.delete_desc=刪除倉庫操作不可逆轉,請三思而後行。
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滾。
settings.delete_notices_2=- 此操作將永久刪除該倉庫,包括 Git 數據、 問題、 評論和協作者的操作權限。
settings.delete_notices_fork_1=- 如果該倉庫為公開的,則在刪除倉庫後所有的派生倉庫都將轉換成獨立的倉庫。
settings.delete_notices_fork_2=- 如果該倉庫為私有,則會同時刪除所有的派生倉庫。
settings.delete_notices_fork_3=- 如果您想要保留派生倉庫,請先將可見性修改為公開的後再進行刪除操作。
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.deletion_success=倉庫刪除成功!
settings.update_settings_success=倉庫設置更新成功!
settings.transfer_owner=新擁有者
@@ -613,7 +615,7 @@ settings.transfer_succeed=倉庫所有權轉移成功!
settings.confirm_delete=確認刪除倉庫
settings.add_collaborator=增加新的協作者
settings.add_collaborator_success=成功添加新的協作者!
settings.delete_collaborator=Delete
settings.delete_collaborator=刪除
settings.collaborator_deletion=Collaborator Deletion
settings.collaborator_deletion_desc=This user will no longer have collaboration access to this repository after deletion. Do you want to continue?
settings.remove_collaborator_success=被操作的協作者已經被收回權限!
@@ -688,6 +690,8 @@ diff.show_unified_view=統一視圖
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二進制
diff.view_file=查看文件
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=版本發佈
release.new_release=發佈新版本
@@ -915,6 +919,7 @@ auths.enabled=已啟用
auths.updated=最後更新時間
auths.auth_type=認證類型
auths.auth_name=認證名稱
auths.security_protocol=Security Protocol
auths.domain=域名
auths.host=主機地址
auths.port=主機端口
@@ -968,17 +973,17 @@ config.log_file_root_path=日志文件根目錄
config.script_type=腳本類型
config.reverse_auth_user=反向代理認證
config.ssh_config=SSH Configuration
config.ssh_enabled=Enabled
config.ssh_start_builtin_server=Start Builtin Server
config.ssh_config=SSH 配置
config.ssh_enabled=已啟用
config.ssh_start_builtin_server=啟動內建伺服器
config.ssh_domain=Domain
config.ssh_port=Port
config.ssh_listen_port=Listen Port
config.ssh_root_path=Root Path
config.ssh_key_test_path=Key Test Path
config.ssh_keygen_path=Keygen ('ssh-keygen') Path
config.ssh_minimum_key_size_check=Minimum Key Size Check
config.ssh_minimum_key_sizes=Minimum Key Sizes
config.ssh_port=
config.ssh_listen_port=監聽埠
config.ssh_root_path=根路徑
config.ssh_key_test_path=金鑰測試路徑
config.ssh_keygen_path=金鑰產生 (' ssh-keygen ') 路徑
config.ssh_minimum_key_size_check=金鑰最小大小檢查
config.ssh_minimum_key_sizes=金鑰最小大小
config.db_config=數據庫配置
config.db_type=數據庫類型
@@ -1009,9 +1014,9 @@ config.mailer_disable_helo=禁用 HELO 操作
config.mailer_name=發送者名稱
config.mailer_host=郵件主機地址
config.mailer_user=發送者帳號
config.send_test_mail=Send Test Email
config.test_mail_failed=Fail to send test email to '%s': %v
config.test_mail_sent=Test email has been sent to '%s'.
config.send_test_mail=發送測試郵件
config.test_mail_failed=無法向 '%s' 發送測試郵件: %v
config.test_mail_sent=測試電子郵件已發送到 '%s'
config.oauth_config=社交帳號配置
config.oauth_enabled=啟用服務
config.cache_config=Cache 配置

1108
conf/locale/locale_zh-TW.ini Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# Docker for Gogs
Visit [Docker Hub](https://hub.docker.com/r/gogs/gogs/) see all available tags.
Visit [Docker Hub](https://hub.docker.com/r/gogs/) see all available images and tags.
## Usage
@@ -43,9 +43,11 @@ If you're more comfortable with mounting data to a data container, the commands
```
# Create data container
docker run --name=gogs-data --entrypoint /bin/true gogs/gogs
# Use `docker run` for the first time.
docker run --name=gogs --volumes-from gogs-data -p 10022:22 -p 10080:3000 gogs/gogs
```
#### Using Docker 1.9 Volume command
```
@@ -71,9 +73,27 @@ Most of settings are obvious and easy to understand, but there are some settings
Full documentation of application settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
### Crond
### Container options
Please set environment variable `RUN_CROND` to be `true` or `1` in order to start `crond` inside the container.
This container have some options available via environment variables, these options are opt-in features that can help the administration of this container:
- **SOCAT_LINK**:
- <u>Possible value:</u>
`true`, `false`, `1`, `0`
- <u>Default:</u>
`true`
- <u>Action:</u>
Bind linked docker container to localhost socket using socat.
Any exported port from a linked container will be binded to the matching port on localhost.
- <u>Disclaimer:</u>
As this option rely on the environment variable created by docker when a container is linked, this option should be deactivated in managed environment such as Rancher or Kubernetes (set to `0` or `false`)
- **RUN_CROND**:
- <u>Possible value:</u>
`true`, `false`, `1`, `0`
- <u>Default:</u>
`false`
- <u>Action:</u>
Request crond to be run inside the container. Its default configuration will periodically run all scripts from `/etc/periodic/${period}` but custom crontabs can be added to `/var/spool/cron/crontabs/`.
## Upgrade

View File

@@ -5,19 +5,28 @@ set -e
# Set temp environment vars
export GOPATH=/tmp/go
export PATH=${PATH}:${GOPATH}/bin
export GO15VENDOREXPERIMENT=1
# Install build deps
apk --no-cache --no-progress add --virtual build-deps linux-pam-dev go gcc musl-dev
apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev go
# Init go environment to build Gogs
# Install glide
git clone -b 0.10.2 https://github.com/Masterminds/glide ${GOPATH}/src/github.com/Masterminds/glide
cd ${GOPATH}/src/github.com/Masterminds/glide
make build
go install
# Build Gogs
mkdir -p ${GOPATH}/src/github.com/gogits/
ln -s /app/gogs/ ${GOPATH}/src/github.com/gogits/gogs
cd ${GOPATH}/src/github.com/gogits/gogs
go get -v -tags "sqlite cert pam"
go build -tags "sqlite cert pam"
glide install
make build TAGS="sqlite cert pam"
# Cleanup GOPATH
rm -r $GOPATH
# Cleanup GOPATH & vendoring dir
rm -r $GOPATH /app/gogs/vendor
# Remove build deps
apk --no-progress del build-deps

148
glide.lock generated Normal file
View File

@@ -0,0 +1,148 @@
hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
updated: 2016-06-12T17:35:14.27036884+08:00
imports:
- name: github.com/bradfitz/gomemcache
version: fb1f79c6b65acda83063cbc69f6bba1522558bfc
subpackages:
- memcache
- name: github.com/codegangsta/cli
version: 1efa31f08b9333f1bd4882d61f9d668a70cd902e
- name: github.com/go-macaron/binding
version: 9440f336b443056c90d7d448a0a55ad8c7599880
- name: github.com/go-macaron/cache
version: 56173531277692bc2925924d51fda1cd0a6b8178
subpackages:
- memcache
- redis
- name: github.com/go-macaron/captcha
version: 8aa5919789ab301e865595eb4b1114d6b9847deb
- name: github.com/go-macaron/csrf
version: 6a9a7df172cc1fcd81e4585f44b09200b6087cc0
- name: github.com/go-macaron/gzip
version: cad1c6580a07c56f5f6bc52d66002a05985c5854
- name: github.com/go-macaron/i18n
version: ef57533c3b0fc2d8581deda14937e52f11a203ab
- name: github.com/go-macaron/inject
version: c5ab7bf3a307593cd44cb272d1a5beea473dd072
- name: github.com/go-macaron/session
version: 66031fcb37a0fff002a1f028eb0b3a815c78306b
subpackages:
- redis
- name: github.com/go-macaron/toolbox
version: 82b511550b0aefc36b3a28062ad3a52e812bee38
- name: github.com/go-sql-driver/mysql
version: 3654d25ec346ee8ce71a68431025458d52a38ac0
- name: github.com/go-xorm/core
version: bc1b7f81f0e369289078424064634a5ee7d21051
- name: github.com/go-xorm/xorm
version: b8b1711cde4d9c68da95cd0ff8de0de0cb491df3
- name: github.com/gogits/chardet
version: 2404f777256163ea3eadb273dada5dcb037993c0
- name: github.com/gogits/cron
version: 96040e4fab17baa0391ce571694e4ccb5fce5dac
- name: github.com/gogits/git-module
version: db93fa550116997bbe0b62baa653b8e6f4135258
- name: github.com/gogits/go-gogs-client
version: ee68cd9eefff11615f336e9965762f6736eeecc8
- name: github.com/issue9/identicon
version: d36b54562f4cf70c83653e13dc95c220c79ef521
- name: github.com/jaytaylor/html2text
version: 52d9b785554a1918cb09909b89a1509a98b853fd
- name: github.com/kardianos/minwinsvc
version: cad6b2b879b0970e4245a20ebf1a81a756e2bb70
- name: github.com/klauspost/compress
version: 14eb9c4951195779ecfbec34431a976de7335b0a
subpackages:
- gzip
- flate
- name: github.com/klauspost/cpuid
version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
- name: github.com/klauspost/crc32
version: 19b0b332c9e4516a6370a0456e6182c3b5036720
- name: github.com/lib/pq
version: ee1442bda7bd1b6a84e913bdb421cb1874ec629d
subpackages:
- oid
- name: github.com/mattn/go-sqlite3
version: 38ee283dabf11c9cbdb968eebd79b1fa7acbabe6
- name: github.com/mcuadros/go-version
version: d52711f8d6bea8dc01efafdb68ad95a4e2606630
- name: github.com/microcosm-cc/bluemonday
version: 4ac6f27528d0a3f2a59e0b0a6f6b3ff0bb89fe20
- name: github.com/msteinert/pam
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
- name: github.com/nfnt/resize
version: 4d93a29130b1b6aba503e2aa8b50f516213ea80e
- name: github.com/russross/blackfriday
version: 4e6f303e8d936855981ddcdbfc092b03d2b2b68e
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/sergi/go-diff
version: ec7fdbb58eb3e300c8595ad5ac74a5aa50019cc7
subpackages:
- diffmatchpatch
- name: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- name: github.com/Unknwon/cae
version: 7f5e046bc8a6c3cde743c233b96ee4fd84ee6ecd
subpackages:
- zip
- name: github.com/Unknwon/com
version: 28b053d5a2923b87ce8c5a08f3af779894a72758
- name: github.com/Unknwon/i18n
version: 39d6f2727e0698b1021ceb6a77c1801aa92e7d5d
- name: github.com/Unknwon/paginater
version: 7748a72e01415173a27d79866b984328e7b0c12b
- name: golang.org/x/crypto
version: 77f4136a99ffb5ecdbdd0226bd5cb146cf56bc0e
subpackages:
- ssh
- curve25519
- ed25519
- ed25519/internal/edwards25519
- name: golang.org/x/net
version: 3f122ce3dbbe488b7e6a8bdb26f41edec852a40b
subpackages:
- html
- html/charset
- html/atom
- name: golang.org/x/sys
version: 7f918dd405547ecb864d14a8ecbbfe205b5f930f
subpackages:
- windows/svc
- windows
- name: golang.org/x/text
version: e4775119bd79944a15a741ac4be61e43509a70d9
subpackages:
- transform
- language
- encoding
- encoding/charmap
- encoding/htmlindex
- internal/tag
- encoding/internal/identifier
- encoding/internal
- encoding/japanese
- encoding/korean
- encoding/simplifiedchinese
- encoding/traditionalchinese
- encoding/unicode
- internal/utf8internal
- runes
- name: gopkg.in/alexcesaro/quotedprintable.v3
version: 2caba252f4dc53eaf6b553000885530023f54623
- name: gopkg.in/asn1-ber.v1
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
- name: gopkg.in/bufio.v1
version: 567b2bfa514e796916c4747494d6ff5132a1dfce
- name: gopkg.in/gomail.v2
version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
- name: gopkg.in/ini.v1
version: 72ba3e6b9e6b87e0c74c9a7a4dc86e8dd8ba4355
- name: gopkg.in/ldap.v2
version: 0e7db8eb77695b5a952f0e5d78df9ab160050c73
- name: gopkg.in/macaron.v1
version: 2133042f8d1022b8253e4e23f7940467941409ce
- name: gopkg.in/redis.v2
version: e6179049628164864e6e84e973cfb56335748dea
devImports: []

57
glide.yaml Normal file
View File

@@ -0,0 +1,57 @@
package: github.com/gogits/gogs
import:
- package: github.com/Unknwon/cae
subpackages:
- zip
- package: github.com/Unknwon/com
- package: github.com/Unknwon/i18n
- package: github.com/Unknwon/paginater
- package: github.com/codegangsta/cli
- package: github.com/go-macaron/binding
- package: github.com/go-macaron/cache
subpackages:
- memcache
- redis
- package: github.com/go-macaron/captcha
- package: github.com/go-macaron/csrf
- package: github.com/go-macaron/gzip
- package: github.com/go-macaron/i18n
- package: github.com/go-macaron/session
subpackages:
- redis
- package: github.com/go-macaron/toolbox
- package: github.com/go-sql-driver/mysql
- package: github.com/go-xorm/core
- package: github.com/go-xorm/xorm
- package: github.com/gogits/chardet
- package: github.com/gogits/cron
- package: github.com/gogits/git-module
- package: github.com/gogits/go-gogs-client
- package: github.com/issue9/identicon
- package: github.com/kardianos/minwinsvc
- package: github.com/lib/pq
- package: github.com/mattn/go-sqlite3
- package: github.com/mcuadros/go-version
- package: github.com/microcosm-cc/bluemonday
- package: github.com/msteinert/pam
- package: github.com/nfnt/resize
- package: github.com/russross/blackfriday
- package: github.com/satori/go.uuid
- package: github.com/sergi/go-diff
subpackages:
- diffmatchpatch
- package: golang.org/x/crypto
subpackages:
- ssh
- package: golang.org/x/net
subpackages:
- html
- html/charset
- package: golang.org/x/text
subpackages:
- transform
- language
- package: gopkg.in/gomail.v2
- package: gopkg.in/ini.v1
- package: gopkg.in/ldap.v2
- package: gopkg.in/macaron.v1

View File

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

View File

@@ -20,6 +20,33 @@ const (
ACCESS_MODE_OWNER // 4
)
func (mode AccessMode) String() string {
switch mode {
case ACCESS_MODE_READ:
return "read"
case ACCESS_MODE_WRITE:
return "write"
case ACCESS_MODE_ADMIN:
return "admin"
case ACCESS_MODE_OWNER:
return "owner"
default:
return "none"
}
}
// ParseAccessMode returns corresponding access mode to given permission string.
func ParseAccessMode(permission string) AccessMode {
switch permission {
case "write":
return ACCESS_MODE_WRITE
case "admin":
return ACCESS_MODE_ADMIN
default:
return ACCESS_MODE_READ
}
}
// Access represents the highest access level of a user to the repository. The only access type
// that is not in this table is the real owner of a repository. In case of an organization
// repository, the members of the owners team are in this table.
@@ -110,7 +137,7 @@ func (u *User) GetAccessibleRepositories() ([]*Repository, error) {
repoIDs = append(repoIDs, access.RepoID)
}
repos := make([]*Repository, 0, len(repoIDs))
return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated").Find(&repos)
return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated_unix").Find(&repos)
}
func maxAccessMode(modes ...AccessMode) AccessMode {

View File

@@ -84,13 +84,18 @@ type Action struct {
RefName string
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
Content string `xorm:"TEXT"`
Created time.Time `xorm:"created"`
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (a *Action) BeforeInsert() {
a.CreatedUnix = time.Now().UTC().Unix()
}
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created":
a.Created = regulateTimeZone(a.Created)
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}
@@ -484,7 +489,7 @@ func CommitRepoAction(
Content: string(bs),
RepoID: repo.ID,
RepoUserName: repoUserName,
RepoName: repoName,
RepoName: repo.Name,
RefName: refName,
IsPrivate: repo.IsPrivate,
}); err != nil {
@@ -512,7 +517,7 @@ func CommitRepoAction(
Before: oldCommitID,
After: newCommitID,
CompareUrl: setting.AppUrl + commit.CompareUrl,
Commits: commit.ToApiPayloadCommits(repo.FullRepoLink()),
Commits: commit.ToApiPayloadCommits(repo.FullLink()),
Repo: payloadRepo,
Pusher: &api.PayloadAuthor{
Name: pusher_name,
@@ -556,7 +561,7 @@ func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repos
RepoUserName: newOwner.Name,
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
Content: path.Join(oldOwner.LowerName, repo.LowerName),
Content: path.Join(oldOwner.Name, repo.Name),
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", actUser.Id, repo.ID, err)
}

View File

@@ -12,6 +12,7 @@ import (
"time"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
@@ -29,7 +30,19 @@ type Notice struct {
ID int64 `xorm:"pk autoincr"`
Type NoticeType
Description string `xorm:"TEXT"`
Created time.Time `xorm:"CREATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (n *Notice) BeforeInsert() {
n.CreatedUnix = time.Now().UTC().Unix()
}
func (n *Notice) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
n.Created = time.Unix(n.CreatedUnix, 0).Local()
}
}
// TrStr returns a translation format string.
@@ -39,6 +52,11 @@ func (n *Notice) TrStr() string {
// CreateNotice creates new system notice.
func CreateNotice(tp NoticeType, desc string) error {
// prevent panic if database connection is not available at this point
if x == nil {
return fmt.Errorf("Could not save notice due database connection not being available: %d %s", tp, desc)
}
n := &Notice{
Type: tp,
Description: desc,
@@ -56,7 +74,12 @@ func CreateRepositoryNotice(desc string) error {
// creates a system notice when error occurs.
func RemoveAllWithNotice(title, path string) {
var err error
// workaround for Go not being able to remove read-only files/folders: https://github.com/golang/go/issues/9606
// this bug should be fixed on Go 1.7, so the workaround should be removed when Gogs don't support Go 1.6 anymore:
// https://github.com/golang/go/commit/2ffb3e5d905b5622204d199128dec06cefd57790
if setting.IsWindows {
// converting "/" to "\" in path on Windows
path = strings.Replace(path, "/", "\\", -1)
err = exec.Command("cmd", "/C", "rmdir", "/S", "/Q", path).Run()
} else {
err = os.RemoveAll(path)

View File

@@ -280,6 +280,18 @@ func (err ErrAccessTokenNotExist) Error() string {
return fmt.Sprintf("access token does not exist [sha: %s]", err.SHA)
}
type ErrAccessTokenEmpty struct {
}
func IsErrAccessTokenEmpty(err error) bool {
_, ok := err.(ErrAccessTokenEmpty)
return ok
}
func (err ErrAccessTokenEmpty) Error() string {
return fmt.Sprintf("access token is empty")
}
// ________ .__ __ .__
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \

View File

@@ -48,10 +48,10 @@ const (
)
type DiffLine struct {
LeftIdx int
RightIdx int
Type DiffLineType
Content string
LeftIdx int
RightIdx int
Type DiffLineType
Content string
}
func (d *DiffLine) GetType() int {
@@ -161,6 +161,7 @@ type DiffFile struct {
IsBin bool
IsRenamed bool
Sections []*DiffSection
IsIncomplete bool
}
func (diffFile *DiffFile) GetType() int {
@@ -174,6 +175,7 @@ func (diffFile *DiffFile) GetHighlightClass() string {
type Diff struct {
TotalAddition, TotalDeletion int
Files []*DiffFile
IsIncomplete bool
}
func (diff *Diff) NumFiles() int {
@@ -182,7 +184,7 @@ func (diff *Diff) NumFiles() int {
const DIFF_HEAD = "diff --git "
func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
var (
diff = &Diff{Files: make([]*DiffFile, 0)}
@@ -193,15 +195,12 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
leftLine, rightLine int
lineCount int
curFileLinesCount int
)
input := bufio.NewReader(reader)
isEOF := false
for {
if isEOF {
break
}
for !isEOF {
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
@@ -216,20 +215,16 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
line = line[:len(line)-1]
}
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
continue
} else if len(line) == 0 {
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 {
continue
}
curFileLinesCount++
lineCount++
// Diff data too large, we only show the first about maxlines lines
if lineCount >= maxlines {
log.Warn("Diff data too large")
io.Copy(ioutil.Discard, reader)
diff.Files = nil
return diff, nil
if curFileLinesCount >= maxLines || len(line) >= maxLineCharacteres {
curFile.IsIncomplete = true
}
switch {
@@ -304,6 +299,12 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
Sections: make([]*DiffSection, 0, 10),
}
diff.Files = append(diff.Files, curFile)
if len(diff.Files) >= maxFiles {
diff.IsIncomplete = true
io.Copy(ioutil.Discard, reader)
break
}
curFileLinesCount = 0
// Check file diff type.
for {
@@ -366,7 +367,7 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
return diff, nil
}
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxlines int) (*Diff, error) {
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return nil, err
@@ -405,7 +406,7 @@ func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxline
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
defer process.Remove(pid)
diff, err := ParsePatch(maxlines, stdout)
diff, err := ParsePatch(maxLines, maxLineCharacteres, maxFiles, stdout)
if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err)
}
@@ -417,6 +418,6 @@ func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxline
return diff, nil
}
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitId, maxlines)
func GetDiffCommit(repoPath, commitId string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitId, maxLines, maxLineCharacteres, maxFiles)
}

View File

@@ -5,7 +5,6 @@
package models
import (
"bytes"
"errors"
"fmt"
"io"
@@ -33,8 +32,8 @@ var (
// Issue represents an issue or pull request of repository.
type Issue struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
Index int64 // Index in one repository.
RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
Name string
Repo *Repository `xorm:"-"`
PosterID int64
@@ -52,14 +51,37 @@ type Issue struct {
RenderedContent string `xorm:"-"`
Priority int
NumComments int
Deadline time.Time
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
Deadline time.Time `xorm:"-"`
DeadlineUnix int64
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
Attachments []*Attachment `xorm:"-"`
Comments []*Comment `xorm:"-"`
}
func (i *Issue) BeforeInsert() {
i.CreatedUnix = time.Now().UTC().Unix()
i.UpdatedUnix = i.CreatedUnix
}
func (i *Issue) BeforeUpdate() {
i.UpdatedUnix = time.Now().UTC().Unix()
i.DeadlineUnix = i.Deadline.UTC().Unix()
}
func (issue *Issue) loadAttributes() (err error) {
issue.Repo, err = GetRepositoryByID(issue.RepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
return nil
}
func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -74,6 +96,23 @@ func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
log.Error(3, "GetCommentsByIssueID[%d]: %v", i.ID, err)
}
i.Labels, err = GetLabelsByIssueID(i.ID)
if err != nil {
log.Error(3, "GetLabelsByIssueID[%d]: %v", i.ID, err)
}
case "poster_id":
i.Poster, err = GetUserByID(i.PosterID)
if err != nil {
if IsErrUserNotExist(err) {
i.PosterID = -1
i.Poster = NewFakeUser()
} else {
log.Error(3, "GetUserByID[%d]: %v", i.ID, err)
}
return
}
case "milestone_id":
if i.MilestoneID == 0 {
return
@@ -83,6 +122,7 @@ func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
if err != nil {
log.Error(3, "GetMilestoneById[%d]: %v", i.ID, err)
}
case "assignee_id":
if i.AssigneeID == 0 {
return
@@ -92,8 +132,13 @@ func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
if err != nil {
log.Error(3, "GetUserByID[%d]: %v", i.ID, err)
}
case "created":
i.Created = regulateTimeZone(i.Created)
case "deadline_unix":
i.Deadline = time.Unix(i.DeadlineUnix, 0).Local()
case "created_unix":
i.Created = time.Unix(i.CreatedUnix, 0).Local()
case "updated_unix":
i.Updated = time.Unix(i.UpdatedUnix, 0).Local()
}
}
@@ -102,21 +147,23 @@ func (i *Issue) HashTag() string {
return "issue-" + com.ToStr(i.ID)
}
// State returns string representation of issue status.
func (i *Issue) State() string {
if i.IsClosed {
return "closed"
}
return "open"
}
func (issue *Issue) FullLink() string {
return fmt.Sprintf("%s/issues/%d", issue.Repo.FullLink(), issue.Index)
}
// IsPoster returns true if given user by ID is the poster.
func (i *Issue) IsPoster(uid int64) bool {
return i.PosterID == uid
}
func (i *Issue) GetPoster() (err error) {
i.Poster, err = GetUserByID(i.PosterID)
if IsErrUserNotExist(err) {
i.PosterID = -1
i.Poster = NewFakeUser()
return nil
}
return err
}
func (i *Issue) hasLabel(e Engine, labelID int64) bool {
return hasIssueLabel(e, i.ID, labelID)
}
@@ -157,11 +204,6 @@ func (i *Issue) getLabels(e Engine) (err error) {
return nil
}
// GetLabels retrieves all labels of issue and assign to corresponding field.
func (i *Issue) GetLabels() error {
return i.getLabels(x)
}
func (i *Issue) removeLabel(e *xorm.Session, label *Label) error {
return deleteIssueLabel(e, i, label)
}
@@ -285,6 +327,19 @@ func (i *Issue) GetPullRequest() (err error) {
// It's caller's responsibility to create action.
func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64, uuids []string, isPull bool) (err error) {
issue.Name = strings.TrimSpace(issue.Name)
issue.Index = repo.NextIssueIndex()
if issue.AssigneeID > 0 {
// Silently drop invalid assignee
valid, err := hasAccess(e, &User{Id: issue.AssigneeID}, repo, ACCESS_MODE_WRITE)
if err != nil {
return fmt.Errorf("hasAccess: %v", err)
} else if !valid {
issue.AssigneeID = 0
}
}
if _, err = e.Insert(issue); err != nil {
return err
}
@@ -307,6 +362,10 @@ func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64,
}
for _, label := range labels {
if label.RepoID != repo.ID {
continue
}
if err = issue.addLabel(e, label); err != nil {
return fmt.Errorf("addLabel: %v", err)
}
@@ -344,7 +403,7 @@ func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64,
}
}
return nil
return issue.loadAttributes()
}
// NewIssue creates new issue with labels for repository.
@@ -359,6 +418,10 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
return fmt.Errorf("newIssue: %v", err)
}
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
// Notify watchers.
act := &Action{
ActUserID: issue.Poster.Id,
@@ -371,11 +434,13 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}
if err = notifyWatchers(sess, act); err != nil {
return err
if err = NotifyWatchers(act); err != nil {
log.Error(4, "NotifyWatchers: %v", err)
} else if err = issue.MailParticipants(); err != nil {
log.Error(4, "MailParticipants: %v", err)
}
return sess.Commit()
return nil
}
// GetIssueByRef returns an Issue specified by a GFM reference.
@@ -401,8 +466,7 @@ func GetIssueByRef(ref string) (*Issue, error) {
return nil, err
}
issue.Repo = repo
return issue, nil
return issue, issue.loadAttributes()
}
// GetIssueByIndex returns issue by given index in repository.
@@ -417,7 +481,7 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
} else if !has {
return nil, ErrIssueNotExist{0, repoID, index}
}
return issue, nil
return issue, issue.loadAttributes()
}
// GetIssueByID returns an issue by given ID.
@@ -429,7 +493,7 @@ func GetIssueByID(id int64) (*Issue, error) {
} else if !has {
return nil, ErrIssueNotExist{id, 0, 0}
}
return issue, nil
return issue, issue.loadAttributes()
}
type IssuesOptions struct {
@@ -449,6 +513,10 @@ type IssuesOptions struct {
// Issues returns a list of issues by given conditions.
func Issues(opts *IssuesOptions) ([]*Issue, error) {
if opts.Page <= 0 {
opts.Page = 1
}
sess := x.Limit(setting.IssuePagingNum, (opts.Page-1)*setting.IssuePagingNum)
if opts.RepoID > 0 {
@@ -458,7 +526,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
if len(opts.RepoIDs) == 0 {
return make([]*Issue, 0), nil
}
sess.Where("issue.repo_id IN ("+strings.Join(base.Int64sToStrings(opts.RepoIDs), ",")+")").And("issue.is_closed=?", opts.IsClosed)
sess.In("issue.repo_id", base.Int64sToStrings(opts.RepoIDs)).And("issue.is_closed=?", opts.IsClosed)
} else {
sess.Where("issue.is_closed=?", opts.IsClosed)
}
@@ -477,43 +545,34 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
switch opts.SortType {
case "oldest":
sess.Asc("created")
sess.Asc("issue.created_unix")
case "recentupdate":
sess.Desc("updated")
sess.Desc("issue.updated_unix")
case "leastupdate":
sess.Asc("updated")
sess.Asc("issue.updated_unix")
case "mostcomment":
sess.Desc("num_comments")
sess.Desc("issue.num_comments")
case "leastcomment":
sess.Asc("num_comments")
sess.Asc("issue.num_comments")
case "priority":
sess.Desc("priority")
sess.Desc("issue.priority")
default:
sess.Desc("created")
sess.Desc("issue.created_unix")
}
labelIDs := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if len(labelIDs) > 0 {
validJoin := false
queryStr := "issue.id=issue_label.issue_id"
for _, id := range labelIDs {
if id == 0 {
continue
}
validJoin = true
queryStr += " AND issue_label.label_id=" + com.ToStr(id)
}
if validJoin {
sess.Join("INNER", "issue_label", queryStr)
if len(opts.Labels) > 0 && opts.Labels != "0" {
labelIDs := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if len(labelIDs) > 0 {
sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id").In("issue.label_id", labelIDs)
}
}
if opts.IsMention {
queryStr := "issue.id=issue_user.issue_id AND issue_user.is_mentioned=1"
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").And("issue_user.is_mentioned = ?", true)
if opts.UserID > 0 {
queryStr += " AND issue_user.uid=" + com.ToStr(opts.UserID)
sess.And("issue_user.uid = ?", opts.UserID)
}
sess.Join("INNER", "issue_user", queryStr)
}
issues := make([]*Issue, 0, setting.IssuePagingNum)
@@ -629,18 +688,8 @@ func GetIssueUserPairsByRepoIds(rids []int64, isClosed bool, page int) ([]*Issue
return []*IssueUser{}, nil
}
buf := bytes.NewBufferString("")
for _, rid := range rids {
buf.WriteString("repo_id=")
buf.WriteString(com.ToStr(rid))
buf.WriteString(" OR ")
}
cond := strings.TrimSuffix(buf.String(), " OR ")
ius := make([]*IssueUser, 0, 10)
sess := x.Limit(20, (page-1)*20).Where("is_closed=?", isClosed)
if len(cond) > 0 {
sess.And(cond)
}
sess := x.Limit(20, (page-1)*20).Where("is_closed=?", isClosed).In("repo_id", rids)
err := sess.Find(&ius)
return ius, err
}
@@ -665,42 +714,44 @@ func GetIssueUserPairsByMode(uid, rid int64, isClosed bool, page, filterMode int
return ius, err
}
func UpdateMentions(userNames []string, issueId int64) error {
for i := range userNames {
userNames[i] = strings.ToLower(userNames[i])
}
users := make([]*User, 0, len(userNames))
if err := x.Where("lower_name IN (?)", strings.Join(userNames, "\",\"")).OrderBy("lower_name ASC").Find(&users); err != nil {
return err
// UpdateIssueMentions extracts mentioned people from content and
// updates issue-user relations for them.
func UpdateIssueMentions(issueID int64, mentions []string) error {
if len(mentions) == 0 {
return nil
}
ids := make([]int64, 0, len(userNames))
for i := range mentions {
mentions[i] = strings.ToLower(mentions[i])
}
users := make([]*User, 0, len(mentions))
if err := x.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil {
return fmt.Errorf("find mentioned users: %v", err)
}
ids := make([]int64, 0, len(mentions))
for _, user := range users {
ids = append(ids, user.Id)
if !user.IsOrganization() {
if !user.IsOrganization() || user.NumMembers == 0 {
continue
}
if user.NumMembers == 0 {
continue
}
tempIds := make([]int64, 0, user.NumMembers)
orgUsers, err := GetOrgUsersByOrgId(user.Id)
memberIDs := make([]int64, 0, user.NumMembers)
orgUsers, err := GetOrgUsersByOrgID(user.Id)
if err != nil {
return err
return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.Id, err)
}
for _, orgUser := range orgUsers {
tempIds = append(tempIds, orgUser.ID)
memberIDs = append(memberIDs, orgUser.ID)
}
ids = append(ids, tempIds...)
ids = append(ids, memberIDs...)
}
if err := UpdateIssueUsersByMentions(ids, issueId); err != nil {
return err
if err := UpdateIssueUsersByMentions(issueID, ids); err != nil {
return fmt.Errorf("UpdateIssueUsersByMentions: %v", err)
}
return nil
@@ -736,7 +787,7 @@ func parseCountResult(results []map[string][]byte) int64 {
type IssueStatsOptions struct {
RepoID int64
UserID int64
LabelID int64
Labels string
MilestoneID int64
AssigneeID int64
FilterMode int
@@ -747,41 +798,60 @@ type IssueStatsOptions struct {
func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
stats := &IssueStats{}
queryStr := "SELECT COUNT(*) FROM `issue` "
if opts.LabelID > 0 {
queryStr += "INNER JOIN `issue_label` ON `issue`.id=`issue_label`.issue_id AND `issue_label`.label_id=" + com.ToStr(opts.LabelID)
}
countSession := func(opts *IssueStatsOptions) *xorm.Session {
sess := x.Where("issue.repo_id = ?", opts.RepoID).And("is_pull = ?", opts.IsPull)
baseCond := " WHERE issue.repo_id=" + com.ToStr(opts.RepoID) + " AND issue.is_closed=?"
if opts.MilestoneID > 0 {
baseCond += " AND issue.milestone_id=" + com.ToStr(opts.MilestoneID)
if len(opts.Labels) > 0 && opts.Labels != "0" {
labelIDs := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if len(labelIDs) > 0 {
sess.Join("INNER", "issue_label", "issue.id = issue_id").In("label_id", labelIDs)
}
}
if opts.MilestoneID > 0 {
sess.And("issue.milestone_id = ?", opts.MilestoneID)
}
if opts.AssigneeID > 0 {
sess.And("assignee_id = ?", opts.AssigneeID)
}
return sess
}
if opts.AssigneeID > 0 {
baseCond += " AND assignee_id=" + com.ToStr(opts.AssigneeID)
}
baseCond += " AND issue.is_pull=?"
switch opts.FilterMode {
case FM_ALL, FM_ASSIGN:
results, _ := x.Query(queryStr+baseCond, false, opts.IsPull)
stats.OpenCount = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond, true, opts.IsPull)
stats.ClosedCount = parseCountResult(results)
stats.OpenCount, _ = countSession(opts).
And("is_closed = ?", false).
Count(&Issue{})
stats.ClosedCount, _ = countSession(opts).
And("is_closed = ?", true).
Count(&Issue{})
case FM_CREATE:
baseCond += " AND poster_id=?"
results, _ := x.Query(queryStr+baseCond, false, opts.IsPull, opts.UserID)
stats.OpenCount = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond, true, opts.IsPull, opts.UserID)
stats.ClosedCount = parseCountResult(results)
stats.OpenCount, _ = countSession(opts).
And("poster_id = ?", opts.UserID).
And("is_closed = ?", false).
Count(&Issue{})
stats.ClosedCount, _ = countSession(opts).
And("poster_id = ?", opts.UserID).
And("is_closed = ?", true).
Count(&Issue{})
case FM_MENTION:
queryStr += " INNER JOIN `issue_user` ON `issue`.id=`issue_user`.issue_id"
baseCond += " AND `issue_user`.uid=? AND `issue_user`.is_mentioned=?"
results, _ := x.Query(queryStr+baseCond, false, opts.IsPull, opts.UserID, true)
stats.OpenCount = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond, true, opts.IsPull, opts.UserID, true)
stats.ClosedCount = parseCountResult(results)
stats.OpenCount, _ = countSession(opts).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.uid = ?", opts.UserID).
And("issue_user.is_mentioned = ?", true).
And("issue.is_closed = ?", false).
Count(&Issue{})
stats.ClosedCount, _ = countSession(opts).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.uid = ?", opts.UserID).
And("issue_user.is_mentioned = ?", true).
And("issue.is_closed = ?", true).
Count(&Issue{})
}
return stats
}
@@ -790,64 +860,70 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPull bool) *IssueStats {
stats := &IssueStats{}
queryStr := "SELECT COUNT(*) FROM `issue` "
baseCond := " WHERE issue.is_closed=?"
if repoID > 0 || len(repoIDs) == 0 {
baseCond += " AND issue.repo_id=" + com.ToStr(repoID)
} else {
baseCond += " AND issue.repo_id IN (" + strings.Join(base.Int64sToStrings(repoIDs), ",") + ")"
countSession := func(isClosed, isPull bool, repoID int64, repoIDs []int64) *xorm.Session {
sess := x.Where("issue.is_closed = ?", isClosed).And("issue.is_pull = ?", isPull)
if repoID > 0 || len(repoIDs) == 0 {
sess.And("repo_id = ?", repoID)
} else {
sess.In("repo_id", repoIDs)
}
return sess
}
if isPull {
baseCond += " AND issue.is_pull=1"
} else {
baseCond += " AND issue.is_pull=0"
}
stats.AssignCount, _ = countSession(false, isPull, repoID, repoIDs).
And("assignee_id = ?", uid).
Count(&Issue{})
results, _ := x.Query(queryStr+baseCond+" AND assignee_id=?", false, uid)
stats.AssignCount = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond+" AND poster_id=?", false, uid)
stats.CreateCount = parseCountResult(results)
stats.CreateCount, _ = countSession(false, isPull, repoID, repoIDs).
And("assignee_id = ?", uid).
Count(&Issue{})
openCountSession := countSession(false, isPull, repoID, repoIDs)
closedCountSession := countSession(true, isPull, repoID, repoIDs)
switch filterMode {
case FM_ASSIGN:
baseCond += " AND assignee_id=" + com.ToStr(uid)
openCountSession.And("assignee_id = ?", uid)
closedCountSession.And("assignee_id = ?", uid)
case FM_CREATE:
baseCond += " AND poster_id=" + com.ToStr(uid)
openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid)
}
results, _ = x.Query(queryStr+baseCond, false)
stats.OpenCount = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond, true)
stats.ClosedCount = parseCountResult(results)
stats.OpenCount, _ = openCountSession.Count(&Issue{})
stats.ClosedCount, _ = closedCountSession.Count(&Issue{})
return stats
}
// GetRepoIssueStats returns number of open and closed repository issues by given filter mode.
func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen int64, numClosed int64) {
queryStr := "SELECT COUNT(*) FROM `issue` "
baseCond := " WHERE issue.repo_id=? AND issue.is_closed=?"
countSession := func(isClosed, isPull bool, repoID int64) *xorm.Session {
sess := x.Where("issue.repo_id = ?", isClosed).
And("is_pull = ?", isPull).
And("repo_id = ?", repoID)
if isPull {
baseCond += " AND issue.is_pull=1"
} else {
baseCond += " AND issue.is_pull=0"
return sess
}
openCountSession := countSession(false, isPull, repoID)
closedCountSession := countSession(true, isPull, repoID)
switch filterMode {
case FM_ASSIGN:
baseCond += " AND assignee_id=" + com.ToStr(uid)
openCountSession.And("assignee_id = ?", uid)
closedCountSession.And("assignee_id = ?", uid)
case FM_CREATE:
baseCond += " AND poster_id=" + com.ToStr(uid)
openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid)
}
results, _ := x.Query(queryStr+baseCond, repoID, false)
numOpen = parseCountResult(results)
results, _ = x.Query(queryStr+baseCond, repoID, true)
numClosed = parseCountResult(results)
return numOpen, numClosed
openResult, _ := openCountSession.Count(&Issue{})
closedResult, _ := closedCountSession.Count(&Issue{})
return openResult, closedResult
}
func updateIssue(e Engine, issue *Issue) error {
@@ -913,9 +989,12 @@ func UpdateIssueUserByRead(uid, issueID int64) error {
}
// UpdateIssueUsersByMentions updates issue-user pairs by mentioning.
func UpdateIssueUsersByMentions(uids []int64, iid int64) error {
func UpdateIssueUsersByMentions(issueID int64, uids []int64) error {
for _, uid := range uids {
iu := &IssueUser{UID: uid, IssueID: iid}
iu := &IssueUser{
UID: uid,
IssueID: issueID,
}
has, err := x.Get(iu)
if err != nil {
return err
@@ -951,12 +1030,19 @@ type Milestone struct {
IsClosed bool
NumIssues int
NumClosedIssues int
NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100).
Deadline time.Time
DeadlineString string `xorm:"-"`
IsOverDue bool `xorm:"-"`
ClosedDate time.Time
NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100).
IsOverDue bool `xorm:"-"`
DeadlineString string `xorm:"-"`
Deadline time.Time `xorm:"-"`
DeadlineUnix int64
ClosedDate time.Time `xorm:"-"`
ClosedDateUnix int64
}
func (m *Milestone) BeforeInsert() {
m.DeadlineUnix = m.Deadline.UTC().Unix()
}
func (m *Milestone) BeforeUpdate() {
@@ -965,25 +1051,38 @@ func (m *Milestone) BeforeUpdate() {
} else {
m.Completeness = 0
}
m.DeadlineUnix = m.Deadline.UTC().Unix()
m.ClosedDateUnix = m.ClosedDate.UTC().Unix()
}
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
if colName == "deadline" {
switch colName {
case "num_closed_issues":
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
case "deadline_unix":
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
if m.Deadline.Year() == 9999 {
return
}
m.Deadline = regulateTimeZone(m.Deadline)
m.DeadlineString = m.Deadline.Format("2006-01-02")
if time.Now().After(m.Deadline) {
if time.Now().Local().After(m.Deadline) {
m.IsOverDue = true
}
case "closed_date_unix":
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
}
}
// CalOpenIssues calculates the open issues of milestone.
func (m *Milestone) CalOpenIssues() {
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
// State returns string representation of milestone status.
func (m *Milestone) State() string {
if m.IsClosed {
return "closed"
}
return "open"
}
// NewMilestone creates new milestone of repository.
@@ -1252,7 +1351,20 @@ type Attachment struct {
CommentID int64
ReleaseID int64 `xorm:"INDEX"`
Name string
Created time.Time `xorm:"CREATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (a *Attachment) BeforeInsert() {
a.CreatedUnix = time.Now().UTC().Unix()
}
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.

View File

@@ -13,6 +13,7 @@ import (
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
)
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
@@ -52,9 +53,11 @@ type Comment struct {
IssueID int64 `xorm:"INDEX"`
CommitID int64
Line int64
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
Created time.Time `xorm:"CREATED"`
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
Created time.Time `xorm:"-"`
CreatedUnix int64
// Reference issue in commit message
CommitSHA string `xorm:"VARCHAR(40)"`
@@ -65,6 +68,10 @@ type Comment struct {
ShowTag CommentTag `xorm:"-"`
}
func (c *Comment) BeforeInsert() {
c.CreatedUnix = time.Now().UTC().Unix()
}
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -84,8 +91,8 @@ func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
log.Error(3, "GetUserByID[%d]: %v", c.ID, err)
}
}
case "created":
c.Created = regulateTimeZone(c.Created)
case "created_unix":
c.Created = time.Unix(c.CreatedUnix, 0).Local()
}
}
@@ -107,10 +114,34 @@ func (c *Comment) EventTag() string {
return "event-" + com.ToStr(c.ID)
}
// MailParticipants sends new comment emails to repository watchers
// and mentioned people.
func (cmt *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) {
mentions := markdown.FindAllMentions(cmt.Content)
if err = UpdateIssueMentions(cmt.IssueID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", cmt.IssueID, err)
}
switch opType {
case ACTION_COMMENT_ISSUE:
issue.Content = cmt.Content
case ACTION_CLOSE_ISSUE:
issue.Content = fmt.Sprintf("Closed #%d", issue.Index)
case ACTION_REOPEN_ISSUE:
issue.Content = fmt.Sprintf("Reopened #%d", issue.Index)
}
if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil {
log.Error(4, "mailIssueCommentToParticipants: %v", err)
}
return nil
}
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
comment := &Comment{
Type: opts.Type,
PosterID: opts.Doer.Id,
Poster: opts.Doer,
IssueID: opts.Issue.ID,
CommitID: opts.CommitID,
CommitSHA: opts.CommitSHA,
@@ -151,7 +182,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
if IsErrAttachmentNotExist(err) {
continue
}
return nil, fmt.Errorf("getAttachmentByUUID[%s]: %v", uuid, err)
return nil, fmt.Errorf("getAttachmentByUUID [%s]: %v", uuid, err)
}
attachments = append(attachments, attach)
}
@@ -161,7 +192,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
attachments[i].CommentID = comment.ID
// No assign value could be 0, so ignore AllCols().
if _, err = e.Id(attachments[i].ID).Update(attachments[i]); err != nil {
return nil, fmt.Errorf("update attachment[%d]: %v", attachments[i].ID, err)
return nil, fmt.Errorf("update attachment [%d]: %v", attachments[i].ID, err)
}
}
@@ -194,11 +225,15 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
if err != nil {
return nil, err
}
}
// Notify watchers for whatever action comes in
if err = notifyWatchers(e, act); err != nil {
return nil, fmt.Errorf("notifyWatchers: %v", err)
// Notify watchers for whatever action comes in, ignore if no action type.
if act.OpType > 0 {
if err = notifyWatchers(e, act); err != nil {
log.Error(4, "notifyWatchers: %v", err)
}
comment.MailParticipants(act.OpType, opts.Issue)
}
return comment, nil
@@ -302,7 +337,7 @@ func GetCommentByID(id int64) (*Comment, error) {
// GetCommentsByIssueID returns all comments of issue by given ID.
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
comments := make([]*Comment, 0, 10)
return comments, x.Where("issue_id=?", issueID).Asc("created").Find(&comments)
return comments, x.Where("issue_id=?", issueID).Asc("created_unix").Find(&comments)
}
// UpdateComment updates information of comment.

81
models/issue_mail.go Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2016 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"
"github.com/Unknwon/com"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
func (issue *Issue) MailSubject() string {
return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.Name, issue.Name, issue.Index)
}
// mailIssueCommentToParticipants can be used for both new issue creation and comment.
func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error {
if !setting.Service.EnableNotifyMail {
return nil
}
// Mail wahtcers.
watchers, err := GetWatchers(issue.RepoID)
if err != nil {
return fmt.Errorf("GetWatchers [%d]: %v", issue.RepoID, err)
}
tos := make([]string, 0, len(watchers)) // List of email addresses.
names := make([]string, 0, len(watchers))
for i := range watchers {
if watchers[i].UserID == doer.Id {
continue
}
to, err := GetUserByID(watchers[i].UserID)
if err != nil {
return fmt.Errorf("GetUserByID [%d]: %v", watchers[i].UserID, err)
}
if to.IsOrganization() {
continue
}
tos = append(tos, to.Email)
names = append(names, to.Name)
}
SendIssueCommentMail(issue, doer, tos)
// Mail mentioned people and exclude watchers.
names = append(names, doer.Name)
tos = make([]string, 0, len(mentions)) // list of user names.
for i := range mentions {
if com.IsSliceContainsStr(names, mentions[i]) {
continue
}
tos = append(tos, mentions[i])
}
SendIssueMentionMail(issue, doer, GetUserEmailsByNames(tos))
return nil
}
// MailParticipants sends new issue thread created emails to repository watchers
// and mentioned people.
func (issue *Issue) MailParticipants() (err error) {
mentions := markdown.FindAllMentions(issue.Content)
if err = UpdateIssueMentions(issue.ID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
}
if err = mailIssueCommentToParticipants(issue, issue.Poster, mentions); err != nil {
log.Error(4, "mailIssueCommentToParticipants: %v", err)
}
return nil
}

View File

@@ -15,6 +15,7 @@ import (
"time"
"github.com/Unknwon/com"
"github.com/go-macaron/binding"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
@@ -23,6 +24,11 @@ import (
"github.com/gogits/gogs/modules/log"
)
var (
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
)
type LoginType int
// Note: new type must be added at the end of list to maintain compatibility.
@@ -35,11 +41,6 @@ const (
LOGIN_DLDAP // 5
)
var (
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
)
var LoginNames = map[LoginType]string{
LOGIN_LDAP: "LDAP (via BindDN)",
LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind
@@ -47,6 +48,12 @@ var LoginNames = map[LoginType]string{
LOGIN_PAM: "PAM",
}
var SecurityProtocolNames = map[ldap.SecurityProtocol]string{
ldap.SECURITY_PROTOCOL_UNENCRYPTED: "Unencrypted",
ldap.SECURITY_PROTOCOL_LDAPS: "LDAPS",
ldap.SECURITY_PROTOCOL_START_TLS: "StartTLS",
}
// Ensure structs implemented interface.
var (
_ core.Conversion = &LDAPConfig{}
@@ -66,6 +73,10 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg)
}
func (cfg *LDAPConfig) SecurityProtocolName() string {
return SecurityProtocolNames[cfg.SecurityProtocol]
}
type SMTPConfig struct {
Auth string
Host string
@@ -101,8 +112,20 @@ type LoginSource struct {
Name string `xorm:"UNIQUE"`
IsActived bool `xorm:"NOT NULL DEFAULT false"`
Cfg core.Conversion `xorm:"TEXT"`
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
}
func (s *LoginSource) BeforeInsert() {
s.CreatedUnix = time.Now().UTC().Unix()
s.UpdatedUnix = s.CreatedUnix
}
func (s *LoginSource) BeforeUpdate() {
s.UpdatedUnix = time.Now().UTC().Unix()
}
// Cell2Int64 converts a xorm.Cell type to int64,
@@ -132,6 +155,15 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
}
}
func (s *LoginSource) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
s.Created = time.Unix(s.CreatedUnix, 0).Local()
case "updated_unix":
s.Updated = time.Unix(s.UpdatedUnix, 0).Local()
}
}
func (source *LoginSource) TypeName() string {
return LoginNames[source.Type]
}
@@ -152,10 +184,16 @@ func (source *LoginSource) IsPAM() bool {
return source.Type == LOGIN_PAM
}
func (source *LoginSource) HasTLS() bool {
return ((source.IsLDAP() || source.IsDLDAP()) &&
source.LDAP().SecurityProtocol > ldap.SECURITY_PROTOCOL_UNENCRYPTED) ||
source.IsSMTP()
}
func (source *LoginSource) UseTLS() bool {
switch source.Type {
case LOGIN_LDAP, LOGIN_DLDAP:
return source.LDAP().UseSSL
return source.LDAP().SecurityProtocol != ldap.SECURITY_PROTOCOL_UNENCRYPTED
case LOGIN_SMTP:
return source.SMTP().TLS
}
@@ -243,7 +281,7 @@ func DeleteSource(source *LoginSource) error {
func LoginUserLDAPSource(u *User, loginName, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
cfg := source.Cfg.(*LDAPConfig)
directBind := (source.Type == LOGIN_DLDAP)
name, fn, sn, mail, admin, logged := cfg.SearchEntry(loginName, passwd, directBind)
username, fn, sn, mail, isAdmin, logged := cfg.SearchEntry(loginName, passwd, directBind)
if !logged {
// User not in LDAP, do nothing
return nil, ErrUserNotExist{0, loginName}
@@ -254,37 +292,42 @@ func LoginUserLDAPSource(u *User, loginName, passwd string, source *LoginSource,
}
// Fallback.
if len(name) == 0 {
name = loginName
if len(username) == 0 {
username = loginName
}
// Validate username make sure it satisfies requirement.
if !binding.AlphaDashDotPattern.MatchString(username) {
return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", username)
}
if len(mail) == 0 {
mail = fmt.Sprintf("%s@localhost", name)
mail = fmt.Sprintf("%s@localhost", username)
}
u = &User{
LowerName: strings.ToLower(name),
Name: name,
FullName: composeFullName(fn, sn, name),
LowerName: strings.ToLower(username),
Name: username,
FullName: composeFullName(fn, sn, username),
LoginType: source.Type,
LoginSource: source.ID,
LoginName: loginName,
Email: mail,
IsAdmin: admin,
IsAdmin: isAdmin,
IsActive: true,
}
return u, CreateUser(u)
}
func composeFullName(firstName, surename, userName string) string {
func composeFullName(firstname, surname, 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
case len(firstname) == 0 && len(surname) == 0:
return username
case len(firstname) == 0:
return surname
case len(surname) == 0:
return firstname
default:
return firstName + " " + surename
return firstname + " " + surname
}
}

183
models/mail.go Normal file
View File

@@ -0,0 +1,183 @@
// Copyright 2016 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"
"html/template"
"path"
"gopkg.in/gomail.v2"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
const (
MAIL_AUTH_ACTIVATE base.TplName = "auth/activate"
MAIL_AUTH_ACTIVATE_EMAIL base.TplName = "auth/activate_email"
MAIL_AUTH_RESET_PASSWORD base.TplName = "auth/reset_passwd"
MAIL_AUTH_REGISTER_NOTIFY base.TplName = "auth/register_notify"
MAIL_ISSUE_COMMENT base.TplName = "issue/comment"
MAIL_ISSUE_MENTION base.TplName = "issue/mention"
MAIL_NOTIFY_COLLABORATOR base.TplName = "notify/collaborator"
)
type MailRender interface {
HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error)
}
var mailRender MailRender
func InitMailRender(dir, appendDir string, funcMap []template.FuncMap) {
opt := &macaron.RenderOptions{
Directory: dir,
AppendDirectories: []string{appendDir},
Funcs: funcMap,
Extensions: []string{".tmpl", ".html"},
}
ts := macaron.NewTemplateSet()
ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt)
mailRender = &macaron.TplRender{
TemplateSet: ts,
Opt: opt,
}
}
func SendTestMail(email string) error {
return gomail.Send(&mailer.Sender{}, mailer.NewMessage([]string{email}, "Gogs Test Email!", "Gogs Test Email!").Message)
}
func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject, info string) {
data := map[string]interface{}{
"Username": u.DisplayName(),
"ActiveCodeLives": setting.Service.ActiveCodeLives / 60,
"ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60,
"Code": code,
}
body, err := mailRender.HTMLString(string(tpl), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, %s", u.Id, info)
mailer.SendAsync(msg)
}
func SendActivateAccountMail(c *macaron.Context, u *User) {
SendUserMail(c, u, MAIL_AUTH_ACTIVATE, u.GenerateActivateCode(), c.Tr("mail.activate_account"), "activate account")
}
func SendResetPasswordMail(c *macaron.Context, u *User) {
SendUserMail(c, u, MAIL_AUTH_RESET_PASSWORD, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "reset password")
}
// SendActivateAccountMail sends confirmation email.
func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) {
data := map[string]interface{}{
"Username": u.DisplayName(),
"ActiveCodeLives": setting.Service.ActiveCodeLives / 60,
"Code": u.GenerateEmailActivateCode(email.Email),
"Email": email.Email,
}
body, err := mailRender.HTMLString(string(MAIL_AUTH_ACTIVATE_EMAIL), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
return
}
msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), body)
msg.Info = fmt.Sprintf("UID: %d, activate email", u.Id)
mailer.SendAsync(msg)
}
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
func SendRegisterNotifyMail(c *macaron.Context, u *User) {
data := map[string]interface{}{
"Username": u.DisplayName(),
}
body, err := mailRender.HTMLString(string(MAIL_AUTH_REGISTER_NOTIFY), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), body)
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.Id)
mailer.SendAsync(msg)
}
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail(u, doer *User, repo *Repository) {
repoName := path.Join(repo.Owner.Name, repo.Name)
subject := fmt.Sprintf("%s added you to %s", doer.DisplayName(), repoName)
data := map[string]interface{}{
"Subject": subject,
"RepoName": repoName,
"Link": repo.FullLink(),
}
body, err := mailRender.HTMLString(string(MAIL_NOTIFY_COLLABORATOR), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.Id)
mailer.SendAsync(msg)
}
func composeTplData(subject, body, link string) map[string]interface{} {
data := make(map[string]interface{}, 10)
data["Subject"] = subject
data["Body"] = body
data["Link"] = link
return data
}
func composeIssueMessage(issue *Issue, doer *User, tplName base.TplName, tos []string, info string) *mailer.Message {
subject := issue.MailSubject()
body := string(markdown.RenderSpecialLink([]byte(issue.Content), issue.Repo.FullLink(), issue.Repo.ComposeMetas()))
data := composeTplData(subject, body, issue.FullLink())
data["Doer"] = doer
content, err := mailRender.HTMLString(string(tplName), data)
if err != nil {
log.Error(3, "HTMLString (%s): %v", tplName, err)
}
msg := mailer.NewMessage(tos, subject, content)
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
return msg
}
// SendIssueCommentMail composes and sends issue comment emails to target receivers.
func SendIssueCommentMail(issue *Issue, doer *User, tos []string) {
if len(tos) == 0 {
return
}
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_COMMENT, tos, "issue comment"))
}
// SendIssueMentionMail composes and sends issue mention emails to target receivers.
func SendIssueMentionMail(issue *Issue, doer *User, tos []string) {
if len(tos) == 0 {
return
}
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_MENTION, tos, "issue mention"))
}

View File

@@ -13,6 +13,7 @@ import (
"path"
"path/filepath"
"strings"
"time"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
@@ -50,7 +51,7 @@ func (m *migration) Migrate(x *xorm.Engine) error {
// The version table. Should have only one row with id==1
type Version struct {
Id int64
ID int64 `xorm:"pk autoincr"`
Version int64
}
@@ -58,13 +59,15 @@ type Version struct {
// If you want to "retire" a migration, remove it from the top of the list and
// update _MIN_VER_DB accordingly
var migrations = []Migration{
NewMigration("fix locale file load panic", fixLocaleFileLoadPanic), // V4 -> V5:v0.6.0
NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix), // V5 -> V6:v0.6.3
NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20
NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
NewMigration("fix locale file load panic", fixLocaleFileLoadPanic), // V4 -> V5:v0.6.0
NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix), // V5 -> V6:v0.6.3
NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20
NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
NewMigration("convert date to unix timestamp", convertDateToUnix), // V11 -> V12:v0.9.2
NewMigration("convert LDAP UseSSL option to SecurityProtocol", ldapUseSSLToSecurityProtocol), // V12 -> V13:v0.9.37
}
// Migrate database to current version
@@ -73,7 +76,7 @@ func Migrate(x *xorm.Engine) error {
return fmt.Errorf("sync: %v", err)
}
currentVersion := &Version{Id: 1}
currentVersion := &Version{ID: 1}
has, err := x.Get(currentVersion)
if err != nil {
return fmt.Errorf("get: %v", err)
@@ -453,3 +456,222 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
return sess.Commit()
}
type TAction struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
func (t *TAction) TableName() string { return "action" }
type TNotice struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
func (t *TNotice) TableName() string { return "notice" }
type TComment struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
func (t *TComment) TableName() string { return "comment" }
type TIssue struct {
ID int64 `xorm:"pk autoincr"`
DeadlineUnix int64
CreatedUnix int64
UpdatedUnix int64
}
func (t *TIssue) TableName() string { return "issue" }
type TMilestone struct {
ID int64 `xorm:"pk autoincr"`
DeadlineUnix int64
ClosedDateUnix int64
}
func (t *TMilestone) TableName() string { return "milestone" }
type TAttachment struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
func (t *TAttachment) TableName() string { return "attachment" }
type TLoginSource struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TLoginSource) TableName() string { return "login_source" }
type TPull struct {
ID int64 `xorm:"pk autoincr"`
MergedUnix int64
}
func (t *TPull) TableName() string { return "pull_request" }
type TRelease struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
func (t *TRelease) TableName() string { return "release" }
type TRepo struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TRepo) TableName() string { return "repository" }
type TMirror struct {
ID int64 `xorm:"pk autoincr"`
UpdatedUnix int64
NextUpdateUnix int64
}
func (t *TMirror) TableName() string { return "mirror" }
type TPublicKey struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TPublicKey) TableName() string { return "public_key" }
type TDeployKey struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TDeployKey) TableName() string { return "deploy_key" }
type TAccessToken struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TAccessToken) TableName() string { return "access_token" }
type TUser struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TUser) TableName() string { return "user" }
type TWebhook struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
func (t *TWebhook) TableName() string { return "webhook" }
func convertDateToUnix(x *xorm.Engine) (err error) {
log.Info("This migration could take up to minutes, please be patient.")
type Bean struct {
ID int64 `xorm:"pk autoincr"`
Created time.Time
Updated time.Time
Merged time.Time
Deadline time.Time
ClosedDate time.Time
NextUpdate time.Time
}
var tables = []struct {
name string
cols []string
bean interface{}
}{
{"action", []string{"created"}, new(TAction)},
{"notice", []string{"created"}, new(TNotice)},
{"comment", []string{"created"}, new(TComment)},
{"issue", []string{"deadline", "created", "updated"}, new(TIssue)},
{"milestone", []string{"deadline", "closed_date"}, new(TMilestone)},
{"attachment", []string{"created"}, new(TAttachment)},
{"login_source", []string{"created", "updated"}, new(TLoginSource)},
{"pull_request", []string{"merged"}, new(TPull)},
{"release", []string{"created"}, new(TRelease)},
{"repository", []string{"created", "updated"}, new(TRepo)},
{"mirror", []string{"updated", "next_update"}, new(TMirror)},
{"public_key", []string{"created", "updated"}, new(TPublicKey)},
{"deploy_key", []string{"created", "updated"}, new(TDeployKey)},
{"access_token", []string{"created", "updated"}, new(TAccessToken)},
{"user", []string{"created", "updated"}, new(TUser)},
{"webhook", []string{"created", "updated"}, new(TWebhook)},
}
for _, table := range tables {
log.Info("Converting table: %s", table.name)
if err = x.Sync2(table.bean); err != nil {
return fmt.Errorf("Sync [table: %s]: %v", table.name, err)
}
offset := 0
for {
beans := make([]*Bean, 0, 100)
if err = x.Sql(fmt.Sprintf("SELECT * FROM `%s` ORDER BY id ASC LIMIT 100 OFFSET %d",
table.name, offset)).Find(&beans); err != nil {
return fmt.Errorf("select beans [table: %s, offset: %d]: %v", table.name, offset, err)
}
log.Trace("Table [%s]: offset: %d, beans: %d", table.name, offset, len(beans))
if len(beans) == 0 {
break
}
offset += 100
baseSQL := "UPDATE `" + table.name + "` SET "
for _, bean := range beans {
valSQLs := make([]string, 0, len(table.cols))
for _, col := range table.cols {
fieldSQL := ""
fieldSQL += col + "_unix = "
switch col {
case "deadline":
if bean.Deadline.IsZero() {
continue
}
fieldSQL += com.ToStr(bean.Deadline.UTC().Unix())
case "created":
fieldSQL += com.ToStr(bean.Created.UTC().Unix())
case "updated":
fieldSQL += com.ToStr(bean.Updated.UTC().Unix())
case "closed_date":
fieldSQL += com.ToStr(bean.ClosedDate.UTC().Unix())
case "merged":
fieldSQL += com.ToStr(bean.Merged.UTC().Unix())
case "next_update":
fieldSQL += com.ToStr(bean.NextUpdate.UTC().Unix())
}
valSQLs = append(valSQLs, fieldSQL)
}
if len(valSQLs) == 0 {
continue
}
if _, err = x.Exec(baseSQL + strings.Join(valSQLs, ",") + " WHERE id = " + com.ToStr(bean.ID)); err != nil {
return fmt.Errorf("update bean [table: %s, id: %d]: %v", table.name, bean.ID, err)
}
}
}
}
return nil
}

52
models/migrations/v13.go Normal file
View File

@@ -0,0 +1,52 @@
// Copyright 2016 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 migrations
import (
"encoding/json"
"fmt"
"strings"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
)
func ldapUseSSLToSecurityProtocol(x *xorm.Engine) error {
results, err := x.Query("SELECT `id`,`cfg` FROM `login_source` WHERE `type` = 2 OR `type` = 5")
if err != nil {
if strings.Contains(err.Error(), "no such column") {
return nil
}
return fmt.Errorf("select LDAP login sources: %v", err)
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
for _, result := range results {
cfg := map[string]interface{}{}
if err = json.Unmarshal(result["cfg"], &cfg); err != nil {
return fmt.Errorf("decode JSON config: %v", err)
}
if com.ToStr(cfg["UseSSL"]) == "true" {
cfg["SecurityProtocol"] = 1 // LDAPS
}
delete(cfg, "UseSSL")
data, err := json.Marshal(&cfg)
if err != nil {
return fmt.Errorf("encode JSON config: %v", err)
}
if _, err = sess.Exec("UPDATE `login_source` SET `cfg`=? WHERE `id`=?",
string(data), com.StrTo(result["id"]).MustInt64()); err != nil {
return fmt.Errorf("update config column: %v", err)
}
}
return sess.Commit()
}

View File

@@ -11,16 +11,13 @@ import (
"os"
"path"
"strings"
"time"
"github.com/Unknwon/com"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
_ "github.com/lib/pq"
"github.com/gogits/gogs/models/migrations"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -44,27 +41,6 @@ func sessionRelease(sess *xorm.Session) {
sess.Close()
}
// Note: get back time.Time from database Go sees it at UTC where they are really Local.
// So this function makes correct timezone offset.
func regulateTimeZone(t time.Time) time.Time {
if !setting.UseMySQL {
return t
}
zone := t.Local().Format("-0700")
if len(zone) != 5 {
log.Error(4, "Unprocessable timezone: %s - %s", t.Local(), zone)
return t
}
hour := com.StrTo(zone[2:3]).MustInt()
minutes := com.StrTo(zone[3:5]).MustInt()
if zone[0] == '-' {
return t.Add(time.Duration(hour) * time.Hour).Add(time.Duration(minutes) * time.Minute)
}
return t.Add(-1 * time.Duration(hour) * time.Hour).Add(-1 * time.Duration(minutes) * time.Minute)
}
var (
x *xorm.Engine
tables []interface{}
@@ -121,14 +97,18 @@ func LoadConfigs() {
func getEngine() (*xorm.Engine, error) {
cnnstr := ""
var Param string = "?"
if strings.Contains(DbCfg.Name,Param) {
Param="&"
}
switch DbCfg.Type {
case "mysql":
if DbCfg.Host[0] == '/' { // looks like a unix socket
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s?charset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
} else {
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
}
case "postgres":
var host, port = "127.0.0.1", "5432"
@@ -139,8 +119,8 @@ func getEngine() (*xorm.Engine, error) {
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
port = fields[1]
}
cnnstr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, DbCfg.SSLMode)
cnnstr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
case "sqlite3":
if !EnableSQLite3 {
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)

View File

@@ -58,7 +58,7 @@ func (org *User) GetTeams() error {
// GetMembers returns all members of organization.
func (org *User) GetMembers() error {
ous, err := GetOrgUsersByOrgId(org.Id)
ous, err := GetOrgUsersByOrgID(org.Id)
if err != nil {
return err
}
@@ -169,7 +169,7 @@ func GetOrgByName(name string) (*User, error) {
}
u := &User{
LowerName: strings.ToLower(name),
Type: ORGANIZATION,
Type: USER_TYPE_ORGANIZATION,
}
has, err := x.Get(u)
if err != nil {
@@ -306,10 +306,10 @@ func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
return ous, err
}
// GetOrgUsersByOrgId returns all organization-user relations by organization ID.
func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
ous := make([]*OrgUser, 0, 10)
err := x.Where("org_id=?", orgId).Find(&ous)
err := x.Where("org_id=?", orgID).Find(&ous)
return ous, err
}
@@ -426,618 +426,6 @@ func RemoveOrgUser(orgId, uid int64) error {
return sess.Commit()
}
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// | |\ ___/ / __ \| Y Y \
// |____| \___ >____ /__|_| /
// \/ \/ \/
const OWNER_TEAM = "Owners"
// Team represents a organization team.
type Team struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
LowerName string
Name string
Description string
Authorize AccessMode
Repos []*Repository `xorm:"-"`
Members []*User `xorm:"-"`
NumRepos int
NumMembers int
}
// IsOwnerTeam returns true if team is owner team.
func (t *Team) IsOwnerTeam() bool {
return t.Name == OWNER_TEAM
}
// IsTeamMember returns true if given user is a member of team.
func (t *Team) IsMember(uid int64) bool {
return IsTeamMember(t.OrgID, t.ID, uid)
}
func (t *Team) getRepositories(e Engine) (err error) {
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
return fmt.Errorf("get team-repos: %v", err)
}
t.Repos = make([]*Repository, 0, len(teamRepos))
for i := range teamRepos {
repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
if err != nil {
return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
}
t.Repos = append(t.Repos, repo)
}
return nil
}
// GetRepositories returns all repositories in team of organization.
func (t *Team) GetRepositories() error {
return t.getRepositories(x)
}
func (t *Team) getMembers(e Engine) (err error) {
t.Members, err = getTeamMembers(e, t.ID)
return err
}
// GetMembers returns all members in team of organization.
func (t *Team) GetMembers() (err error) {
return t.getMembers(x)
}
// AddMember adds new member to team of organization.
func (t *Team) AddMember(uid int64) error {
return AddTeamMember(t.OrgID, t.ID, uid)
}
// RemoveMember removes member from team of organization.
func (t *Team) RemoveMember(uid int64) error {
return RemoveTeamMember(t.OrgID, t.ID, uid)
}
func (t *Team) hasRepository(e Engine, repoID int64) bool {
return hasTeamRepo(e, t.OrgID, t.ID, repoID)
}
// HasRepository returns true if given repository belong to team.
func (t *Team) HasRepository(repoID int64) bool {
return t.hasRepository(x, repoID)
}
func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
return err
}
t.NumRepos++
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return fmt.Errorf("update team: %v", err)
}
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
return fmt.Errorf("recalculateAccesses: %v", err)
}
if err = t.getMembers(e); err != nil {
return fmt.Errorf("getMembers: %v", err)
}
for _, u := range t.Members {
if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
}
}
return nil
}
// AddRepository adds new repository to team of organization.
func (t *Team) AddRepository(repo *Repository) (err error) {
if repo.OwnerID != t.OrgID {
return errors.New("Repository does not belong to organization")
} else if t.HasRepository(repo.ID) {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = t.addRepository(sess, repo); err != nil {
return err
}
return sess.Commit()
}
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
return err
}
t.NumRepos--
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return err
}
// Don't need to recalculate when delete a repository from organization.
if recalculate {
if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
return err
}
}
if err = t.getMembers(e); err != nil {
return fmt.Errorf("get team members: %v", err)
}
for _, u := range t.Members {
has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
if err != nil {
return err
} else if has {
continue
}
if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
return err
}
}
return nil
}
// RemoveRepository removes repository from team of organization.
func (t *Team) RemoveRepository(repoID int64) error {
if !t.HasRepository(repoID) {
return nil
}
repo, err := GetRepositoryByID(repoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = t.removeRepository(sess, repo, true); err != nil {
return err
}
return sess.Commit()
}
// NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID.
func NewTeam(t *Team) error {
if len(t.Name) == 0 {
return errors.New("empty team name")
}
has, err := x.Id(t.OrgID).Get(new(User))
if err != nil {
return err
} else if !has {
return ErrOrgNotExist
}
t.LowerName = strings.ToLower(t.Name)
has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(new(Team))
if err != nil {
return err
} else if has {
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
}
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(t); err != nil {
sess.Rollback()
return err
}
// Update organization number of teams.
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
sess.Rollback()
return err
}
return sess.Commit()
}
func getTeam(e Engine, orgId int64, name string) (*Team, error) {
t := &Team{
OrgID: orgId,
LowerName: strings.ToLower(name),
}
has, err := e.Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
return t, nil
}
// GetTeam returns team by given team name and organization.
func GetTeam(orgId int64, name string) (*Team, error) {
return getTeam(x, orgId, name)
}
func getTeamById(e Engine, teamId int64) (*Team, error) {
t := new(Team)
has, err := e.Id(teamId).Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
return t, nil
}
// GetTeamById returns team by given ID.
func GetTeamById(teamId int64) (*Team, error) {
return getTeamById(x, teamId)
}
// UpdateTeam updates information of team.
func UpdateTeam(t *Team, authChanged bool) (err error) {
if len(t.Name) == 0 {
return errors.New("empty team name")
}
if len(t.Description) > 255 {
t.Description = t.Description[:255]
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
t.LowerName = strings.ToLower(t.Name)
has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
if err != nil {
return err
} else if has {
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
}
if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
return fmt.Errorf("update: %v", err)
}
// Update access for team members if needed.
if authChanged {
if err = t.getRepositories(sess); err != nil {
return fmt.Errorf("getRepositories:%v", err)
}
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
return fmt.Errorf("recalculateTeamAccesses: %v", err)
}
}
}
return sess.Commit()
}
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
func DeleteTeam(t *Team) error {
if err := t.GetRepositories(); err != nil {
return err
}
// Get organization.
org, err := GetUserByID(t.OrgID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
// Delete all accesses.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
return err
}
}
// Delete team-user.
if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
return err
}
// Delete team.
if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
return err
}
// Update organization number of teams.
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
return err
}
return sess.Commit()
}
// ___________ ____ ___
// \__ ___/___ _____ _____ | | \______ ___________
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
// |____| \___ >____ /__|_| /______//____ >\___ >__|
// \/ \/ \/ \/ \/
// TeamUser represents an team-user relation.
type TeamUser struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
Uid int64 `xorm:"UNIQUE(s)"`
}
func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
return has
}
// IsTeamMember returns true if given user is a member of team.
func IsTeamMember(orgID, teamID, uid int64) bool {
return isTeamMember(x, orgID, teamID, uid)
}
func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
teamUsers := make([]*TeamUser, 0, 10)
if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
return nil, fmt.Errorf("get team-users: %v", err)
}
members := make([]*User, 0, len(teamUsers))
for i := range teamUsers {
member := new(User)
if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
}
members = append(members, member)
}
return members, nil
}
// GetTeamMembers returns all members in given team of organization.
func GetTeamMembers(teamID int64) ([]*User, error) {
return getTeamMembers(x, teamID)
}
func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
tus := make([]*TeamUser, 0, 5)
if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
return nil, err
}
ts := make([]*Team, len(tus))
for i, tu := range tus {
t := new(Team)
has, err := e.Id(tu.TeamID).Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
ts[i] = t
}
return ts, nil
}
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
return getUserTeams(x, orgId, uid)
}
// AddTeamMember adds new member to given team of given organization.
func AddTeamMember(orgId, teamId, uid int64) error {
if IsTeamMember(orgId, teamId, uid) {
return nil
}
if err := AddOrgUser(orgId, uid); err != nil {
return err
}
// Get team and its repositories.
t, err := GetTeamById(teamId)
if err != nil {
return err
}
t.NumMembers++
if err = t.GetRepositories(); err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
tu := &TeamUser{
Uid: uid,
OrgID: orgId,
TeamID: teamId,
}
if _, err = sess.Insert(tu); err != nil {
return err
} else if _, err = sess.Id(t.ID).Update(t); err != nil {
return err
}
// Give access to team repositories.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
return err
}
}
// We make sure it exists before.
ou := new(OrgUser)
if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
return err
}
ou.NumTeams++
if t.IsOwnerTeam() {
ou.IsOwner = true
}
if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
return err
}
return sess.Commit()
}
func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
if !isTeamMember(e, orgId, teamId, uid) {
return nil
}
// Get team and its repositories.
t, err := getTeamById(e, teamId)
if err != nil {
return err
}
// Check if the user to delete is the last member in owner team.
if t.IsOwnerTeam() && t.NumMembers == 1 {
return ErrLastOrgOwner{UID: uid}
}
t.NumMembers--
if err = t.getRepositories(e); err != nil {
return err
}
// Get organization.
org, err := getUserByID(e, orgId)
if err != nil {
return err
}
tu := &TeamUser{
Uid: uid,
OrgID: orgId,
TeamID: teamId,
}
if _, err := e.Delete(tu); err != nil {
return err
} else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return err
}
// Delete access to team repositories.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
return err
}
}
// This must exist.
ou := new(OrgUser)
_, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
if err != nil {
return err
}
ou.NumTeams--
if t.IsOwnerTeam() {
ou.IsOwner = false
}
if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
return err
}
return nil
}
// RemoveTeamMember removes member from given team of given organization.
func RemoveTeamMember(orgId, teamId, uid int64) error {
sess := x.NewSession()
defer sessionRelease(sess)
if err := sess.Begin(); err != nil {
return err
}
if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
return err
}
return sess.Commit()
}
// ___________ __________
// \__ ___/___ _____ _____\______ \ ____ ______ ____
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
// | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
// |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
// \/ \/ \/ \/ \/|__|
// TeamRepo represents an team-repository relation.
type TeamRepo struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
RepoID int64 `xorm:"UNIQUE(s)"`
}
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
return has
}
// HasTeamRepo returns true if given repository belongs to team.
func HasTeamRepo(orgID, teamID, repoID int64) bool {
return hasTeamRepo(x, orgID, teamID, repoID)
}
func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
_, err := e.InsertOne(&TeamRepo{
OrgID: orgID,
TeamID: teamID,
RepoID: repoID,
})
return err
}
// AddTeamRepo adds new repository relation to team.
func AddTeamRepo(orgID, teamID, repoID int64) error {
return addTeamRepo(x, orgID, teamID, repoID)
}
func removeTeamRepo(e Engine, teamID, repoID int64) error {
_, err := e.Delete(&TeamRepo{
TeamID: teamID,
RepoID: repoID,
})
return err
}
// RemoveTeamRepo deletes repository relation to team.
func RemoveTeamRepo(teamID, repoID int64) error {
return removeTeamRepo(x, teamID, repoID)
}
func removeOrgRepo(e Engine, orgID, repoID int64) error {
_, err := e.Delete(&TeamRepo{
OrgID: orgID,
@@ -1055,7 +443,7 @@ func RemoveOrgRepo(orgID, repoID int64) error {
// that the user with the given userID has access to.
func (org *User) GetUserRepositories(userID int64) (err error) {
teams := make([]*Team, 0, org.NumTeams)
if err = x.Sql(`SELECT team.id FROM team
if err = x.Sql(`SELECT team.id FROM team
INNER JOIN team_user ON team_user.team_id = team.id
WHERE team_user.org_id = ? AND team_user.uid = ?`, org.Id, userID).Find(&teams); err != nil {
return fmt.Errorf("get teams: %v", err)
@@ -1071,11 +459,10 @@ WHERE team_user.org_id = ? AND team_user.uid = ?`, org.Id, userID).Find(&teams);
}
repos := make([]*Repository, 0, 5)
if err = x.Sql(`SELECT repository.* FROM repository
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
INNER JOIN team_repo ON team_repo.repo_id = repository.id
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (?)
GROUP BY repository.id`,
org.Id, false, strings.Join(teamIDs, ",")).Find(&repos); err != nil {
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
GROUP BY repository.id`, strings.Join(teamIDs, ",")), org.Id, false).Find(&repos); err != nil {
return fmt.Errorf("get repositories: %v", err)
}
org.Repos = repos
@@ -1097,6 +484,8 @@ WHERE team_user.org_id = ? AND team_user.uid = ?`,
return fmt.Errorf("get teams: %v", err)
}
org.Teams = teams
// FIXME: should I change this value inside method,
// or only in location of caller where it's really needed?
org.NumTeams = len(org.Teams)

618
models/org_team.go Normal file
View File

@@ -0,0 +1,618 @@
// Copyright 2016 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 (
"errors"
"fmt"
"strings"
)
const OWNER_TEAM = "Owners"
// Team represents a organization team.
type Team struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
LowerName string
Name string
Description string
Authorize AccessMode
Repos []*Repository `xorm:"-"`
Members []*User `xorm:"-"`
NumRepos int
NumMembers int
}
// IsOwnerTeam returns true if team is owner team.
func (t *Team) IsOwnerTeam() bool {
return t.Name == OWNER_TEAM
}
// IsTeamMember returns true if given user is a member of team.
func (t *Team) IsMember(uid int64) bool {
return IsTeamMember(t.OrgID, t.ID, uid)
}
func (t *Team) getRepositories(e Engine) (err error) {
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
return fmt.Errorf("get team-repos: %v", err)
}
t.Repos = make([]*Repository, 0, len(teamRepos))
for i := range teamRepos {
repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
if err != nil {
return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
}
t.Repos = append(t.Repos, repo)
}
return nil
}
// GetRepositories returns all repositories in team of organization.
func (t *Team) GetRepositories() error {
return t.getRepositories(x)
}
func (t *Team) getMembers(e Engine) (err error) {
t.Members, err = getTeamMembers(e, t.ID)
return err
}
// GetMembers returns all members in team of organization.
func (t *Team) GetMembers() (err error) {
return t.getMembers(x)
}
// AddMember adds new membership of the team to the organization,
// the user will have membership to the organization automatically when needed.
func (t *Team) AddMember(uid int64) error {
return AddTeamMember(t.OrgID, t.ID, uid)
}
// RemoveMember removes member from team of organization.
func (t *Team) RemoveMember(uid int64) error {
return RemoveTeamMember(t.OrgID, t.ID, uid)
}
func (t *Team) hasRepository(e Engine, repoID int64) bool {
return hasTeamRepo(e, t.OrgID, t.ID, repoID)
}
// HasRepository returns true if given repository belong to team.
func (t *Team) HasRepository(repoID int64) bool {
return t.hasRepository(x, repoID)
}
func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
return err
}
t.NumRepos++
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return fmt.Errorf("update team: %v", err)
}
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
return fmt.Errorf("recalculateAccesses: %v", err)
}
if err = t.getMembers(e); err != nil {
return fmt.Errorf("getMembers: %v", err)
}
for _, u := range t.Members {
if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
}
}
return nil
}
// AddRepository adds new repository to team of organization.
func (t *Team) AddRepository(repo *Repository) (err error) {
if repo.OwnerID != t.OrgID {
return errors.New("Repository does not belong to organization")
} else if t.HasRepository(repo.ID) {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = t.addRepository(sess, repo); err != nil {
return err
}
return sess.Commit()
}
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
return err
}
t.NumRepos--
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return err
}
// Don't need to recalculate when delete a repository from organization.
if recalculate {
if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
return err
}
}
if err = t.getMembers(e); err != nil {
return fmt.Errorf("get team members: %v", err)
}
for _, u := range t.Members {
has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
if err != nil {
return err
} else if has {
continue
}
if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
return err
}
}
return nil
}
// RemoveRepository removes repository from team of organization.
func (t *Team) RemoveRepository(repoID int64) error {
if !t.HasRepository(repoID) {
return nil
}
repo, err := GetRepositoryByID(repoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = t.removeRepository(sess, repo, true); err != nil {
return err
}
return sess.Commit()
}
// NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID.
func NewTeam(t *Team) error {
if len(t.Name) == 0 {
return errors.New("empty team name")
}
has, err := x.Id(t.OrgID).Get(new(User))
if err != nil {
return err
} else if !has {
return ErrOrgNotExist
}
t.LowerName = strings.ToLower(t.Name)
has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(new(Team))
if err != nil {
return err
} else if has {
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
}
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(t); err != nil {
sess.Rollback()
return err
}
// Update organization number of teams.
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
sess.Rollback()
return err
}
return sess.Commit()
}
func getTeam(e Engine, orgId int64, name string) (*Team, error) {
t := &Team{
OrgID: orgId,
LowerName: strings.ToLower(name),
}
has, err := e.Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
return t, nil
}
// GetTeam returns team by given team name and organization.
func GetTeam(orgId int64, name string) (*Team, error) {
return getTeam(x, orgId, name)
}
func getTeamByID(e Engine, teamId int64) (*Team, error) {
t := new(Team)
has, err := e.Id(teamId).Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
return t, nil
}
// GetTeamByID returns team by given ID.
func GetTeamByID(teamId int64) (*Team, error) {
return getTeamByID(x, teamId)
}
// UpdateTeam updates information of team.
func UpdateTeam(t *Team, authChanged bool) (err error) {
if len(t.Name) == 0 {
return errors.New("empty team name")
}
if len(t.Description) > 255 {
t.Description = t.Description[:255]
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
t.LowerName = strings.ToLower(t.Name)
has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
if err != nil {
return err
} else if has {
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
}
if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
return fmt.Errorf("update: %v", err)
}
// Update access for team members if needed.
if authChanged {
if err = t.getRepositories(sess); err != nil {
return fmt.Errorf("getRepositories:%v", err)
}
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
return fmt.Errorf("recalculateTeamAccesses: %v", err)
}
}
}
return sess.Commit()
}
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
func DeleteTeam(t *Team) error {
if err := t.GetRepositories(); err != nil {
return err
}
// Get organization.
org, err := GetUserByID(t.OrgID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
// Delete all accesses.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
return err
}
}
// Delete team-user.
if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
return err
}
// Delete team.
if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
return err
}
// Update organization number of teams.
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
return err
}
return sess.Commit()
}
// ___________ ____ ___
// \__ ___/___ _____ _____ | | \______ ___________
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
// |____| \___ >____ /__|_| /______//____ >\___ >__|
// \/ \/ \/ \/ \/
// TeamUser represents an team-user relation.
type TeamUser struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
Uid int64 `xorm:"UNIQUE(s)"`
}
func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
return has
}
// IsTeamMember returns true if given user is a member of team.
func IsTeamMember(orgID, teamID, uid int64) bool {
return isTeamMember(x, orgID, teamID, uid)
}
func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
teamUsers := make([]*TeamUser, 0, 10)
if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
return nil, fmt.Errorf("get team-users: %v", err)
}
members := make([]*User, 0, len(teamUsers))
for i := range teamUsers {
member := new(User)
if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
}
members = append(members, member)
}
return members, nil
}
// GetTeamMembers returns all members in given team of organization.
func GetTeamMembers(teamID int64) ([]*User, error) {
return getTeamMembers(x, teamID)
}
func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
tus := make([]*TeamUser, 0, 5)
if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
return nil, err
}
ts := make([]*Team, len(tus))
for i, tu := range tus {
t := new(Team)
has, err := e.Id(tu.TeamID).Get(t)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTeamNotExist
}
ts[i] = t
}
return ts, nil
}
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
return getUserTeams(x, orgId, uid)
}
// AddTeamMember adds new membership of given team to given organization,
// the user will have membership to given organization automatically when needed.
func AddTeamMember(orgID, teamID, uid int64) error {
if IsTeamMember(orgID, teamID, uid) {
return nil
}
if err := AddOrgUser(orgID, uid); err != nil {
return err
}
// Get team and its repositories.
t, err := GetTeamByID(teamID)
if err != nil {
return err
}
t.NumMembers++
if err = t.GetRepositories(); err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
tu := &TeamUser{
Uid: uid,
OrgID: orgID,
TeamID: teamID,
}
if _, err = sess.Insert(tu); err != nil {
return err
} else if _, err = sess.Id(t.ID).Update(t); err != nil {
return err
}
// Give access to team repositories.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
return err
}
}
// We make sure it exists before.
ou := new(OrgUser)
if _, err = sess.Where("uid = ?", uid).And("org_id = ?", orgID).Get(ou); err != nil {
return err
}
ou.NumTeams++
if t.IsOwnerTeam() {
ou.IsOwner = true
}
if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
return err
}
return sess.Commit()
}
func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
if !isTeamMember(e, orgID, teamID, uid) {
return nil
}
// Get team and its repositories.
t, err := getTeamByID(e, teamID)
if err != nil {
return err
}
// Check if the user to delete is the last member in owner team.
if t.IsOwnerTeam() && t.NumMembers == 1 {
return ErrLastOrgOwner{UID: uid}
}
t.NumMembers--
if err = t.getRepositories(e); err != nil {
return err
}
// Get organization.
org, err := getUserByID(e, orgID)
if err != nil {
return err
}
tu := &TeamUser{
Uid: uid,
OrgID: orgID,
TeamID: teamID,
}
if _, err := e.Delete(tu); err != nil {
return err
} else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
return err
}
// Delete access to team repositories.
for _, repo := range t.Repos {
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
return err
}
}
// This must exist.
ou := new(OrgUser)
_, err = e.Where("uid = ?", uid).And("org_id = ?", org.Id).Get(ou)
if err != nil {
return err
}
ou.NumTeams--
if t.IsOwnerTeam() {
ou.IsOwner = false
}
if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
return err
}
return nil
}
// RemoveTeamMember removes member from given team of given organization.
func RemoveTeamMember(orgID, teamID, uid int64) error {
sess := x.NewSession()
defer sessionRelease(sess)
if err := sess.Begin(); err != nil {
return err
}
if err := removeTeamMember(sess, orgID, teamID, uid); err != nil {
return err
}
return sess.Commit()
}
// ___________ __________
// \__ ___/___ _____ _____\______ \ ____ ______ ____
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
// | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
// |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
// \/ \/ \/ \/ \/|__|
// TeamRepo represents an team-repository relation.
type TeamRepo struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
RepoID int64 `xorm:"UNIQUE(s)"`
}
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
return has
}
// HasTeamRepo returns true if given repository belongs to team.
func HasTeamRepo(orgID, teamID, repoID int64) bool {
return hasTeamRepo(x, orgID, teamID, repoID)
}
func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
_, err := e.InsertOne(&TeamRepo{
OrgID: orgID,
TeamID: teamID,
RepoID: repoID,
})
return err
}
// AddTeamRepo adds new repository relation to team.
func AddTeamRepo(orgID, teamID, repoID int64) error {
return addTeamRepo(x, orgID, teamID, repoID)
}
func removeTeamRepo(e Engine, teamID, repoID int64) error {
_, err := e.Delete(&TeamRepo{
TeamID: teamID,
RepoID: repoID,
})
return err
}
// RemoveTeamRepo deletes repository relation to team.
func RemoveTeamRepo(teamID, repoID int64) error {
return removeTeamRepo(x, teamID, repoID)
}

View File

@@ -58,20 +58,25 @@ type PullRequest struct {
HasMerged bool
MergedCommitID string `xorm:"VARCHAR(40)"`
Merged time.Time
MergerID int64
Merger *User `xorm:"-"`
Merger *User `xorm:"-"`
Merged time.Time `xorm:"-"`
MergedUnix int64
}
func (pr *PullRequest) BeforeUpdate() {
pr.MergedUnix = pr.Merged.UTC().Unix()
}
// Note: don't try to get Pull because will end up recursive querying.
func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "merged":
case "merged_unix":
if !pr.HasMerged {
return
}
pr.Merged = regulateTimeZone(pr.Merged)
pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
}
}
@@ -231,7 +236,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
Before: pr.MergeBase,
After: pr.MergedCommitID,
CompareUrl: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullRepoLink()),
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullLink()),
Repo: pr.BaseRepo.ComposePayload(),
Pusher: &api.PayloadAuthor{
Name: pr.HeadRepo.MustOwner().DisplayName(),
@@ -337,9 +342,6 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}
if err = notifyWatchers(sess, act); err != nil {
return err
}
pr.Index = pull.Index
if err = repo.SavePatch(pr.Index, patch); err != nil {
@@ -359,7 +361,17 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
return fmt.Errorf("insert pull repo: %v", err)
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
if err = NotifyWatchers(act); err != nil {
log.Error(4, "NotifyWatchers: %v", err)
} else if err = pull.MailParticipants(); err != nil {
log.Error(4, "MailParticipants: %v", err)
}
return nil
}
// GetUnmergedPullRequest returnss a pull request that is open and has not been merged

View File

@@ -33,13 +33,19 @@ type Release struct {
Note string `xorm:"TEXT"`
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
IsPrerelease bool
Created time.Time `xorm:"CREATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (r *Release) BeforeInsert() {
r.CreatedUnix = time.Now().UTC().Unix()
}
func (r *Release) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created":
r.Created = regulateTimeZone(r.Created)
case "created_unix":
r.Created = time.Unix(r.CreatedUnix, 0).Local()
}
}
@@ -61,6 +67,8 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
return fmt.Errorf("GetBranchCommit: %v", err)
}
// Trim '--' prefix to prevent command line argument vulnerability
rel.TagName = strings.TrimPrefix(rel.TagName, "--")
if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil {
return err
}
@@ -125,7 +133,7 @@ func GetReleaseByID(id int64) (*Release, error) {
// GetReleasesByRepoID returns a list of releases of repository.
func GetReleasesByRepoID(repoID int64) (rels []*Release, err error) {
err = x.Desc("created").Find(&rels, Release{RepoID: repoID})
err = x.Desc("created_unix").Find(&rels, Release{RepoID: repoID})
return rels, err
}

View File

@@ -129,8 +129,7 @@ func NewRepoContext() {
log.Fatal(4, "Fail to execute 'git config --global core.quotepath false': %s", stderr)
}
// Clean up temporary data.
os.RemoveAll(filepath.Join(setting.AppDataPath, "tmp"))
RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp"))
}
// Repository represents a git repository.
@@ -171,6 +170,7 @@ type Repository struct {
EnableIssues bool `xorm:"NOT NULL DEFAULT true"`
EnableExternalTracker bool
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalMetas map[string]string `xorm:"-"`
EnablePulls bool `xorm:"NOT NULL DEFAULT true"`
@@ -178,8 +178,19 @@ type Repository struct {
ForkID int64
BaseRepo *Repository `xorm:"-"`
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
}
func (repo *Repository) BeforeInsert() {
repo.CreatedUnix = time.Now().UTC().Unix()
repo.UpdatedUnix = repo.CreatedUnix
}
func (repo *Repository) BeforeUpdate() {
repo.UpdatedUnix = time.Now().UTC().Unix()
}
func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
@@ -195,8 +206,14 @@ func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
case "num_closed_milestones":
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
case "updated":
repo.Updated = regulateTimeZone(repo.Updated)
case "external_tracker_style":
if len(repo.ExternalTrackerStyle) == 0 {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
}
case "created_unix":
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
case "updated_unix":
repo.Updated = time.Unix(repo.UpdatedUnix, 0)
}
}
@@ -242,6 +259,13 @@ func (repo *Repository) ComposeMetas() map[string]string {
"user": repo.MustOwner().Name,
"repo": repo.Name,
}
switch repo.ExternalTrackerStyle {
case markdown.ISSUE_NAME_STYLE_ALPHANUMERIC:
repo.ExternalMetas["style"] = markdown.ISSUE_NAME_STYLE_ALPHANUMERIC
default:
repo.ExternalMetas["style"] = markdown.ISSUE_NAME_STYLE_NUMERIC
}
}
return repo.ExternalMetas
}
@@ -322,11 +346,11 @@ func (repo *Repository) GitConfigPath() string {
return filepath.Join(repo.RepoPath(), "config")
}
func (repo *Repository) RepoLink() string {
func (repo *Repository) Link() string {
return setting.AppSubUrl + "/" + repo.MustOwner().Name + "/" + repo.Name
}
func (repo *Repository) RepoRelLink() string {
func (repo *Repository) RelLink() string {
return "/" + repo.MustOwner().Name + "/" + repo.Name
}
@@ -334,7 +358,7 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID)
}
func (repo *Repository) FullRepoLink() string {
func (repo *Repository) FullLink() string {
return setting.AppUrl + repo.MustOwner().Name + "/" + repo.Name
}
@@ -435,7 +459,7 @@ func (repo *Repository) ComposePayload() *api.PayloadRepo {
return &api.PayloadRepo{
ID: repo.ID,
Name: repo.Name,
URL: repo.FullRepoLink(),
URL: repo.FullLink(),
SSHURL: cl.SSH,
CloneURL: cl.HTTPS,
Description: repo.Description,
@@ -494,7 +518,7 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
}
var (
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
reservedPatterns = []string{"*.git", "*.keys", "*.wiki"}
)
@@ -523,16 +547,29 @@ func IsUsableName(name string) error {
// Mirror represents a mirror information of repository.
type Mirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
Interval int // Hour.
Updated time.Time `xorm:"UPDATED"`
NextUpdate time.Time
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
Interval int // Hour.
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64
NextUpdate time.Time `xorm:"-"`
NextUpdateUnix int64
address string `xorm:"-"`
}
func (m *Mirror) BeforeInsert() {
m.NextUpdateUnix = m.NextUpdate.UTC().Unix()
}
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().UTC().Unix()
m.NextUpdateUnix = m.NextUpdate.UTC().Unix()
}
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -541,6 +578,10 @@ func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
if err != nil {
log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err)
}
case "updated_unix":
m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
case "next_updated_unix":
m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
}
}
@@ -616,7 +657,7 @@ func GetMirror(repoId int64) (*Mirror, error) {
}
func updateMirror(e Engine, m *Mirror) error {
_, err := e.Id(m.ID).Update(m)
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
@@ -706,9 +747,10 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
if opts.IsMirror {
if _, err = x.InsertOne(&Mirror{
RepoID: repo.ID,
Interval: 24,
NextUpdate: time.Now().Add(24 * time.Hour),
RepoID: repo.ID,
Interval: 24,
EnablePrune: true,
NextUpdate: time.Now().Add(24 * time.Hour),
}); err != nil {
return repo, fmt.Errorf("InsertOne: %v", err)
}
@@ -1020,11 +1062,16 @@ func CountPublicRepositories() int64 {
return countRepositories(false)
}
func Repositories(page, pageSize int) (_ []*Repository, err error) {
repos := make([]*Repository, 0, pageSize)
return repos, x.Limit(pageSize, (page-1)*pageSize).Asc("id").Find(&repos)
}
// RepositoriesWithUsers returns number of repos in given page.
func RepositoriesWithUsers(page, pageSize int) (_ []*Repository, err error) {
repos := make([]*Repository, 0, pageSize)
if err = x.Limit(pageSize, (page-1)*pageSize).Asc("id").Find(&repos); err != nil {
return nil, err
repos, err := Repositories(page, pageSize)
if err != nil {
return nil, fmt.Errorf("Repositories: %v", err)
}
for i := range repos {
@@ -1364,20 +1411,8 @@ func DeleteRepository(uid, repoID int64) error {
}
if repo.NumForks > 0 {
if repo.IsPrivate {
forkRepos, err := GetRepositoriesByForkID(repo.ID)
if err != nil {
return fmt.Errorf("getRepositoriesByForkID: %v", err)
}
for i := range forkRepos {
if err = DeleteRepository(forkRepos[i].OwnerID, forkRepos[i].ID); err != nil {
log.Error(4, "DeleteRepository [%d]: %v", forkRepos[i].ID, err)
}
}
} else {
if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
}
if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
}
}
@@ -1435,7 +1470,8 @@ func GetRepositoryByID(id int64) (*Repository, error) {
// GetRepositories returns a list of repositories of given user.
func GetRepositories(uid int64, private bool) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
sess := x.Desc("updated")
sess := x.Desc("updated_unix")
if !private {
sess.Where("is_private=?", false)
}
@@ -1444,9 +1480,9 @@ func GetRepositories(uid int64, private bool) ([]*Repository, error) {
}
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated.
func GetRecentUpdatedRepositories(page int) (repos []*Repository, err error) {
return repos, x.Limit(setting.ExplorePagingNum, (page-1)*setting.ExplorePagingNum).
Where("is_private=?", false).Limit(setting.ExplorePagingNum).Desc("updated").Find(&repos)
func GetRecentUpdatedRepositories(page, pageSize int) (repos []*Repository, err error) {
return repos, x.Limit(pageSize, (page-1)*pageSize).
Where("is_private=?", false).Limit(pageSize).Desc("updated_unix").Find(&repos)
}
func getRepositoryCount(e Engine, u *User) (int64, error) {
@@ -1458,32 +1494,49 @@ func GetRepositoryCount(u *User) (int64, error) {
return getRepositoryCount(x, u)
}
type SearchOption struct {
Keyword string
Uid int64
Limit int
Private bool
type SearchRepoOptions struct {
Keyword string
OwnerID int64
OrderBy string
Private bool // Include private repositories in results
Page int
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
}
// SearchRepositoryByName returns given number of repositories whose name contains keyword.
func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) {
if len(opt.Keyword) == 0 {
return repos, nil
// SearchRepositoryByName takes keyword and part of repository name to search,
// it returns results in given range and number of total results.
func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int64, _ error) {
if len(opts.Keyword) == 0 {
return repos, 0, nil
}
opt.Keyword = strings.ToLower(opt.Keyword)
opts.Keyword = strings.ToLower(opts.Keyword)
repos = make([]*Repository, 0, opt.Limit)
// Append conditions.
sess := x.Limit(opt.Limit)
if opt.Uid > 0 {
sess.Where("owner_id=?", opt.Uid)
if opts.Page <= 0 {
opts.Page = 1
}
if !opt.Private {
repos = make([]*Repository, 0, opts.PageSize)
// Append conditions
sess := x.Where("LOWER(lower_name) LIKE ?", "%"+opts.Keyword+"%")
if opts.OwnerID > 0 {
sess.And("owner_id = ?", opts.OwnerID)
}
if !opts.Private {
sess.And("is_private=?", false)
}
sess.And("lower_name like ?", "%"+opt.Keyword+"%").Find(&repos)
return repos, err
var countSess xorm.Session
countSess = *sess
count, err := countSess.Count(new(Repository))
if err != nil {
return nil, 0, fmt.Errorf("Count: %v", err)
}
if len(opts.OrderBy) > 0 {
sess.OrderBy(opts.OrderBy)
}
return repos, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&repos)
}
// DeleteRepositoryArchives deletes all repositories' archives.
@@ -1629,10 +1682,16 @@ func MirrorUpdate() {
}
repoPath := m.Repo.RepoPath()
gitArgs := []string{"remote", "update"}
if m.EnablePrune {
gitArgs = append(gitArgs, "--prune")
}
if _, stderr, err := process.ExecDir(
time.Duration(setting.Git.Timeout.Mirror)*time.Second,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update", "--prune"); err != nil {
"git", gitArgs...); err != nil {
desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
@@ -1764,9 +1823,26 @@ func CheckRepoStats() {
repoStatsCheck(checkers[i])
}
// FIXME: use checker when v0.9, stop supporting old fork repo format.
// ***** START: Repository.NumClosedIssues *****
desc := "repository count 'num_closed_issues'"
results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false)
if err != nil {
log.Error(4, "Select %s: %v", desc, err)
} else {
for _, result := range results {
id := com.StrTo(result["id"]).MustInt64()
log.Trace("Updating %s: %d", desc, id)
_, err = x.Exec("UPDATE `repository` SET num_closed_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, false, id)
if err != nil {
log.Error(4, "Update %s[%d]: %v", desc, id, err)
}
}
}
// ***** END: Repository.NumClosedIssues *****
// FIXME: use checker when stop supporting old fork repo format.
// ***** START: Repository.NumForks *****
results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
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 {
log.Error(4, "Select repository count 'num_forks': %v", err)
} else {

View File

@@ -6,28 +6,27 @@ package models
import (
"fmt"
"time"
)
// Collaboration represent the relation between an individual and a repository.
type Collaboration struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
Mode AccessMode `xorm:"DEFAULT 2 NOT NULL"`
Created time.Time `xorm:"CREATED"`
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
Mode AccessMode `xorm:"DEFAULT 2 NOT NULL"`
}
func (c *Collaboration) ModeName() string {
func (c *Collaboration) ModeI18nKey() string {
switch c.Mode {
case ACCESS_MODE_READ:
return "Read"
return "repo.settings.collaboration.read"
case ACCESS_MODE_WRITE:
return "Write"
return "repo.settings.collaboration.write"
case ACCESS_MODE_ADMIN:
return "Admin"
return "repo.settings.collaboration.admin"
default:
return "repo.settings.collaboration.undefined"
}
return "Undefined"
}
// AddCollaborator adds new collaboration relation between an individual and a repository.

62
models/repo_test.go Normal file
View File

@@ -0,0 +1,62 @@
package models_test
import (
. "github.com/gogits/gogs/models"
. "github.com/smartystreets/goconvey/convey"
"testing"
"github.com/gogits/gogs/modules/markdown"
)
func TestRepo(t *testing.T) {
Convey("The metas map", t, func() {
var repo = new(Repository)
repo.Name = "testrepo"
repo.Owner = new(User)
repo.Owner.Name = "testuser"
repo.ExternalTrackerFormat = "https://someurl.com/{user}/{repo}/{issue}"
Convey("When no external tracker is configured", func() {
Convey("It should be nil", func() {
repo.EnableExternalTracker = false
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
})
Convey("It should be nil even if other settings are present", func() {
repo.EnableExternalTracker = false
repo.ExternalTrackerFormat = "http://someurl.com/{user}/{repo}/{issue}"
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
})
})
Convey("When an external issue tracker is configured", func() {
repo.EnableExternalTracker = true
Convey("It should default to numeric issue style", func() {
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_NUMERIC)
})
Convey("It should pass through numeric issue style setting", func() {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_NUMERIC)
})
Convey("It should pass through alphanumeric issue style setting", func() {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_ALPHANUMERIC
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_ALPHANUMERIC)
})
Convey("It should contain the user name", func() {
metas := repo.ComposeMetas()
So(metas["user"], ShouldEqual, "testuser")
})
Convey("It should contain the repo name", func() {
metas := repo.ComposeMetas()
So(metas["repo"], ShouldEqual, "testrepo")
})
Convey("It should contain the URL format", func() {
metas := repo.ComposeMetas()
So(metas["format"], ShouldEqual, "https://someurl.com/{user}/{repo}/{issue}")
})
})
})
}

View File

@@ -45,22 +45,36 @@ const (
// PublicKey represents a SSH or deploy key.
type PublicKey struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"INDEX NOT NULL"`
Name string `xorm:"NOT NULL"`
Fingerprint string `xorm:"NOT NULL"`
Content string `xorm:"TEXT NOT NULL"`
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
Created time.Time `xorm:"CREATED"`
Updated time.Time // Note: Updated must below Created for AfterSet.
HasRecentActivity bool `xorm:"-"`
HasUsed bool `xorm:"-"`
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"INDEX NOT NULL"`
Name string `xorm:"NOT NULL"`
Fingerprint string `xorm:"NOT NULL"`
Content string `xorm:"TEXT NOT NULL"`
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
UpdatedUnix int64
HasRecentActivity bool `xorm:"-"`
HasUsed bool `xorm:"-"`
}
func (k *PublicKey) BeforeInsert() {
k.CreatedUnix = time.Now().UTC().Unix()
}
func (k *PublicKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().UTC().Unix()
}
func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created":
case "created_unix":
k.Created = time.Unix(k.CreatedUnix, 0).Local()
case "updated_unix":
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
k.HasUsed = k.Updated.After(k.Created)
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}
@@ -608,21 +622,35 @@ func RewriteAllPublicKeys() error {
// DeployKey represents deploy key information and its relation with repository.
type DeployKey struct {
ID int64 `xorm:"pk autoincr"`
KeyID int64 `xorm:"UNIQUE(s) INDEX"`
RepoID int64 `xorm:"UNIQUE(s) INDEX"`
Name string
Fingerprint string
Content string `xorm:"-"`
Created time.Time `xorm:"CREATED"`
Updated time.Time // Note: Updated must below Created for AfterSet.
HasRecentActivity bool `xorm:"-"`
HasUsed bool `xorm:"-"`
ID int64 `xorm:"pk autoincr"`
KeyID int64 `xorm:"UNIQUE(s) INDEX"`
RepoID int64 `xorm:"UNIQUE(s) INDEX"`
Name string
Fingerprint string
Content string `xorm:"-"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
UpdatedUnix int64
HasRecentActivity bool `xorm:"-"`
HasUsed bool `xorm:"-"`
}
func (k *DeployKey) BeforeInsert() {
k.CreatedUnix = time.Now().UTC().Unix()
}
func (k *DeployKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().UTC().Unix()
}
func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created":
case "created_unix":
k.Created = time.Unix(k.CreatedUnix, 0).Local()
case "updated_unix":
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
k.HasUsed = k.Updated.After(k.Created)
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}

View File

@@ -7,6 +7,7 @@ package models
import (
"time"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
"github.com/gogits/gogs/modules/base"
@@ -14,16 +15,38 @@ import (
// AccessToken represents a personal access token.
type AccessToken struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX"`
Name string
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX"`
Name string
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
UpdatedUnix int64
HasRecentActivity bool `xorm:"-"`
HasUsed bool `xorm:"-"`
}
func (t *AccessToken) BeforeInsert() {
t.CreatedUnix = time.Now().UTC().Unix()
}
func (t *AccessToken) BeforeUpdate() {
t.UpdatedUnix = time.Now().UTC().Unix()
}
func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
t.Created = time.Unix(t.CreatedUnix, 0).Local()
case "updated_unix":
t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
t.HasUsed = t.Updated.After(t.Created)
t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}
}
// NewAccessToken creates new access token.
func NewAccessToken(t *AccessToken) error {
t.Sha1 = base.EncodeSha1(gouuid.NewV4().String())
@@ -33,6 +56,9 @@ func NewAccessToken(t *AccessToken) error {
// GetAccessTokenBySHA returns access token by given sha1.
func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
if sha == "" {
return nil, ErrAccessTokenEmpty{}
}
t := &AccessToken{Sha1: sha}
has, err := x.Get(t)
if err != nil {
@@ -46,16 +72,7 @@ func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
// ListAccessTokens returns a list of access tokens belongs to given user.
func ListAccessTokens(uid int64) ([]*AccessToken, error) {
tokens := make([]*AccessToken, 0, 5)
err := x.Where("uid=?", uid).Desc("id").Find(&tokens)
if err != nil {
return nil, err
}
for _, t := range tokens {
t.HasUsed = t.Updated.After(t.Created)
t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}
return tokens, nil
return tokens, x.Where("uid=?", uid).Desc("id").Find(&tokens)
}
// UpdateAccessToken updates information of access token.

View File

@@ -36,8 +36,8 @@ import (
type UserType int
const (
INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
ORGANIZATION
USER_TYPE_INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
USER_TYPE_ORGANIZATION
)
var (
@@ -68,10 +68,13 @@ type User struct {
Repos []*Repository `xorm:"-"`
Location string
Website string
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
// Remember visibility choice for convenience, true for private
LastRepoVisibility bool
@@ -79,10 +82,11 @@ type User struct {
MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
// Permissions
IsActive bool
IsActive bool // Activate primary email
IsAdmin bool
AllowGitHook bool
AllowImportLocal bool // Allow migrate repository by local path
ProhibitLogin bool
// Avatar
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
@@ -103,18 +107,26 @@ type User struct {
Members []*User `xorm:"-"`
}
func (u *User) BeforeInsert() {
u.CreatedUnix = time.Now().UTC().Unix()
u.UpdatedUnix = u.CreatedUnix
}
func (u *User) BeforeUpdate() {
if u.MaxRepoCreation < -1 {
u.MaxRepoCreation = -1
}
u.UpdatedUnix = time.Now().UTC().Unix()
}
func (u *User) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "full_name":
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
case "created":
u.Created = regulateTimeZone(u.Created)
case "created_unix":
u.Created = time.Unix(u.CreatedUnix, 0).Local()
case "updated_unix":
u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
}
}
@@ -156,16 +168,6 @@ func (u *User) CanImportLocal() bool {
return u.IsAdmin || u.AllowImportLocal
}
// EmailAdresses is the list of all email addresses of a user. Can contain the
// primary email address, but is not obligatory
type EmailAddress struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX NOT NULL"`
Email string `xorm:"UNIQUE NOT NULL"`
IsActivated bool
IsPrimary bool `xorm:"-"`
}
// DashboardLink returns the user dashboard page link.
func (u *User) DashboardLink() string {
if u.IsOrganization() {
@@ -229,7 +231,7 @@ func (u *User) GenerateRandomAvatar() error {
}
func (u *User) RelAvatarLink() string {
defaultImgUrl := "/img/avatar_default.jpg"
defaultImgUrl := "/img/avatar_default.png"
if u.Id == -1 {
return defaultImgUrl
}
@@ -252,11 +254,11 @@ func (u *User) RelAvatarLink() string {
return setting.GravatarSource + u.Avatar
}
// AvatarLink returns user gravatar link.
// AvatarLink returns user avatar link.
func (u *User) AvatarLink() string {
link := u.RelAvatarLink()
if link[0] == '/' && link[1] != '/' {
return setting.AppSubUrl + link
return strings.TrimSuffix(setting.AppUrl, "/") + link
}
return link
}
@@ -378,7 +380,7 @@ func (u *User) IsWriterOfRepo(repo *Repository) bool {
// IsOrganization returns true if user is actually a organization.
func (u *User) IsOrganization() bool {
return u.Type == ORGANIZATION
return u.Type == USER_TYPE_ORGANIZATION
}
// IsUserOrgOwner returns true if user is in the owner team of given organization.
@@ -453,19 +455,6 @@ func IsUserExist(uid int64, name string) (bool, error) {
return x.Where("id!=?", uid).Get(&User{LowerName: strings.ToLower(name)})
}
// IsEmailUsed returns true if the e-mail has been used.
func IsEmailUsed(email string) (bool, error) {
if len(email) == 0 {
return false, nil
}
email = strings.ToLower(email)
if has, err := x.Get(&EmailAddress{Email: email}); has || err != nil {
return has, err
}
return x.Get(&User{Email: email})
}
// GetUserSalt returns a ramdom user salt token.
func GetUserSalt() string {
return base.GetRandomString(10)
@@ -510,16 +499,14 @@ func CreateUser(u *User) (err error) {
u.MaxRepoCreation = -1
sess := x.NewSession()
defer sess.Close()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(u); err != nil {
sess.Rollback()
return err
} else if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil {
sess.Rollback()
return err
}
@@ -877,8 +864,8 @@ func GetUserEmailsByNames(names []string) []string {
return mails
}
// GetUserIdsByNames returns a slice of ids corresponds to names.
func GetUserIdsByNames(names []string) []int64 {
// GetUserIDsByNames returns a slice of ids corresponds to names.
func GetUserIDsByNames(names []string) []int64 {
ids := make([]int64, 0, len(names))
for _, name := range names {
u, err := GetUserByName(name)
@@ -890,147 +877,6 @@ func GetUserIdsByNames(names []string) []int64 {
return ids
}
// GetEmailAddresses returns all e-mail addresses belongs to given user.
func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
emails := make([]*EmailAddress, 0, 5)
err := x.Where("uid=?", uid).Find(&emails)
if err != nil {
return nil, err
}
u, err := GetUserByID(uid)
if err != nil {
return nil, err
}
isPrimaryFound := false
for _, email := range emails {
if email.Email == u.Email {
isPrimaryFound = true
email.IsPrimary = true
} else {
email.IsPrimary = false
}
}
// We alway want the primary email address displayed, even if it's not in
// the emailaddress table (yet)
if !isPrimaryFound {
emails = append(emails, &EmailAddress{
Email: u.Email,
IsActivated: true,
IsPrimary: true,
})
}
return emails, nil
}
func AddEmailAddress(email *EmailAddress) error {
email.Email = strings.ToLower(strings.TrimSpace(email.Email))
used, err := IsEmailUsed(email.Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{email.Email}
}
_, err = x.Insert(email)
return err
}
func AddEmailAddresses(emails []*EmailAddress) error {
if len(emails) == 0 {
return nil
}
// Check if any of them has been used
for i := range emails {
emails[i].Email = strings.ToLower(strings.TrimSpace(emails[i].Email))
used, err := IsEmailUsed(emails[i].Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{emails[i].Email}
}
}
if _, err := x.Insert(emails); err != nil {
return fmt.Errorf("Insert: %v", err)
}
return nil
}
func (email *EmailAddress) Activate() error {
email.IsActivated = true
if _, err := x.Id(email.ID).AllCols().Update(email); err != nil {
return err
}
if user, err := GetUserByID(email.UID); err != nil {
return err
} else {
user.Rands = GetUserSalt()
return UpdateUser(user)
}
}
func DeleteEmailAddress(email *EmailAddress) (err error) {
if email.ID > 0 {
_, err = x.Id(email.ID).Delete(new(EmailAddress))
} else {
_, err = x.Where("email=?", email.Email).Delete(new(EmailAddress))
}
return err
}
func DeleteEmailAddresses(emails []*EmailAddress) (err error) {
for i := range emails {
if err = DeleteEmailAddress(emails[i]); err != nil {
return err
}
}
return nil
}
func MakeEmailPrimary(email *EmailAddress) error {
has, err := x.Get(email)
if err != nil {
return err
} else if !has {
return ErrEmailNotExist
}
if !email.IsActivated {
return ErrEmailNotActivated
}
user := &User{Id: email.UID}
has, err = x.Get(user)
if err != nil {
return err
} else if !has {
return ErrUserNotExist{email.UID, ""}
}
// Make sure the former primary email doesn't disappear
former_primary_email := &EmailAddress{Email: user.Email}
has, err = x.Get(former_primary_email)
if err != nil {
return err
} else if !has {
former_primary_email.UID = user.Id
former_primary_email.IsActivated = user.IsActive
x.Insert(former_primary_email)
}
user.Email = email.Email
_, err = x.Id(user.Id).AllCols().Update(user)
return err
}
// UserCommit represents a commit with validation of user.
type UserCommit struct {
User *User
@@ -1103,16 +949,47 @@ func GetUserByEmail(email string) (*User, error) {
return nil, ErrUserNotExist{0, email}
}
// SearchUserByName returns given number of users whose name contains keyword.
func SearchUserByName(opt SearchOption) (us []*User, err error) {
if len(opt.Keyword) == 0 {
return us, nil
}
opt.Keyword = strings.ToLower(opt.Keyword)
type SearchUserOptions struct {
Keyword string
Type UserType
OrderBy string
Page int
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
}
us = make([]*User, 0, opt.Limit)
err = x.Limit(opt.Limit).Where("type=0").And("lower_name like ?", "%"+opt.Keyword+"%").Find(&us)
return us, err
// SearchUserByName takes keyword and part of user name to search,
// it returns results in given range and number of total results.
func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
if len(opts.Keyword) == 0 {
return users, 0, nil
}
opts.Keyword = strings.ToLower(opts.Keyword)
if opts.PageSize <= 0 || opts.PageSize > setting.ExplorePagingNum {
opts.PageSize = setting.ExplorePagingNum
}
if opts.Page <= 0 {
opts.Page = 1
}
searchQuery := "%" + opts.Keyword + "%"
users = make([]*User, 0, opts.PageSize)
// Append conditions
sess := x.Where("LOWER(lower_name) LIKE ?", searchQuery).
Or("LOWER(full_name) LIKE ?", searchQuery).
And("type = ?", opts.Type)
var countSess xorm.Session
countSess = *sess
count, err := countSess.Count(new(User))
if err != nil {
return nil, 0, fmt.Errorf("Count: %v", err)
}
if len(opts.OrderBy) > 0 {
sess.OrderBy(opts.OrderBy)
}
return users, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&users)
}
// ___________ .__ .__

198
models/user_mail.go Normal file
View File

@@ -0,0 +1,198 @@
// Copyright 2016 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"
"strings"
)
// EmailAdresses is the list of all email addresses of a user. Can contain the
// primary email address, but is not obligatory.
type EmailAddress struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX NOT NULL"`
Email string `xorm:"UNIQUE NOT NULL"`
IsActivated bool
IsPrimary bool `xorm:"-"`
}
// GetEmailAddresses returns all email addresses belongs to given user.
func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
emails := make([]*EmailAddress, 0, 5)
if err := x.Where("uid=?", uid).Find(&emails); err != nil {
return nil, err
}
u, err := GetUserByID(uid)
if err != nil {
return nil, err
}
isPrimaryFound := false
for _, email := range emails {
if email.Email == u.Email {
isPrimaryFound = true
email.IsPrimary = true
} else {
email.IsPrimary = false
}
}
// We alway want the primary email address displayed, even if it's not in
// the emailaddress table (yet).
if !isPrimaryFound {
emails = append(emails, &EmailAddress{
Email: u.Email,
IsActivated: true,
IsPrimary: true,
})
}
return emails, nil
}
func isEmailUsed(e Engine, email string) (bool, error) {
if len(email) == 0 {
return true, nil
}
return e.Get(&EmailAddress{Email: email})
}
// IsEmailUsed returns true if the email has been used.
func IsEmailUsed(email string) (bool, error) {
return isEmailUsed(x, email)
}
func addEmailAddress(e Engine, email *EmailAddress) error {
email.Email = strings.ToLower(strings.TrimSpace(email.Email))
used, err := isEmailUsed(e, email.Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{email.Email}
}
_, err = e.Insert(email)
return err
}
func AddEmailAddress(email *EmailAddress) error {
return addEmailAddress(x, email)
}
func AddEmailAddresses(emails []*EmailAddress) error {
if len(emails) == 0 {
return nil
}
// Check if any of them has been used
for i := range emails {
emails[i].Email = strings.ToLower(strings.TrimSpace(emails[i].Email))
used, err := IsEmailUsed(emails[i].Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{emails[i].Email}
}
}
if _, err := x.Insert(emails); err != nil {
return fmt.Errorf("Insert: %v", err)
}
return nil
}
func (email *EmailAddress) Activate() error {
user, err := GetUserByID(email.UID)
if err != nil {
return err
}
user.Rands = GetUserSalt()
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
email.IsActivated = true
if _, err := sess.Id(email.ID).AllCols().Update(email); err != nil {
return err
} else if err = updateUser(sess, user); err != nil {
return err
}
return sess.Commit()
}
func DeleteEmailAddress(email *EmailAddress) (err error) {
if email.ID > 0 {
_, err = x.Id(email.ID).Delete(new(EmailAddress))
} else {
_, err = x.Where("email=?", email.Email).Delete(new(EmailAddress))
}
return err
}
func DeleteEmailAddresses(emails []*EmailAddress) (err error) {
for i := range emails {
if err = DeleteEmailAddress(emails[i]); err != nil {
return err
}
}
return nil
}
func MakeEmailPrimary(email *EmailAddress) error {
has, err := x.Get(email)
if err != nil {
return err
} else if !has {
return ErrEmailNotExist
}
if !email.IsActivated {
return ErrEmailNotActivated
}
user := &User{Id: email.UID}
has, err = x.Get(user)
if err != nil {
return err
} else if !has {
return ErrUserNotExist{email.UID, ""}
}
// Make sure the former primary email doesn't disappear.
formerPrimaryEmail := &EmailAddress{Email: user.Email}
has, err = x.Get(formerPrimaryEmail)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if !has {
formerPrimaryEmail.UID = user.Id
formerPrimaryEmail.IsActivated = user.IsActive
if _, err = sess.Insert(formerPrimaryEmail); err != nil {
return err
}
}
user.Email = email.Email
if _, err = sess.Id(user.Id).AllCols().Update(user); err != nil {
return err
}
return sess.Commit()
}

View File

@@ -94,8 +94,20 @@ type Webhook struct {
HookTaskType HookTaskType
Meta string `xorm:"TEXT"` // store hook-specific attributes
LastStatus HookStatus // Last delivery status
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
}
func (w *Webhook) BeforeInsert() {
w.CreatedUnix = time.Now().UTC().Unix()
w.UpdatedUnix = w.CreatedUnix
}
func (w *Webhook) BeforeUpdate() {
w.UpdatedUnix = time.Now().UTC().Unix()
}
func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
@@ -106,8 +118,10 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
if err = json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
}
case "created":
w.Created = regulateTimeZone(w.Created)
case "created_unix":
w.Created = time.Unix(w.CreatedUnix, 0).Local()
case "updated_unix":
w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
}
}
@@ -160,16 +174,32 @@ func CreateWebhook(w *Webhook) error {
return err
}
// GetWebhookByID returns webhook by given ID.
func GetWebhookByID(id int64) (*Webhook, error) {
w := new(Webhook)
has, err := x.Id(id).Get(w)
// getWebhook uses argument bean as query condition,
// ID must be specified and do not assign unnecessary fields.
func getWebhook(bean *Webhook) (*Webhook, error) {
has, err := x.Get(bean)
if err != nil {
return nil, err
} else if !has {
return nil, ErrWebhookNotExist{id}
return nil, ErrWebhookNotExist{bean.ID}
}
return w, nil
return bean, nil
}
// GetWebhookByRepoID returns webhook of repository by given ID.
func GetWebhookByRepoID(repoID, id int64) (*Webhook, error) {
return getWebhook(&Webhook{
ID: id,
RepoID: repoID,
})
}
// GetWebhookByOrgID returns webhook of organization by given ID.
func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
return getWebhook(&Webhook{
ID: id,
OrgID: orgID,
})
}
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
@@ -190,25 +220,42 @@ func UpdateWebhook(w *Webhook) error {
return err
}
// DeleteWebhook deletes webhook of repository.
func DeleteWebhook(id int64) (err error) {
// deleteWebhook uses argument bean as query condition,
// ID must be specified and do not assign unnecessary fields.
func deleteWebhook(bean *Webhook) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Delete(&Webhook{ID: id}); err != nil {
if _, err = sess.Delete(bean); err != nil {
return err
} else if _, err = sess.Delete(&HookTask{HookID: id}); err != nil {
} else if _, err = sess.Delete(&HookTask{HookID: bean.ID}); err != nil {
return err
}
return sess.Commit()
}
// GetWebhooksByOrgId returns all webhooks for an organization.
func GetWebhooksByOrgId(orgID int64) (ws []*Webhook, err error) {
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
func DeleteWebhookByRepoID(repoID, id int64) (error) {
return deleteWebhook(&Webhook{
ID: id,
RepoID: repoID,
})
}
// DeleteWebhookByOrgID deletes webhook of organization by given ID.
func DeleteWebhookByOrgID(orgID, id int64) (error) {
return deleteWebhook(&Webhook{
ID: id,
OrgID: orgID,
})
}
// GetWebhooksByOrgID returns all webhooks for an organization.
func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
err = x.Find(&ws, &Webhook{OrgID: orgID})
return ws, err
}
@@ -534,7 +581,7 @@ func (t *HookTask) deliver() {
}
// Update webhook last delivery status.
w, err := GetWebhookByID(t.HookID)
w, err := GetWebhookByRepoID(t.RepoID, t.HookID)
if err != nil {
log.Error(5, "GetWebhookByID: %v", err)
return
@@ -570,14 +617,6 @@ func (t *HookTask) deliver() {
return
}
t.ResponseInfo.Body = string(p)
switch t.Type {
case SLACK:
if t.ResponseInfo.Body != "ok" {
log.Error(5, "slack failed with: %s", t.ResponseInfo.Body)
t.IsSucceed = false
}
}
}
// DeliverHooks checks and delivers undelivered hooks.

View File

@@ -69,10 +69,12 @@ func ToWikiPageURL(name string) string {
return url.QueryEscape(strings.Replace(name, " ", "-", -1))
}
// ToWikiPageName formats a URL back to corresponding wiki page name.
// ToWikiPageName formats a URL back to corresponding wiki page name,
// and removes leading characters './' to prevent changing files
// that are not belong to wiki repository.
func ToWikiPageName(urlString string) string {
name, _ := url.QueryUnescape(strings.Replace(urlString, "-", " ", -1))
return name
return strings.Replace(strings.TrimLeft(name, "./"), "/", " ", -1)
}
// WikiCloneLink returns clone URLs of repository wiki.
@@ -149,7 +151,7 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = ToWikiPageName(strings.Replace(title, "/", " ", -1))
title = ToWikiPageName(title)
filename := path.Join(localPath, title+".md")
// If not a new file, show perform update not create.
@@ -161,6 +163,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
os.Remove(path.Join(localPath, oldTitle+".md"))
}
// SECURITY: if new file is a symlink to non-exist critical file,
// attack content can be written to the target file (e.g. authorized_keys2)
// as a new page operation.
// So we want to make sure the symlink is removed before write anything.
// The new file we created will be in normal text format.
os.Remove(filename)
if err = ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
@@ -198,7 +207,7 @@ func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = ToWikiPageName(strings.Replace(title, "/", " ", -1))
title = ToWikiPageName(title)
filename := path.Join(localPath, title+".md")
os.Remove(filename)

View File

@@ -36,6 +36,7 @@ type AdminEditUserForm struct {
Admin bool
AllowGitHook bool
AllowImportLocal bool
ProhibitLogin bool
}
func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View File

@@ -49,7 +49,7 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
if len(tokenSHA) > 0 {
t, err := models.GetAccessTokenBySHA(tokenSHA)
if err != nil {
if models.IsErrAccessTokenNotExist(err) {
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
log.Error(4, "GetAccessTokenBySHA: %v", err)
}
return 0

View File

@@ -31,6 +31,7 @@ type AuthenticationForm struct {
SMTPHost string
SMTPPort int
AllowedDomains string
SecurityProtocol int `binding:"Range(0,2)"`
TLS bool
SkipVerify bool
PAMServiceName string

View File

@@ -16,12 +16,21 @@ import (
"github.com/gogits/gogs/modules/log"
)
type SecurityProtocol int
// Note: new type must be added at the end of list to maintain compatibility.
const (
SECURITY_PROTOCOL_UNENCRYPTED SecurityProtocol = iota
SECURITY_PROTOCOL_LDAPS
SECURITY_PROTOCOL_START_TLS
)
// 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
SecurityProtocol SecurityProtocol
SkipVerify bool
BindDN string // DN to bind with
BindPassword string // Bind DN password
@@ -102,9 +111,46 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
return userDN, true
}
func dial(ls *Source) (*ldap.Conn, error) {
log.Trace("Dialing LDAP with security protocol (%v) without verifying: %v", ls.SecurityProtocol, ls.SkipVerify)
tlsCfg := &tls.Config{
ServerName: ls.Host,
InsecureSkipVerify: ls.SkipVerify,
}
if ls.SecurityProtocol == SECURITY_PROTOCOL_LDAPS {
return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), tlsCfg)
}
conn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
if err != nil {
return nil, fmt.Errorf("Dial: %v", err)
}
if ls.SecurityProtocol == SECURITY_PROTOCOL_START_TLS {
if err = conn.StartTLS(tlsCfg); err != nil {
conn.Close()
return nil, fmt.Errorf("StartTLS: %v", err)
}
}
return conn, nil
}
func bindUser(l *ldap.Conn, userDN, passwd string) error {
log.Trace("Binding with userDN: %s", userDN)
err := l.Bind(userDN, passwd)
if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return err
}
log.Trace("Bound successfully with userDN: %s", userDN)
return err
}
// 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, string, bool, bool) {
l, err := ldapDial(ls)
l, err := dial(ls)
if err != nil {
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
ls.Enabled = false
@@ -164,12 +210,12 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
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)
username := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
admin_attr := false
isAdmin := false
if len(ls.AdminFilter) > 0 {
log.Trace("Checking admin with filter %s and base %s", ls.AdminFilter, userDN)
search = ldap.NewSearchRequest(
@@ -183,7 +229,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
} else if len(sr.Entries) < 1 {
log.Error(4, "LDAP Admin Search failed")
} else {
admin_attr = true
isAdmin = true
}
}
@@ -195,27 +241,5 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
}
}
return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true
}
func bindUser(l *ldap.Conn, userDN, passwd string) error {
log.Trace("Binding with userDN: %s", userDN)
err := l.Bind(userDN, passwd)
if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return err
}
log.Trace("Bound successfully with userDN: %s", userDN)
return err
}
func ldapDial(ls *Source) (*ldap.Conn, error) {
if ls.UseSSL {
log.Debug("Using TLS for LDAP without verifying: %v", ls.SkipVerify)
return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), &tls.Config{
InsecureSkipVerify: ls.SkipVerify,
})
} else {
return ldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
}
return username, firstname, surname, mail, isAdmin, true
}

View File

@@ -88,6 +88,7 @@ type RepoSettingForm struct {
Interval int
MirrorAddress string
Private bool
EnablePrune bool
// Advanced settings
EnableWiki bool
@@ -96,6 +97,7 @@ type RepoSettingForm struct {
EnableIssues bool
EnableExternalTracker bool
TrackerURLFormat string
TrackerIssueStyle string
EnablePulls bool
}
@@ -141,7 +143,7 @@ func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
}
type NewSlackHookForm struct {
PayloadURL string `binding:"Required;Url`
PayloadURL string `binding:"Required;Url"`
Channel string `binding:"Required"`
Username string
IconURL string

View File

@@ -97,6 +97,7 @@ func GetRandomString(n int, alphabets ...byte) string {
}
// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
// FIXME: use https://godoc.org/golang.org/x/crypto/pbkdf2?
func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
prf := hmac.New(h, password)
hashLen := prf.Size()
@@ -206,7 +207,7 @@ func HashEmail(email string) string {
// AvatarLink returns avatar link by given email.
func AvatarLink(email string) string {
if setting.DisableGravatar || setting.OfflineMode {
return setting.AppSubUrl + "/img/avatar_default.jpg"
return setting.AppSubUrl + "/img/avatar_default.png"
}
return setting.GravatarSource + HashEmail(email)
@@ -521,3 +522,11 @@ func IsImageFile(data []byte) (string, bool) {
}
return contentType, false
}
func IsPDFFile(data []byte) (string, bool) {
contentType := http.DetectContentType(data)
if strings.Index(contentType, "application/pdf") != -1 {
return contentType, true
}
return contentType, false
}

File diff suppressed because one or more lines are too long

73
modules/context/api.go Normal file
View File

@@ -0,0 +1,73 @@
// Copyright 2016 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 context
import (
"fmt"
"strings"
"github.com/Unknwon/paginater"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
type APIContext struct {
*Context
Org *APIOrganization
}
// Error responses error message to client with given message.
// If status is 500, also it prints error to log.
func (ctx *APIContext) Error(status int, title string, obj interface{}) {
var message string
if err, ok := obj.(error); ok {
message = err.Error()
} else {
message = obj.(string)
}
if status == 500 {
log.Error(4, "%s: %s", title, message)
}
ctx.JSON(status, map[string]string{
"message": message,
"url": base.DOC_URL,
})
}
// SetLinkHeader sets pagination link header by given totol number and page size.
func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
page := paginater.New(total, pageSize, ctx.QueryInt("page"), 0)
links := make([]string, 0, 4)
if page.HasNext() {
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"next\"", setting.AppUrl, ctx.Req.URL.Path[1:], page.Next()))
}
if !page.IsLast() {
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"last\"", setting.AppUrl, ctx.Req.URL.Path[1:], page.TotalPages()))
}
if !page.IsFirst() {
links = append(links, fmt.Sprintf("<%s%s?page=1>; rel=\"first\"", setting.AppUrl, ctx.Req.URL.Path[1:]))
}
if page.HasPrevious() {
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"prev\"", setting.AppUrl, ctx.Req.URL.Path[1:], page.Previous()))
}
if len(links) > 0 {
ctx.Header().Set("Link", strings.Join(links, ","))
}
}
func APIContexter() macaron.Handler {
return func(c *Context) {
ctx := &APIContext{
Context: c,
}
c.Map(ctx)
}
}

View File

@@ -0,0 +1,14 @@
// Copyright 2016 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 context
import (
"github.com/gogits/gogs/models"
)
type APIOrganization struct {
Organization *models.User
Team *models.Team
}

View File

@@ -2,66 +2,23 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package middleware
package context
import (
"fmt"
"net/url"
"github.com/go-macaron/csrf"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
type ToggleOptions struct {
SignInRequire bool
SignOutRequire bool
AdminRequire bool
DisableCsrf bool
}
// AutoSignIn reads cookie and try to auto-login.
func AutoSignIn(ctx *Context) (bool, error) {
if !models.HasEngine {
return false, nil
}
uname := ctx.GetCookie(setting.CookieUserName)
if len(uname) == 0 {
return false, nil
}
isSucceed := false
defer func() {
if !isSucceed {
log.Trace("auto-login cookie cleared: %s", uname)
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl)
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl)
}
}()
u, err := models.GetUserByName(uname)
if err != nil {
if !models.IsErrUserNotExist(err) {
return false, fmt.Errorf("GetUserByName: %v", err)
}
return false, nil
}
if val, _ := ctx.GetSuperSecureCookie(
base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); val != u.Name {
return false, nil
}
isSucceed = true
ctx.Session.Set("uid", u.Id)
ctx.Session.Set("uname", u.Name)
return true, nil
SignInRequired bool
SignOutRequired bool
AdminRequired bool
DisableCSRF bool
}
func Toggle(options *ToggleOptions) macaron.Handler {
@@ -72,30 +29,39 @@ func Toggle(options *ToggleOptions) macaron.Handler {
return
}
// Checking non-logged users landing page.
// Check prohibit login users.
if ctx.IsSigned && ctx.User.ProhibitLogin {
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(200, "user/auth/prohibit_login")
return
}
// Check non-logged users landing page.
if !ctx.IsSigned && ctx.Req.RequestURI == "/" && setting.LandingPageUrl != setting.LANDING_PAGE_HOME {
ctx.Redirect(setting.AppSubUrl + string(setting.LandingPageUrl))
return
}
// Redirect to dashboard if user tries to visit any non-login page.
if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
if options.SignOutRequired && ctx.IsSigned && ctx.Req.RequestURI != "/" {
ctx.Redirect(setting.AppSubUrl + "/")
return
}
if !options.SignOutRequire && !options.DisableCsrf && ctx.Req.Method == "POST" && !auth.IsAPIPath(ctx.Req.URL.Path) {
if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" && !auth.IsAPIPath(ctx.Req.URL.Path) {
csrf.Validate(ctx.Context, ctx.csrf)
if ctx.Written() {
return
}
}
if options.SignInRequire {
if options.SignInRequired {
if !ctx.IsSigned {
// Restrict API calls with error message.
if auth.IsAPIPath(ctx.Req.URL.Path) {
ctx.APIError(403, "", "Only signed in user is allowed to call APIs.")
ctx.JSON(403, map[string]string{
"message": "Only signed in user is allowed to call APIs.",
})
return
}
@@ -109,15 +75,15 @@ func Toggle(options *ToggleOptions) macaron.Handler {
}
}
// Auto-signin info is provided and has not signed in.
if !options.SignOutRequire && !ctx.IsSigned && !auth.IsAPIPath(ctx.Req.URL.Path) &&
// Redirect to log in page if auto-signin info is provided and has not signed in.
if !options.SignOutRequired && !ctx.IsSigned && !auth.IsAPIPath(ctx.Req.URL.Path) &&
len(ctx.GetCookie(setting.CookieUserName)) > 0 {
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login")
return
}
if options.AdminRequire {
if options.AdminRequired {
if !ctx.User.IsAdmin {
ctx.Error(403)
return

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 middleware
package context
import (
"fmt"
@@ -18,8 +18,6 @@ import (
"github.com/go-macaron/session"
"gopkg.in/macaron.v1"
"github.com/gogits/git-module"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
@@ -27,27 +25,6 @@ import (
"github.com/gogits/gogs/modules/setting"
)
type RepoContext struct {
AccessMode models.AccessMode
IsWatching bool
IsViewBranch bool
IsViewTag bool
IsViewCommit bool
Repository *models.Repository
Owner *models.User
Commit *git.Commit
Tag *git.Tag
GitRepo *git.Repository
BranchName string
TagName string
TreeName string
CommitID string
RepoLink string
CloneLink models.CloneLink
CommitsCount int64
Mirror *models.Mirror
}
// Context represents context of a request.
type Context struct {
*macaron.Context
@@ -60,38 +37,8 @@ type Context struct {
IsSigned bool
IsBasicAuth bool
Repo *RepoContext
Org struct {
IsOwner bool
IsMember bool
IsTeamMember bool // Is member of team.
IsTeamAdmin bool // In owner team or team that has admin permission level.
Organization *models.User
OrgLink string
Team *models.Team
}
}
// IsOwner returns true if current user is the owner of repository.
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 {
return r.AccessMode >= models.ACCESS_MODE_ADMIN
}
// IsWriter returns true if current user has write or higher access of repository.
func (r *RepoContext) IsWriter() bool {
return r.AccessMode >= models.ACCESS_MODE_WRITE
}
// HasAccess returns true if the current user has at least read access for this repository
func (r *RepoContext) HasAccess() bool {
return r.AccessMode >= models.ACCESS_MODE_READ
Repo *Repository
Org *Organization
}
// HasError returns true if error occurs in form validation.
@@ -165,25 +112,6 @@ func (ctx *Context) HandleText(status int, title string) {
ctx.PlainText(status, []byte(title))
}
// APIError logs error with title if status is 500.
func (ctx *Context) APIError(status int, title string, obj interface{}) {
var message string
if err, ok := obj.(error); ok {
message = err.Error()
} else {
message = obj.(string)
}
if status == 500 {
log.Error(4, "%s: %s", title, message)
}
ctx.JSON(status, map[string]string{
"message": message,
"url": base.DOC_URL,
})
}
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
modtime := time.Now()
for _, p := range params {
@@ -211,7 +139,10 @@ func Contexter() macaron.Handler {
csrf: x,
Flash: f,
Session: sess,
Repo: &RepoContext{},
Repo: &Repository{
PullRequest: &PullRequest{},
},
Org: &Organization{},
}
// Compute current URL for real-time change language.
ctx.Data["Link"] = setting.AppSubUrl + strings.TrimSuffix(ctx.Req.URL.Path, "/")

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 middleware
package context
import (
"strings"
@@ -13,6 +13,17 @@ import (
"github.com/gogits/gogs/modules/setting"
)
type Organization struct {
IsOwner bool
IsMember bool
IsTeamMember bool // Is member of team.
IsTeamAdmin bool // In owner team or team that has admin permission level.
Organization *models.User
OrgLink string
Team *models.Team
}
func HandleOrgAssignment(ctx *Context, args ...bool) {
var (
requireMember bool
@@ -90,7 +101,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
if ctx.Org.IsMember {
if ctx.Org.IsOwner {
if err := org.GetTeams(); err != nil {
ctx.Handle(500, "GetUserTeams", err)
ctx.Handle(500, "GetTeams", err)
return
}
} else {

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 middleware
package context
import (
"fmt"
@@ -18,6 +18,56 @@ import (
"github.com/gogits/gogs/modules/setting"
)
type PullRequest struct {
BaseRepo *models.Repository
Allowed bool
SameRepo bool
HeadInfo string // [<user>:]<branch>
}
type Repository struct {
AccessMode models.AccessMode
IsWatching bool
IsViewBranch bool
IsViewTag bool
IsViewCommit bool
Repository *models.Repository
Owner *models.User
Commit *git.Commit
Tag *git.Tag
GitRepo *git.Repository
BranchName string
TagName string
TreeName string
CommitID string
RepoLink string
CloneLink models.CloneLink
CommitsCount int64
Mirror *models.Mirror
PullRequest *PullRequest
}
// IsOwner returns true if current user is the owner of repository.
func (r *Repository) IsOwner() bool {
return r.AccessMode >= models.ACCESS_MODE_OWNER
}
// IsAdmin returns true if current user has admin or higher access of repository.
func (r *Repository) IsAdmin() bool {
return r.AccessMode >= models.ACCESS_MODE_ADMIN
}
// IsWriter returns true if current user has write or higher access of repository.
func (r *Repository) IsWriter() bool {
return r.AccessMode >= models.ACCESS_MODE_WRITE
}
// HasAccess returns true if the current user has at least read access for this repository
func (r *Repository) HasAccess() bool {
return r.AccessMode >= models.ACCESS_MODE_READ
}
func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
// Non-fork repository will not return error in this method.
if err := repo.GetBaseRepo(); err != nil {
@@ -110,6 +160,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Handle(500, "GetMirror", err)
return
}
ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune
ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
ctx.Data["Mirror"] = ctx.Repo.Mirror
}
@@ -123,7 +174,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
return
}
ctx.Repo.GitRepo = gitRepo
ctx.Repo.RepoLink = repo.RepoLink()
ctx.Repo.RepoLink = repo.Link()
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
@@ -142,32 +193,6 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter()
if repo.IsFork {
RetrieveBaseRepo(ctx, repo)
if ctx.Written() {
return
}
}
// People who have push access and propose a new pull request.
if ctx.Repo.IsWriter() {
// Pull request is allowed if this is a fork repository
// and base repository accepts pull requests.
if repo.BaseRepo != nil {
if repo.BaseRepo.AllowsPulls() {
ctx.Data["CanPullRequest"] = true
ctx.Data["BaseRepo"] = repo.BaseRepo
}
} else {
// Or, this is repository accepts pull requests between branches.
if repo.AllowsPulls() {
ctx.Data["CanPullRequest"] = true
ctx.Data["BaseRepo"] = repo
ctx.Data["IsBetweenBranches"] = true
}
}
}
ctx.Data["DisableSSH"] = setting.SSH.Disabled
ctx.Data["CloneLink"] = repo.CloneLink()
ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
@@ -209,10 +234,40 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Repo.BranchName = brs[0]
}
}
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["CommitID"] = ctx.Repo.CommitID
if repo.IsFork {
RetrieveBaseRepo(ctx, repo)
if ctx.Written() {
return
}
}
// People who have push access and propose a new pull request.
if ctx.Repo.IsWriter() {
// Pull request is allowed if this is a fork repository
// and base repository accepts pull requests.
if repo.BaseRepo != nil {
if repo.BaseRepo.AllowsPulls() {
ctx.Data["BaseRepo"] = repo.BaseRepo
ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
ctx.Repo.PullRequest.Allowed = true
ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName
}
} else {
// Or, this is repository accepts pull requests between branches.
if repo.AllowsPulls() {
ctx.Data["BaseRepo"] = repo
ctx.Repo.PullRequest.BaseRepo = repo
ctx.Repo.PullRequest.Allowed = true
ctx.Repo.PullRequest.SameRepo = true
ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName
}
}
}
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
if ctx.Query("go-get") == "1" {
ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)

View File

@@ -23,10 +23,10 @@ func NewLogger(bufLen int64, mode, config string) {
logger := newLogger(bufLen)
isExist := false
for _, l := range loggers {
for i, l := range loggers {
if l.adapter == mode {
isExist = true
l = logger
loggers[i] = logger
}
}
if !isExist {

View File

@@ -1,190 +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 mailer
import (
"fmt"
"path"
"strings"
"gopkg.in/gomail.v2"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
const (
AUTH_ACTIVATE base.TplName = "mail/auth/activate"
AUTH_ACTIVATE_EMAIL base.TplName = "mail/auth/activate_email"
AUTH_REGISTER_NOTIFY base.TplName = "mail/auth/register_notify"
AUTH_RESET_PASSWORD base.TplName = "mail/auth/reset_passwd"
NOTIFY_COLLABORATOR base.TplName = "mail/notify/collaborator"
NOTIFY_MENTION base.TplName = "mail/notify/mention"
)
func ComposeTplData(u *models.User) map[interface{}]interface{} {
data := make(map[interface{}]interface{}, 10)
data["AppName"] = setting.AppName
data["AppVer"] = setting.AppVer
data["AppUrl"] = setting.AppUrl
data["ActiveCodeLives"] = setting.Service.ActiveCodeLives / 60
data["ResetPwdCodeLives"] = setting.Service.ResetPwdCodeLives / 60
if u != nil {
data["User"] = u
}
return data
}
func SendUserMail(c *macaron.Context, u *models.User, tpl base.TplName, code, subject, info string) {
data := ComposeTplData(u)
data["Code"] = code
body, err := c.HTMLString(string(tpl), data)
if err != nil {
log.Error(4, "HTMLString: %v", err)
return
}
msg := NewMessage([]string{u.Email}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, %s", u.Id, info)
SendAsync(msg)
}
func SendActivateAccountMail(c *macaron.Context, u *models.User) {
SendUserMail(c, u, AUTH_ACTIVATE, u.GenerateActivateCode(), c.Tr("mail.activate_account"), "activate account")
}
// SendResetPasswordMail sends reset password e-mail.
func SendResetPasswordMail(c *macaron.Context, u *models.User) {
SendUserMail(c, u, AUTH_RESET_PASSWORD, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "reset password")
}
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
func SendRegisterNotifyMail(c *macaron.Context, u *models.User) {
body, err := c.HTMLString(string(AUTH_REGISTER_NOTIFY), ComposeTplData(u))
if err != nil {
log.Error(4, "HTMLString: %v", err)
return
}
msg := NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), body)
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.Id)
SendAsync(msg)
}
// SendActivateAccountMail sends confirmation e-mail.
func SendActivateEmailMail(c *macaron.Context, u *models.User, email *models.EmailAddress) {
data := ComposeTplData(u)
data["Code"] = u.GenerateEmailActivateCode(email.Email)
data["Email"] = email.Email
body, err := c.HTMLString(string(AUTH_ACTIVATE_EMAIL), data)
if err != nil {
log.Error(4, "HTMLString: %v", err)
return
}
msg := NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), body)
msg.Info = fmt.Sprintf("UID: %d, activate email", u.Id)
SendAsync(msg)
}
// SendIssueNotifyMail sends mail notification of all watchers of repository.
func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *models.Issue) ([]string, error) {
ws, err := models.GetWatchers(repo.ID)
if err != nil {
return nil, fmt.Errorf("GetWatchers[%d]: %v", repo.ID, err)
}
tos := make([]string, 0, len(ws))
for i := range ws {
uid := ws[i].UserID
if u.Id == uid {
continue
}
to, err := models.GetUserByID(uid)
if err != nil {
return nil, fmt.Errorf("GetUserByID: %v", err)
}
if to.IsOrganization() {
continue
}
tos = append(tos, to.Email)
}
if len(tos) == 0 {
return tos, nil
}
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>.",
markdown.RenderSpecialLink([]byte(strings.Replace(issue.Content, "\n", "<br>", -1)), 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)
SendAsync(msg)
return tos, nil
}
// SendIssueMentionMail sends mail notification for who are mentioned in issue.
func SendIssueMentionMail(r macaron.Render, u, owner *models.User,
repo *models.Repository, issue *models.Issue, tos []string) error {
if len(tos) == 0 {
return nil
}
subject := fmt.Sprintf("[%s] %s (#%d)", repo.Name, issue.Name, issue.Index)
data := ComposeTplData(nil)
data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
data["Subject"] = subject
data["ActUserName"] = u.DisplayName()
data["Content"] = string(markdown.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()))
body, err := r.HTMLString(string(NOTIFY_MENTION), data)
if err != nil {
return fmt.Errorf("HTMLString: %v", err)
}
msg := NewMessage(tos, subject, body)
msg.Info = fmt.Sprintf("Subject: %s, issue mention", subject)
SendAsync(msg)
return nil
}
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail(r macaron.Render, u, doer *models.User, repo *models.Repository) error {
subject := fmt.Sprintf("%s added you to %s/%s", doer.Name, repo.Owner.Name, repo.Name)
data := ComposeTplData(nil)
data["RepoLink"] = path.Join(repo.Owner.Name, repo.Name)
data["Subject"] = subject
body, err := r.HTMLString(string(NOTIFY_COLLABORATOR), data)
if err != nil {
return fmt.Errorf("HTMLString: %v", err)
}
msg := NewMessage([]string{u.Email}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.Id)
SendAsync(msg)
return nil
}
func SendTestMail(email string) error {
return gomail.Send(&Sender{}, NewMessage([]string{email}, "Gogs Test Email!", "Gogs Test Email!").Message)
}

View File

@@ -14,6 +14,7 @@ import (
"strings"
"time"
"github.com/jaytaylor/html2text"
"gopkg.in/gomail.v2"
"github.com/gogits/gogs/modules/log"
@@ -26,14 +27,25 @@ type Message struct {
}
// NewMessageFrom creates new mail message object with custom From header.
func NewMessageFrom(to []string, from, subject, body string) *Message {
func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
log.Trace("NewMessageFrom (htmlBody):\n%s", htmlBody)
msg := gomail.NewMessage()
msg.SetHeader("From", from)
msg.SetHeader("To", to...)
msg.SetHeader("Subject", subject)
msg.SetDateHeader("Date", time.Now())
msg.SetBody("text/plain", body)
msg.AddAlternative("text/html", body)
body, err := html2text.FromString(htmlBody)
if err != nil {
log.Error(4, "html2text.FromString: %v", err)
msg.SetBody("text/html", htmlBody)
} else {
msg.SetBody("text/plain", body)
if setting.MailService.EnableHTMLAlternative {
msg.AddAlternative("text/html", htmlBody)
}
}
return &Message{
Message: msg,
@@ -186,7 +198,7 @@ func processMailQueue() {
case msg := <-mailQueue:
log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info)
if err := gomail.Send(sender, msg.Message); err != nil {
log.Error(4, "Fail to send e-mails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
log.Error(3, "Fail to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
} else {
log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info)
}

View File

@@ -22,6 +22,11 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const (
ISSUE_NAME_STYLE_NUMERIC = "numeric"
ISSUE_NAME_STYLE_ALPHANUMERIC = "alphanumeric"
)
var Sanitizer = bluemonday.UGCPolicy()
// BuildSanitizer initializes sanitizer with allowed attributes based on settings.
@@ -79,13 +84,25 @@ var (
// IssueFullPattern matches link to an issue with or without trailing hash,
// e.g. https://try.gogs.io/gogs/gogs/issues/4#issue-685
IssueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
// IssueIndexPattern matches string that references to an issue, e.g. #1287
IssueIndexPattern = regexp.MustCompile(`( |^|\()#[0-9]+\b`)
// IssueNumericPattern matches string that references to a numeric issue, e.g. #1287
IssueNumericPattern = regexp.MustCompile(`( |^|\()#[0-9]+\b`)
// IssueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
IssueAlphanumericPattern = regexp.MustCompile(`( |^|\()[A-Z]{1,10}-[1-9][0-9]*\b`)
// Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
Sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
)
// FindAllMentions matches mention patterns in given content
// and returns a list of found user names without @ prefix.
func FindAllMentions(content string) []string {
mentions := MentionPattern.FindAllString(content, -1)
for i := range mentions {
mentions[i] = strings.TrimSpace(mentions[i])[1:] // Strip @ character
}
return mentions
}
// Renderer is a extended version of underlying render object.
type Renderer struct {
blackfriday.Renderer
@@ -113,28 +130,30 @@ func (r *Renderer) AutoLink(out *bytes.Buffer, link []byte, kind int) {
// Since this method could only possibly serve one link at a time,
// we do not need to find all.
m := CommitPattern.Find(link)
if m != nil {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "commit/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
if bytes.HasPrefix(link, []byte(setting.AppUrl)) {
m := CommitPattern.Find(link)
if m != nil {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "commit/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
out.WriteString(fmt.Sprintf(` <code><a href="%s">%s</a></code>`, m, base.ShortSha(string(m[i+7:j]))))
return
}
out.WriteString(fmt.Sprintf(` <code><a href="%s">%s</a></code>`, m, base.ShortSha(string(m[i+7:j]))))
return
}
m = IssueFullPattern.Find(link)
if m != nil {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "issues/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
m = IssueFullPattern.Find(link)
if m != nil {
m = bytes.TrimSpace(m)
i := strings.Index(string(m), "issues/")
j := strings.Index(string(m), "#")
if j == -1 {
j = len(m)
}
out.WriteString(fmt.Sprintf(`<a href="%s">#%s</a>`, m, base.ShortSha(string(m[i+7:j]))))
return
}
out.WriteString(fmt.Sprintf(` <a href="%s">#%s</a>`, m, base.ShortSha(string(m[i+7:j]))))
return
}
r.Renderer.AutoLink(out, link, kind)
@@ -159,6 +178,8 @@ var (
svgSuffixWithMark = []byte(".svg?")
spaceBytes = []byte(" ")
spaceEncodedBytes = []byte("%20")
space = " "
spaceEncoded = "%20"
)
// Image defines how images should be processed to produce corresponding HTML elements.
@@ -191,6 +212,9 @@ func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byt
// cutoutVerbosePrefix cutouts URL prefix including sub-path to
// return a clean unified string of request URL path.
func cutoutVerbosePrefix(prefix string) string {
if len(prefix) == 0 || prefix[0] != '/' {
return prefix
}
count := 0
for i := 0; i < len(prefix); i++ {
if prefix[i] == '/' {
@@ -206,22 +230,30 @@ func cutoutVerbosePrefix(prefix string) string {
// RenderIssueIndexPattern renders issue indexes to corresponding links.
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
urlPrefix = cutoutVerbosePrefix(urlPrefix)
ms := IssueIndexPattern.FindAll(rawBytes, -1)
pattern := IssueNumericPattern
if metas["style"] == ISSUE_NAME_STYLE_ALPHANUMERIC {
pattern = IssueAlphanumericPattern
}
ms := pattern.FindAll(rawBytes, -1)
for _, m := range ms {
var space string
if m[0] != '#' {
space = string(m[0])
m = m[1:]
if m[0] == ' ' || m[0] == '(' {
m = m[1:] // ignore leading space or opening parentheses
}
var link string
if metas == nil {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
space, urlPrefix, m[1:], m)), 1)
link = fmt.Sprintf(`<a href="%s/issues/%s">%s</a>`, urlPrefix, m[1:], m)
} else {
// Support for external issue tracker
metas["index"] = string(m[1:])
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s">%s</a>`,
space, com.Expand(metas["format"], metas), m)), 1)
if metas["style"] == ISSUE_NAME_STYLE_ALPHANUMERIC {
metas["index"] = string(m)
} else {
metas["index"] = string(m[1:])
}
link = fmt.Sprintf(`<a href="%s">%s</a>`, com.Expand(metas["format"], metas), m)
}
rawBytes = bytes.Replace(rawBytes, m, []byte(link), 1)
}
return rawBytes
}
@@ -357,6 +389,7 @@ OUTER_LOOP:
// Render renders Markdown to HTML with special links.
func Render(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
urlPrefix = strings.Replace(urlPrefix, space, spaceEncoded, -1)
result := RenderRaw(rawBytes, urlPrefix)
result = PostProcess(result, urlPrefix, metas)
result = Sanitizer.SanitizeBytes(result)

View File

@@ -0,0 +1,308 @@
package markdown_test
import (
. "github.com/gogits/gogs/modules/markdown"
. "github.com/smartystreets/goconvey/convey"
"testing"
"bytes"
"github.com/gogits/gogs/modules/setting"
"github.com/russross/blackfriday"
)
func TestMarkdown(t *testing.T) {
Convey("Rendering an issue mention", t, func() {
var (
urlPrefix = "/prefix"
metas map[string]string = nil
)
setting.AppSubUrlDepth = 0
Convey("To the internal issue tracker", func() {
Convey("It should not render anything when there are no mentions", func() {
testCases := []string{
"",
"this is a test",
"test 123 123 1234",
"#",
"# # #",
"# 123",
"#abcd",
"##1234",
"test#1234",
"#1234test",
" test #1234test",
}
for i := 0; i < len(testCases); i++ {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i])
}
})
Convey("It should render freestanding mentions", func() {
testCases := []string{
"#1234 test", "<a href=\"/prefix/issues/1234\">#1234</a> test",
"test #1234 issue", "test <a href=\"/prefix/issues/1234\">#1234</a> issue",
"test issue #1234", "test issue <a href=\"/prefix/issues/1234\">#1234</a>",
"#5 test", "<a href=\"/prefix/issues/5\">#5</a> test",
"test #5 issue", "test <a href=\"/prefix/issues/5\">#5</a> issue",
"test issue #5", "test issue <a href=\"/prefix/issues/5\">#5</a>",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should not render issue mention without leading space", func() {
input := []byte("test#54321 issue")
expected := "test#54321 issue"
So(string(RenderIssueIndexPattern(input, urlPrefix, metas)), ShouldEqual, expected)
})
Convey("It should not render issue mention without trailing space", func() {
input := []byte("test #54321issue")
expected := "test #54321issue"
So(string(RenderIssueIndexPattern(input, urlPrefix, metas)), ShouldEqual, expected)
})
Convey("It should render issue mention in parentheses", func() {
testCases := []string{
"(#54321 issue)", "(<a href=\"/prefix/issues/54321\">#54321</a> issue)",
"test (#54321) issue", "test (<a href=\"/prefix/issues/54321\">#54321</a>) issue",
"test (#54321 extra) issue", "test (<a href=\"/prefix/issues/54321\">#54321</a> extra) issue",
"test (#54321 issue)", "test (<a href=\"/prefix/issues/54321\">#54321</a> issue)",
"test (#54321)", "test (<a href=\"/prefix/issues/54321\">#54321</a>)",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should render multiple issue mentions in the same line", func() {
testCases := []string{
"#54321 #1243", "<a href=\"/prefix/issues/54321\">#54321</a> <a href=\"/prefix/issues/1243\">#1243</a>",
"test #54321 #1243", "test <a href=\"/prefix/issues/54321\">#54321</a> <a href=\"/prefix/issues/1243\">#1243</a>",
"(#54321 #1243)", "(<a href=\"/prefix/issues/54321\">#54321</a> <a href=\"/prefix/issues/1243\">#1243</a>)",
"(#54321)(#1243)", "(<a href=\"/prefix/issues/54321\">#54321</a>)(<a href=\"/prefix/issues/1243\">#1243</a>)",
"text #54321 test #1243 issue", "text <a href=\"/prefix/issues/54321\">#54321</a> test <a href=\"/prefix/issues/1243\">#1243</a> issue",
"#1 (#4321) test", "<a href=\"/prefix/issues/1\">#1</a> (<a href=\"/prefix/issues/4321\">#4321</a>) test",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
})
Convey("To an external issue tracker with numeric style", func() {
metas = make(map[string]string)
metas["format"] = "https://someurl.com/{user}/{repo}/{index}"
metas["user"] = "someuser"
metas["repo"] = "somerepo"
metas["style"] = ISSUE_NAME_STYLE_NUMERIC
Convey("should not render anything when there are no mentions", func() {
testCases := []string{
"this is a test",
"test 123 123 1234",
"#",
"# # #",
"# 123",
"#abcd",
}
for i := 0; i < len(testCases); i++ {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i])
}
})
Convey("It should render freestanding issue mentions", func() {
testCases := []string{
"#1234 test", "<a href=\"https://someurl.com/someuser/somerepo/1234\">#1234</a> test",
"test #1234 issue", "test <a href=\"https://someurl.com/someuser/somerepo/1234\">#1234</a> issue",
"test issue #1234", "test issue <a href=\"https://someurl.com/someuser/somerepo/1234\">#1234</a>",
"#5 test", "<a href=\"https://someurl.com/someuser/somerepo/5\">#5</a> test",
"test #5 issue", "test <a href=\"https://someurl.com/someuser/somerepo/5\">#5</a> issue",
"test issue #5", "test issue <a href=\"https://someurl.com/someuser/somerepo/5\">#5</a>",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should not render issue mention without leading space", func() {
input := []byte("test#54321 issue")
expected := "test#54321 issue"
So(string(RenderIssueIndexPattern(input, urlPrefix, metas)), ShouldEqual, expected)
})
Convey("It should not render issue mention without trailing space", func() {
input := []byte("test #54321issue")
expected := "test #54321issue"
So(string(RenderIssueIndexPattern(input, urlPrefix, metas)), ShouldEqual, expected)
})
Convey("It should render issue mention in parentheses", func() {
testCases := []string{
"(#54321 issue)", "(<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> issue)",
"test (#54321) issue", "test (<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a>) issue",
"test (#54321 extra) issue", "test (<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> extra) issue",
"test (#54321 issue)", "test (<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> issue)",
"test (#54321)", "test (<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a>)",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should render multiple issue mentions in the same line", func() {
testCases := []string{
"#54321 #1243", "<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> <a href=\"https://someurl.com/someuser/somerepo/1243\">#1243</a>",
"test #54321 #1243", "test <a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> <a href=\"https://someurl.com/someuser/somerepo/1243\">#1243</a>",
"(#54321 #1243)", "(<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> <a href=\"https://someurl.com/someuser/somerepo/1243\">#1243</a>)",
"(#54321)(#1243)", "(<a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a>)(<a href=\"https://someurl.com/someuser/somerepo/1243\">#1243</a>)",
"text #54321 test #1243 issue", "text <a href=\"https://someurl.com/someuser/somerepo/54321\">#54321</a> test <a href=\"https://someurl.com/someuser/somerepo/1243\">#1243</a> issue",
"#1 (#4321) test", "<a href=\"https://someurl.com/someuser/somerepo/1\">#1</a> (<a href=\"https://someurl.com/someuser/somerepo/4321\">#4321</a>) test",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
})
Convey("To an external issue tracker with alphanumeric style", func() {
metas = make(map[string]string)
metas["format"] = "https://someurl.com/{user}/{repo}/?b={index}"
metas["user"] = "someuser"
metas["repo"] = "somerepo"
metas["style"] = ISSUE_NAME_STYLE_ALPHANUMERIC
Convey("It should not render anything when there are no mentions", func() {
testCases := []string{
"",
"this is a test",
"test 123 123 1234",
"#",
"##1234",
"# 123",
"#abcd",
"test #123",
"abc-1234", // issue prefix must be capital
"ABc-1234", // issue prefix must be _all_ capital
"ABCDEFGHIJK-1234", // the limit is 10 characters in the prefix
"ABC1234", // dash is required
"test ABC- test", // number is required
"test -1234 test", // prefix is required
"testABC-123 test", // leading space is required
"test ABC-123test", // trailing space is required
"ABC-0123", // no leading zero
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i])
}
})
Convey("It should render freestanding issue mention", func() {
testCases := []string{
"OTT-1234 test", "<a href=\"https://someurl.com/someuser/somerepo/?b=OTT-1234\">OTT-1234</a> test",
"test T-12 issue", "test <a href=\"https://someurl.com/someuser/somerepo/?b=T-12\">T-12</a> issue",
"test issue ABCDEFGHIJ-1234567890", "test issue <a href=\"https://someurl.com/someuser/somerepo/?b=ABCDEFGHIJ-1234567890\">ABCDEFGHIJ-1234567890</a>",
"A-1 test", "<a href=\"https://someurl.com/someuser/somerepo/?b=A-1\">A-1</a> test",
"test ZED-1 issue", "test <a href=\"https://someurl.com/someuser/somerepo/?b=ZED-1\">ZED-1</a> issue",
"test issue DEED-7154", "test issue <a href=\"https://someurl.com/someuser/somerepo/?b=DEED-7154\">DEED-7154</a>",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should render issue mention in parentheses", func() {
testCases := []string{
"(ABG-124 issue)", "(<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> issue)",
"test (ABG-124) issue", "test (<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a>) issue",
"test (ABG-124 extra) issue", "test (<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> extra) issue",
"test (ABG-124 issue)", "test (<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> issue)",
"test (ABG-124)", "test (<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a>)",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
Convey("It should render multiple issue mentions in the same line", func() {
testCases := []string{
"ABG-124 OTT-4321", "<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> <a href=\"https://someurl.com/someuser/somerepo/?b=OTT-4321\">OTT-4321</a>",
"test ABG-124 OTT-4321", "test <a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> <a href=\"https://someurl.com/someuser/somerepo/?b=OTT-4321\">OTT-4321</a>",
"(ABG-124 OTT-4321)", "(<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> <a href=\"https://someurl.com/someuser/somerepo/?b=OTT-4321\">OTT-4321</a>)",
"(ABG-124)(OTT-4321)", "(<a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a>)(<a href=\"https://someurl.com/someuser/somerepo/?b=OTT-4321\">OTT-4321</a>)",
"text ABG-124 test OTT-4321 issue", "text <a href=\"https://someurl.com/someuser/somerepo/?b=ABG-124\">ABG-124</a> test <a href=\"https://someurl.com/someuser/somerepo/?b=OTT-4321\">OTT-4321</a> issue",
"A-1 (RRE-345) test", "<a href=\"https://someurl.com/someuser/somerepo/?b=A-1\">A-1</a> (<a href=\"https://someurl.com/someuser/somerepo/?b=RRE-345\">RRE-345</a>) test",
}
for i := 0; i < len(testCases); i += 2 {
So(string(RenderIssueIndexPattern([]byte(testCases[i]), urlPrefix, metas)), ShouldEqual, testCases[i+1])
}
})
})
})
Convey("Rendering an issue URL", t, func() {
setting.AppUrl = "http://localhost:3000/"
htmlFlags := 0
htmlFlags |= blackfriday.HTML_SKIP_STYLE
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
renderer := &Renderer{
Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""),
}
buffer := new(bytes.Buffer)
Convey("To the internal issue tracker", func() {
Convey("It should render valid issue URLs", func() {
testCases := []string{
"http://localhost:3000/user/repo/issues/3333", "<a href=\"http://localhost:3000/user/repo/issues/3333\">#3333</a>",
}
for i := 0; i < len(testCases); i += 2 {
renderer.AutoLink(buffer, []byte(testCases[i]), blackfriday.LINK_TYPE_NORMAL)
line, _ := buffer.ReadString(0)
So(line, ShouldEqual, testCases[i+1])
}
})
Convey("It should render but not change non-issue URLs", func() {
testCases := []string{
"http://1111/2222/ssss-issues/3333?param=blah&blahh=333", "<a href=\"http://1111/2222/ssss-issues/3333?param=blah&amp;blahh=333\">http://1111/2222/ssss-issues/3333?param=blah&amp;blahh=333</a>",
"http://test.com/issues/33333", "<a href=\"http://test.com/issues/33333\">http://test.com/issues/33333</a>",
"http://test.com/issues/3", "<a href=\"http://test.com/issues/3\">http://test.com/issues/3</a>",
"http://issues/333", "<a href=\"http://issues/333\">http://issues/333</a>",
"https://issues/333", "<a href=\"https://issues/333\">https://issues/333</a>",
"http://tissues/0", "<a href=\"http://tissues/0\">http://tissues/0</a>",
}
for i := 0; i < len(testCases); i += 2 {
renderer.AutoLink(buffer, []byte(testCases[i]), blackfriday.LINK_TYPE_NORMAL)
line, _ := buffer.ReadString(0)
So(line, ShouldEqual, testCases[i+1])
}
})
})
})
Convey("Rendering a commit URL", t, func() {
setting.AppUrl = "http://localhost:3000/"
htmlFlags := 0
htmlFlags |= blackfriday.HTML_SKIP_STYLE
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
renderer := &Renderer{
Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""),
}
buffer := new(bytes.Buffer)
Convey("To the internal issue tracker", func() {
Convey("It should correctly convert URLs", func() {
testCases := []string{
"http://localhost:3000/user/project/commit/d8a994ef243349f321568f9e36d5c3f444b99cae", " <code><a href=\"http://localhost:3000/user/project/commit/d8a994ef243349f321568f9e36d5c3f444b99cae\">d8a994ef24</a></code>",
"http://localhost:3000/user/project/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2", " <code><a href=\"http://localhost:3000/user/project/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2\">d8a994ef24</a></code>",
"https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2", "<a href=\"https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2\">https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2</a>",
"https://commit/d8a994ef243349f321568f9e36d5c3f444b99cae", "<a href=\"https://commit/d8a994ef243349f321568f9e36d5c3f444b99cae\">https://commit/d8a994ef243349f321568f9e36d5c3f444b99cae</a>",
}
for i := 0; i < len(testCases); i += 2 {
renderer.AutoLink(buffer, []byte(testCases[i]), blackfriday.LINK_TYPE_NORMAL)
line, _ := buffer.ReadString(0)
So(line, ShouldEqual, testCases[i+1])
}
})
})
})
}

View File

@@ -54,7 +54,7 @@ var (
AppSubUrl string
AppSubUrlDepth int // Number of slashes
AppPath string
AppDataPath = "data"
AppDataPath string
// Server settings
Protocol Scheme
@@ -123,6 +123,7 @@ var (
AdminNoticePagingNum int
AdminOrgPagingNum int
ThemeColorMetaTag string
MaxDisplayFileSize int64
// Markdown sttings
Markdown struct {
@@ -156,19 +157,8 @@ var (
CacheConn string
// Session settings
SessionConfig session.Options
// Git settings
Git struct {
MaxGitDiffLines int
GcArgs []string `delim:" "`
Timeout struct {
Migrate int
Mirror int
Clone int
Pull int
} `ini:"git.timeout"`
}
SessionConfig session.Options
CSRFCookieName = "_csrf"
// Cron tasks
Cron struct {
@@ -191,6 +181,25 @@ var (
} `ini:"cron.check_repo_stats"`
}
// Git settings
Git struct {
MaxGitDiffLines int
MaxGitDiffLineCharacters int
MaxGitDiffFiles int
GcArgs []string `delim:" "`
Timeout struct {
Migrate int
Mirror int
Clone int
Pull int
} `ini:"git.timeout"`
}
// API settings
API struct {
MaxResponseItems int
}
// I18n settings
Langs, Names []string
dateLangs map[string]string
@@ -330,10 +339,11 @@ func NewContext() {
Domain = sec.Key("DOMAIN").MustString("localhost")
HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
HttpPort = sec.Key("HTTP_PORT").MustString("3000")
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString("http://localhost:" + HttpPort + "/")
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HttpPort + "/")
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
switch sec.Key("LANDING_PAGE").MustString("home") {
@@ -359,12 +369,6 @@ func NewContext() {
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
log.Fatal(4, "Fail to create '%s': %v", SSH.KeyTestPath, err)
}
if !filepath.IsAbs(SSH.KeygenPath) {
if _, err := exec.LookPath(SSH.KeygenPath); err != nil {
log.Fatal(4, "Fail to test '%s' command: %v (forgotten install?)", SSH.KeygenPath, err)
}
}
}
SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool()
@@ -438,6 +442,7 @@ func NewContext() {
ExplorePagingNum = sec.Key("EXPLORE_PAGING_NUM").MustInt(20)
IssuePagingNum = sec.Key("ISSUE_PAGING_NUM").MustInt(10)
FeedMaxCommitNum = sec.Key("FEED_MAX_COMMIT_NUM").MustInt(5)
MaxDisplayFileSize = sec.Key("MAX_DISPLAY_FILE_SIZE").MustInt64(8388608)
sec = Cfg.Section("ui.admin")
AdminUserPagingNum = sec.Key("USER_PAGING_NUM").MustInt(50)
@@ -467,10 +472,12 @@ func NewContext() {
if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
log.Fatal(4, "Fail to map Markdown settings: %v", err)
} else if err = Cfg.Section("git").MapTo(&Git); err != nil {
log.Fatal(4, "Fail to map Git settings: %v", err)
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
log.Fatal(4, "Fail to map Cron settings: %v", err)
} else if err = Cfg.Section("git").MapTo(&Git); err != nil {
log.Fatal(4, "Fail to map Git settings: %v", err)
} else if err = Cfg.Section("api").MapTo(&API); err != nil {
log.Fatal(4, "Fail to map API settings: %v", err)
}
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
@@ -616,16 +623,17 @@ func newSessionService() {
// Mailer represents mail service.
type Mailer struct {
QueueLength int
Name string
Host string
From string
User, Passwd string
DisableHelo bool
HeloHostname string
SkipVerify bool
UseCertificate bool
CertFile, KeyFile string
QueueLength int
Name string
Host string
From string
User, Passwd string
DisableHelo bool
HeloHostname string
SkipVerify bool
UseCertificate bool
CertFile, KeyFile string
EnableHTMLAlternative bool
}
var (
@@ -640,17 +648,18 @@ func newMailService() {
}
MailService = &Mailer{
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
Name: sec.Key("NAME").MustString(AppName),
Host: sec.Key("HOST").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
CertFile: sec.Key("CERT_FILE").String(),
KeyFile: sec.Key("KEY_FILE").String(),
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
Name: sec.Key("NAME").MustString(AppName),
Host: sec.Key("HOST").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
CertFile: sec.Key("CERT_FILE").String(),
KeyFile: sec.Key("KEY_FILE").String(),
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
}
MailService.From = sec.Key("FROM").MustString(MailService.User)
log.Info("Mail Service Enabled")

View File

@@ -62,12 +62,12 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
}
case "exec":
cmdName := strings.TrimLeft(payload, "'()")
os.Setenv("SSH_ORIGINAL_COMMAND", cmdName)
log.Trace("SSH: Payload: %v", cmdName)
args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf}
log.Trace("SSH: Arguments: %v", args)
cmd := exec.Command(setting.AppPath, args...)
cmd.Env = append(os.Environ(), "SSH_ORIGINAL_COMMAND="+cmdName)
stdout, err := cmd.StdoutPipe()
if err != nil {

View File

@@ -18,6 +18,7 @@ import (
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
@@ -97,7 +98,7 @@ func NewFuncMap() []template.FuncMap {
"ActionContent2Commits": ActionContent2Commits,
"ToUtf8": ToUtf8,
"EscapePound": func(str string) string {
return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1)
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20").Replace(str)
},
"RenderCommitMessage": RenderCommitMessage,
"ThemeColorMetaTag": func() string {
@@ -240,7 +241,7 @@ func ActionIcon(opType int) string {
case 7: // New pull request
return "git-pull-request"
case 10: // Comment issue
return "comment"
return "comment-discussion"
case 11: // Merge pull request
return "git-merge"
case 12, 14: // Close issue or pull request
@@ -255,7 +256,7 @@ func ActionIcon(opType int) string {
func ActionContent2Commits(act Actioner) *models.PushCommits {
push := models.NewPushCommits()
if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
return nil
log.Error(4, "json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
}
return push
}

View File

@@ -5,7 +5,7 @@
package user
import (
"os"
"os"
)
func CurrentUsername() string {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -169,7 +169,7 @@
<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf092;" d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
@@ -178,7 +178,7 @@
<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf09b;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" />
<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
@@ -363,7 +363,7 @@
<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
<glyph unicode="&#xf16c;" d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" />
<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
<glyph unicode="&#xf16d;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" />
<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
@@ -484,7 +484,7 @@
<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1ed;" d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" />
<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M441 864q32 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" />
<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
@@ -626,7 +626,7 @@
<glyph unicode="&#xf283;" horiz-adv-x="2304" d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" />
<glyph unicode="&#xf284;" horiz-adv-x="1792" d="M1549 857q55 0 85.5 -28.5t30.5 -83.5t-34 -82t-91 -27h-136v-177h-25v398h170zM1710 267l-4 -11l-5 -10q-113 -230 -330.5 -366t-474.5 -136q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q244 0 454.5 -124t329.5 -338l2 -4l8 -16 q-30 -15 -136.5 -68.5t-163.5 -84.5q-6 -3 -479 -268q384 -183 799 -366zM896 -234q250 0 462.5 132.5t322.5 357.5l-287 129q-72 -140 -206 -222t-292 -82q-151 0 -280 75t-204 204t-75 280t75 280t204 204t280 75t280 -73.5t204 -204.5l280 143q-116 208 -321 329 t-443 121q-119 0 -232.5 -31.5t-209 -87.5t-176.5 -137t-137 -176.5t-87.5 -209t-31.5 -232.5t31.5 -232.5t87.5 -209t137 -176.5t176.5 -137t209 -87.5t232.5 -31.5z" />
<glyph unicode="&#xf285;" horiz-adv-x="1792" d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" />
<glyph unicode="&#xf286;" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h16v393q-32 19 -32 55q0 26 19 45t45 19t45 -19t19 -45q0 -36 -32 -55v-9h272q16 0 16 -16v-224q0 -16 -16 -16h-272v-128h16q16 0 16 -16v-112h128 v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96q16 0 16 -16z" />
<glyph unicode="&#xf286;" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 q16 0 16 -16z" />
<glyph unicode="&#xf287;" horiz-adv-x="2304" d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" />
<glyph unicode="&#xf288;" horiz-adv-x="1792" d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
<glyph unicode="&#xf289;" horiz-adv-x="2304" d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" />
@@ -641,15 +641,45 @@
<glyph unicode="&#xf293;" d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" />
<glyph unicode="&#xf294;" horiz-adv-x="1024" d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" />
<glyph unicode="&#xf295;" d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
<glyph unicode="&#xf296;" horiz-adv-x="1792" />
<glyph unicode="&#xf297;" horiz-adv-x="1792" />
<glyph unicode="&#xf298;" horiz-adv-x="1792" />
<glyph unicode="&#xf299;" horiz-adv-x="1792" />
<glyph unicode="&#xf29a;" horiz-adv-x="1792" />
<glyph unicode="&#xf29b;" horiz-adv-x="1792" />
<glyph unicode="&#xf29c;" horiz-adv-x="1792" />
<glyph unicode="&#xf29d;" horiz-adv-x="1792" />
<glyph unicode="&#xf29e;" horiz-adv-x="1792" />
<glyph unicode="&#xf296;" horiz-adv-x="1792" d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" />
<glyph unicode="&#xf297;" horiz-adv-x="1792" d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" />
<glyph unicode="&#xf298;" d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" />
<glyph unicode="&#xf299;" horiz-adv-x="1792" d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" />
<glyph unicode="&#xf29a;" horiz-adv-x="1792" d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
<glyph unicode="&#xf29b;" d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" />
<glyph unicode="&#xf29c;" d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf29d;" horiz-adv-x="1408" d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 q-67 -192 -92 -234q-16 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 q3 -1 7 1t7 4l3 2q11 9 11 17z" />
<glyph unicode="&#xf29e;" horiz-adv-x="2304" d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 t9.5 -70.5z" />
<glyph unicode="&#xf2a0;" horiz-adv-x="1408" d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 q-18 -19 -45 -19z" />
<glyph unicode="&#xf2a1;" horiz-adv-x="2176" d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" />
<glyph unicode="&#xf2a2;" horiz-adv-x="1792" d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" />
<glyph unicode="&#xf2a3;" horiz-adv-x="2304" d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" />
<glyph unicode="&#xf2a4;" horiz-adv-x="1792" d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" />
<glyph unicode="&#xf2a5;" d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf2a6;" horiz-adv-x="1535" d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" />
<glyph unicode="&#xf2a7;" horiz-adv-x="1664" d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147l-4 -4t-5 -4q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148q-34 23 -76 23 q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26l-12 224 q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" />
<glyph unicode="&#xf2a8;" horiz-adv-x="1792" d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" />
<glyph unicode="&#xf2a9;" horiz-adv-x="1280" d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" />
<glyph unicode="&#xf2aa;" d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 43 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
<glyph unicode="&#xf2ab;" d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
<glyph unicode="&#xf2ac;" horiz-adv-x="1664" d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" />
<glyph unicode="&#xf2ad;" d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf2ae;" horiz-adv-x="2304" d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" />
<glyph unicode="&#xf2b0;" d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" />
<glyph unicode="&#xf2b1;" horiz-adv-x="1664" d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" />
<glyph unicode="&#xf2b2;" horiz-adv-x="1792" d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" />
<glyph unicode="&#xf2b3;" d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf2b4;" d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf2b5;" horiz-adv-x="1792" />
<glyph unicode="&#xf2b6;" horiz-adv-x="1792" />
<glyph unicode="&#xf2b7;" horiz-adv-x="1792" />
<glyph unicode="&#xf2b8;" horiz-adv-x="1792" />
<glyph unicode="&#xf2b9;" horiz-adv-x="1792" />
<glyph unicode="&#xf2ba;" horiz-adv-x="1792" />
<glyph unicode="&#xf2bb;" horiz-adv-x="1792" />
<glyph unicode="&#xf2bc;" horiz-adv-x="1792" />
<glyph unicode="&#xf2bd;" horiz-adv-x="1792" />
<glyph unicode="&#xf2be;" horiz-adv-x="1792" />
<glyph unicode="&#xf500;" horiz-adv-x="1792" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 382 KiB

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