Compare commits

...

292 Commits

Author SHA1 Message Date
Unknwon
81e6f82caf Update glide.lock and .gopmfile [CI SKIP] 2016-08-10 11:57:53 -07:00
Unknwon
29f76f3936 Update locales [CI SKIP] 2016-08-10 11:54:52 -07:00
lstahlman
ea192147ea Add test pull request task on merging a PR. Fixes #3396 (#3425) 2016-08-10 11:38:44 -07:00
Thibault Meyer
99812a80fd Fix #3420: Bad commit URL generation (#3424) 2016-08-10 11:35:06 -07:00
Thibault Meyer
8ad92bb8a4 Verify list len before use it with IN (#3423) 2016-08-10 11:06:51 -07:00
Unknwon
b85927e488 #3091 show Git configs on admin panel 2016-08-10 11:01:42 -07:00
Unknwon
87b408a2e5 Update bindata.go [CI SKIP] 2016-08-09 23:58:15 -07:00
Thibault Meyer
fc68fb951c Feature #3398: Redefine global mirror interval (#3409)
* add mirror::GLOBAL_INTERVAL on app.ini

* rename key to DEFAULT_INTERVAL

* add key on default app.ini + move code
2016-08-09 23:47:16 -07:00
Unknwon
5448d29b2e #3417 wrong dashboard issue count for create by you 2016-08-09 23:19:52 -07:00
Unknwon
bb51eb5188 Update cron revision [CI SKIP] 2016-08-09 22:02:51 -07:00
lstahlman
89f71b44f7 Add committer information to API and Webhooks. Also fixes #3271 (#3414) 2016-08-09 22:01:57 -07:00
Unknwon
c5d4a9e046 #2907 Add commit timestamp to webhook 2016-08-09 18:28:06 -07:00
Unknwon
edd786446c #3158 skip RUN_USER check on Windows 2016-08-09 17:41:18 -07:00
Unknwon
b0b88d9bc5 #3091 add config option for Git GC 2016-08-09 17:24:32 -07:00
Unknwon
15b0cbe318 #3007 update git-module require version 2016-08-09 17:15:48 -07:00
Unknwon
9f0c571238 Change LICENSE copyright holder name [CI SKIP] 2016-08-09 13:05:15 -07:00
Unknwon
f70343660d Little code refactoring 2016-08-09 12:56:00 -07:00
Rory McNamara
c8b45ecc27 Render the Code view on the server (minus syntax highlighting) (#2942)
* render code view server side

* remove debug print

* fix multiline selection bug

* change string concatenation to bytes.Buffer for efficiency

* Fix newlines added by previous for hljs

* fix selection highlighting

* make css changes in .less
2016-08-09 12:35:20 -07:00
Unknwon
9e8a8867ea #3325 use correct word for .gitignore 2016-08-09 12:16:21 -07:00
lstahlman
2c82fc3edb Fix for #3410 overall issues for organisations is limited to num_repos from the user (#3412) 2016-08-09 10:00:42 -07:00
Unknwon
bbe866122d #3406 fix regression of MustEnableIssues check 2016-08-09 09:39:55 -07:00
Unknwon
87954dbfeb Adjust .codebeatsettings 2016-08-08 23:26:10 -07:00
lstahlman
699c71d319 Fix for #3401 Links of pull request comment email should use pulls URL (#3403) 2016-08-08 22:40:05 -07:00
Unknwon
21f25799b4 Add codebeat files 2016-08-08 20:03:46 -07:00
Unknwon
90af997fec #3399 500 for upstream pulls page if user has forked repository 2016-08-08 13:02:55 -07:00
Unknwon
b73318bc62 Fix 404 when comment on pulls and not using interal issue tracker 2016-08-08 11:29:50 -07:00
Unknwon
e5bf4281b5 #2825 early response 200 when ?go-get=1 2016-08-07 14:29:16 -07:00
Unknwon
0c2b9bbb2b Update glide.lock and .gopmfile 2016-08-07 11:05:19 -07:00
Unknwon
99385db0c4 #3320 code cleanup 2016-08-07 11:01:47 -07:00
Sandro Santilli
90dd0657b5 Add support for federated avatars (#3320)
* Add support for federated avatars

Fixes #3105

Removes avatar fetching duplication code
Adds an "Enable Federated Avatar" checkbox in user settings
(defaults to unchecked)

Moves avatar settings all in the same form, making
local and remote avatars mutually exclusive

Renames UploadAvatarForm to AvatarForm
as it's not anymore only for uploading

* Run gofmt on all modified files

* Move Avatar form in its own page

* Add go-libravatar dependency to vendor/ dir

Hopefully helps with accepting the contribution.
See also #3214

* Revert "Add go-libravatar dependency to vendor/ dir"

This reverts commit a8cb93ae640bbb90f7d25012fc257bda9fae9b82.

* Make federated avatar setting a global configuration

Removes the per-user setting

* Move avatar handling back to base tool, disable federated avatar in offline mode

* Format, handle error

* Properly set fallback host

* Use unsupported github.com mirror for importing go-libravatar

* Remove comment showing life exists outside of github.com

... pity, but contribution would not be accepted otherwise

* Use Combo for Get and Post methods over /avatar

* FEDERATED_AVATAR -> ENABLE_FEDERATED_AVATAR

* Fix persistance of federated avatar lookup checkbox at install time

* Federated Avatars -> Enable Federated Avatars

* Use len(string) == 0 instead of string == ""

* Move import line where it belong

See
https://github.com/Unknwon/go-code-convention/blob/master/en-US/import_packages.md

Pity the import url is still the unofficial one, but oh well...

* Save a line (and waste much more expensive time)

* Remove redundant parens

* Remove an empty line

* Remove empty lines

* Reorder lines to make diff smaller

* Remove another newline

Unknwon review got me start a fight against newlines

* Move DISABLE_GRAVATAR and ENABLE_FEDERATED_AVATAR after OFFLINE_MODE

On re-reading the diff I figured what Unknwon meant here:
https://github.com/gogits/gogs/pull/3320/files#r73741106

* Remove newlines that weren't there before my intervention
2016-08-07 10:27:38 -07:00
Unknwon
ec92565f23 #3393 fix missing sub-url prefix in relative avatar link 2016-08-07 10:13:05 -07:00
Andrey Nering
2772791fda Improve diff highlight (#3390)
- Try to reduce memory allocations
- Add possibility to disable diff highlight (can improve performance for large diffs)
- Tweaking with cost for prettier (cleaner) diffs
- Do not calculate diff when the number of removed lines in a block is not equal to the number of added lines (this usually resulted in ugly diffs)
2016-08-07 09:49:47 -07:00
Unknwon
08c976f811 Only do go vet on this codebase 2016-08-06 11:20:10 -07:00
Unknwon
72dd299ca0 Update .gitattributes 2016-08-06 10:36:40 -07:00
Thibault Meyer
30fda0f1ae Fix #3315: Release dont use tag creation date (#3374)
* Fix #3315: Release dont use tag creation date

* Simplify code and apply gofmt

* remove useless block (ctx.Repo.GitRepo.GetTag) on EditReleasePost

* apply gofmt on modified files
2016-08-06 10:02:15 -07:00
Unknwon
ab9c5fb5e7 #2593 allow render raw content
Use URL query parameter render=1 to render content in raw mode.
2016-08-05 18:34:13 -07:00
rugk
28dc5bb566 Replace gogs.io http links with https version (#3386) 2016-08-05 17:35:40 -07:00
Unknwon
cf6d321991 Ignore repository with issue disabled or use external tracker in dashboard issues 2016-08-05 12:46:26 -07:00
Unknwon
50422f1fc2 #3348 always use relative avatar link in the template 2016-08-05 12:12:54 -07:00
Unknwon
db3d393576 routers/api: rename handlers to be unexported 2016-08-04 17:08:01 -07:00
Unknwon
2f105f3979 #2162 completely disable builtin issue tracker when enable external tracker 2016-08-04 16:32:02 -07:00
Unknwon
ee28fd9255 Update locales [CI SKIP] 2016-08-03 12:24:53 -07:00
Unknwon
13d492e92a Update .gopmfile and glide.lock 2016-08-03 12:12:33 -07:00
Unknwon
e7fd65f0cf #3290 better code structure and batch minor improvements 2016-08-03 11:51:22 -07:00
lstahlman
2eeb0ec9b0 Additional API support for labels (#3290)
* Add API support for labels.

* Error handling for adding/replacing multiple issue labels

* Revisions to function names and error handling. Use issue.ClearLabels in replace/clear functions

* Additional code cleanup
2016-08-03 09:24:16 -07:00
silverwind
b1133c9934 Lighter icon colors for repo files (#3351)
* Lighter icon colors for repo files

* also color submodule icon
2016-08-03 08:53:28 -07:00
Unknwon
991ce42c48 #2162 improve repository advance options UI display
Enable/disable input based on user chosen options for wiki and issue tracker.
2016-07-31 01:26:43 +08:00
Unknwon
10dc330640 #3345 dump content directly to HTTP ResponseWriter 2016-07-30 23:39:58 +08:00
Dennis Chen
dfab54d5a2 Diff patch (#3345)
* Add support for .diff and .patch

Add the ability to get text-diff and format-patch by adding .diff or
.patch in the end of a commit url. Issue #2641

* models: git_diff: various fixes

* Renames commitId to commitID.
* Writes stderr to a bytes.Buffer and displays proper error message on
command failure.
* Various style changes.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2016-07-30 23:02:22 +08:00
Unknwon
3e22ae3412 Update locales 2016-07-30 22:28:23 +08:00
Okunev Yu Dmitry
55b4e77a5e Fix of template error in "/:owner/:repo/pulls" (#3343)
If anonymous (not signed in user) requests page
"/:owner/:repo/pulls" he gets an error:

  template: repo/issue/list:11:105: executing "repo/issue/list" at <.PullRequestCtx.Base...>: nil pointer evaluating *models.Repository.Link

This commit fixes that.

Signed-off-by: Dmitry Yu Okunev <dyokunev@ut.mephi.ru>
2016-07-29 22:59:38 +08:00
Unknwon
ad7ea88923 Update glide.lock 2016-07-28 11:00:14 +08:00
Unknwon
f2884d8e31 Minor fix for pull request template [CI SKIP] 2016-07-28 10:54:52 +08:00
마누엘
36a63dd059 models/release: Update Sha1 if tag already exists (#3331)
Since the release struct is initialized with the current `HEAD` of the
current `release.Target` the commit id has to be updated if the tag
commit already exists. Otherwise the linked commit on the release page
will target the current `HEAD` at release time.
2016-07-28 10:45:35 +08:00
Unknwon
03ba257ad2 Update GitHub templates 2016-07-28 10:36:26 +08:00
마누엘
fe60ca408b routers/repo/release: Use correct branch reference (#3330)
When calculating the current behind commit count the calculation should
use the current release target to get the total commit count. Should the
release target not exist anymore the calculation will return zero for
the newest release on that target. Older releases on that target will then
use that calculated commit count as reference.

The only use case that is now somehow invalid is when the release target
was merged / deleted after a tag on that release target:

    master 1 - - - - - - - 6
            \             /
    branch   2 - 3 - 4 - 5

When `4` is the last tag on branch `branch` and the branch `branch` is not
yet deleted the calculated numbers would be:

    1 commits to branch since this release

Now if the branch `branch` gets deleted the calculation function will not
find the branch and use the commit count of the newest release (`4`) as
reference resulting in:

    0 commit to branch since this release

This fixes #3326
2016-07-27 16:57:32 +08:00
Richard Mahn
0402c803c6 Added Full Name to CreateUser api call (#3333) 2016-07-27 02:43:06 +08:00
Unknwon
29ccf047d8 routers/repo/issue: remove redundant format string 2016-07-26 18:42:18 +08:00
Unknwon
8aa0a76702 #3327 fix wrong table name in Join 2016-07-26 18:40:20 +08:00
Unknwon
2d76de2574 #3281 fix x.Iterate returns nothing inside session scope with SQLite3 2016-07-26 17:26:48 +08:00
Unknwon
4d8b905541 models/ssh_key: code cleaning 2016-07-26 10:47:25 +08:00
Unknwon
452aefd025 Fix issue event octicon CSS 2016-07-26 02:56:07 +08:00
Unknwon
899e799459 #1601 support delete issue comment 2016-07-26 02:48:17 +08:00
Unknwon
2295fafb34 repo/settings/options: take naming style examples out of locale string 2016-07-25 16:55:51 +08:00
Unknwon
a562228c5e Add org.getUserTeams to reduce redundant code 2016-07-24 18:09:45 +08:00
Unknwon
e74630ae3b #1384 add pagination for repositories 2016-07-24 14:32:46 +08:00
Unknwon
1f2e173a74 Refactor User.Id to User.ID 2016-07-24 01:08:22 +08:00
Unknwon
46e96c008c Use struct for UI settings 2016-07-24 00:23:54 +08:00
Unknwon
256cd6374a #2790 fix not detect diff style in pull request file changes 2016-07-23 23:46:49 +08:00
Unknwon
57a47bbc05 Add some tutorial links [CI SKIP] 2016-07-23 21:23:30 +08:00
Unknwon
024fcc836b Minor HTML fix for delete repository notice 2016-07-23 20:42:46 +08:00
Unknwon
250be011c7 Remove redundant Unix timestamp method call
Unix() already uses UTC as timezone
2016-07-23 20:24:44 +08:00
Unknwon
4e822c1911 conf: change default mirror checking interval to 10m 2016-07-23 20:20:09 +08:00
Unknwon
26d52ceb48 #3186 fix wrong link for new pull request button of non-fork repository 2016-07-23 19:55:53 +08:00
Unknwon
d90acacd86 Update README [CI SKIP] 2016-07-23 19:22:43 +08:00
Unknwon
69f5308761 #2903 use different reversed words and patterns for repository and user 2016-07-23 18:58:18 +08:00
Unknwon
4b5e09e4d6 #3181 detect situation when base branch is deleted in pull request 2016-07-23 18:35:16 +08:00
Unknwon
4f78abe7dc #3066 fix create organization ignores full name property 2016-07-23 17:57:22 +08:00
Unknwon
e63b2881b1 api: fix panic if anonymous user request admin API
Add sign in check before check user account level
2016-07-23 17:56:37 +08:00
Unknwon
745167d57a #3157 create user path before rename repository while transfer
os.Rename does not create parent directory automatically when not exist
2016-07-23 17:36:15 +08:00
Unknwon
d7bdc1de8d #3107 fix mention regex does not include dash 2016-07-23 17:29:34 +08:00
Unknwon
c912494609 #3076 detect invalid tag name git error 2016-07-23 15:59:19 +08:00
Richard Mahn
69dae1ec1c Added coding style modes to SimpleMDE (#3286)
* Added coding style modes to SimpleMDE

* Moved the CodeMirror addon from simplemd to codemirror directory
2016-07-23 13:29:20 +08:00
Siarhei Navatski
cf85e9eb7b add IsSubmodule field to DiffFile and hide view file button on diff page for submodules (#3097) 2016-07-23 02:18:56 +08:00
Unknwon
599716bb1b Update locales [CI SKIP] 2016-07-22 22:21:26 +08:00
Unknwon
ae88d76032 Bump version 2016-07-22 21:52:39 +08:00
Unknwon
9266f28822 Fix GitHub wrong repo language detection 2016-07-21 18:20:03 +08:00
Dennis Chen
6488ee12be avatar: make custom and generated avatars equal (#3301)
Sets all avatars to use PNG image format.
Keeps avatars consistent at 290x290px resolution.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2016-07-21 15:31:14 +08:00
Unknwon
c2fb01a257 #3299 don’t pop up confirm box when leave on signin page 2016-07-21 14:36:26 +08:00
Unknwon
5761342f32 #3291 fix SQLite3 session read/update conflict on create new issue 2016-07-21 14:26:30 +08:00
Unknwon
57af7432fc #3295 fix wrong logic judgement 2016-07-21 14:15:04 +08:00
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
669 changed files with 128124 additions and 6084 deletions

6
.codebeatignore Normal file
View File

@@ -0,0 +1,6 @@
conf/**
docker/**
public/**
packager/**
scripts/**
templates/**

7
.codebeatsettings Normal file
View File

@@ -0,0 +1,7 @@
{
"GOLANG": {
"TOTAL_LOC": [500, 999, 1999, 9999],
"TOO_MANY_FUNCTIONS": [50, 99, 199, 999],
"TOO_MANY_IVARS": [20, 50, 70, 99]
}
}

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

11
.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
public/conf/gitignore/* linguist-vendored
public/conf/license/* linguist-vendored
public/assets/* linguist-vendored
public/plugins/* linguist-vendored
public/plugins/* linguist-vendored
public/css/themes/* linguist-vendored
public/css/github.min.css linguist-vendored
public/css/semantic-2.2.1.min.css linguist-vendored
public/js/libs/* linguist-vendored
public/js/jquery-1.11.3.min.js linguist-vendored
public/js/semantic-2.2.1.min.js linguist-vendored

View File

@@ -46,7 +46,7 @@ Please read detailed information on [Wiki](https://github.com/gogits/gogs/wiki/C
### Ask For Help
Before opening an issue, please make sure your problem isn't already addressed on the [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
Before opening an issue, please make sure your problem isn't already addressed on the [Troubleshooting](https://gogs.io/docs/intro/troubleshooting.html) and [FAQs](https://gogs.io/docs/intro/faqs.html) pages.
## Code of conduct

View File

@@ -1,18 +1,21 @@
We DO NOT take questions or config/deploy problems on GitHub, please use our forum: https://discuss.gogs.io
The issue will be closed without any reasons if it does not satisfy any of following requirements:
Please take a moment to search that an issue doesn't already exist.
1. Please speak English, we have forum in [Chinese](https://discuss.gogs.io/c/getting-help/getting-help-chinese).
2. Please post questions or config/deploy problems on our forum: https://discuss.gogs.io, here are bugs and feature requests only.
3. Please take a moment to search that an issue doesn't already exist.
4. Please give all relevant information below for bug reports; incomplete details considered invalid report.
For bug reports, please give the relevant info:
**You MUST delete above content including this line before posting; too lazy to take this action considered invalid report.**
- Gogs version (or commit ref):
- Git version:
- Operating system:
- Database:
- Gogs version (or commit ref):
- Git version:
- Operating system:
- Database (use `[x]`):
- [ ] PostgreSQL
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at http://try.gogs.io:
- [ ] Yes
- Can you reproduce the bug at https://try.gogs.io:
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant
- Log gist:

View File

@@ -1,4 +1,9 @@
Please, make sure you are targeting the `develop` branch!
The pull request will be closed without any reasons if it does not satisfy any of following requirements:
More instructions about contributing with Gogs code can be found here:
1. Please make sure you are targeting the `develop` branch.
2. Please read contributing guidelines:
https://github.com/gogits/gogs/wiki/Contributing-Code
3. Please describe what your pull request does and which issue you're targeting
4. ... if it is not related to any particular issues, explain why we should not reject your pull request.
**You MUST delete above content including this line before posting; too lazy to take this action considered invalid pull request.**

1
.gitignore vendored
View File

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

View File

@@ -3,51 +3,56 @@ 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:0b58b37
github.com/go-xorm/core = commit:5bf745d
github.com/go-xorm/xorm = commit:c6c7056
github.com/gogits/chardet = commit:2404f77
github.com/gogits/cron = commit:7f3990a
github.com/gogits/git-module = commit:18dd87d
github.com/gogits/go-gogs-client = commit:d1020b4
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:80f8150
github.com/mattn/go-sqlite3 = commit:e118d44
github.com/mcuadros/go-version = commit:d52711f
github.com/microcosm-cc/bluemonday = commit:4ac6f27
github.com/microcosm-cc/bluemonday = commit:9dc1992
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/nfnt/resize = commit:891127d
github.com/russross/blackfriday = commit:93622da
github.com/satori/go.uuid = commit:0aa62d5
github.com/sergi/go-diff = commit:ec7fdbb
github.com/strk/go-libravatar = commit:5eed7bf
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:bc89c49
golang.org/x/net = commit:57bfaa8
golang.org/x/sys = commit:a646d33
golang.org/x/text = commit:2910a50
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:cf53f92
gopkg.in/ldap.v2 = commit:d0a5ced
gopkg.in/macaron.v1 = commit:7564489
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

@@ -1,4 +1,4 @@
Copyright (c) 2014 All Gogs Contributors
Copyright (c) The Gogs Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -6,24 +6,31 @@ 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"
NOW = $(shell date -u '+%Y%m%d%I%M%S')
GOVET = go tool vet -composites=false -methods=false -structtags=false
.PHONY: build pack release bindata clean
.IGNORE: public/css/gogs.css
govet:
$(GOVET) gogs.go
$(GOVET) models modules routers
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) -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
build-dev-race: $(GENERATED) govet
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.71 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
| Web | UI | Preview |
|:-------------:|:-------:|:-------:|
@@ -18,7 +18,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
3. The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
4. If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
5. If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
6. If your team/company is using Gogs and would like to put your logo on [our website](http://gogs.io), contact us by any means.
6. If your team/company is using Gogs and would like to put your logo on [our website](https://gogs.io), contact us by any means.
[简体中文](README_ZH.md)
@@ -28,11 +28,11 @@ The goal of this project is to make the easiest, fastest, and most painless way
## Overview
- Please see the [Documentation](http://gogs.io/docs/intro) for common usages and change log.
- Please see the [Documentation](https://gogs.io/docs/intro) for common usages and change log.
- See the [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs)!
- Having trouble? Get help with [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html) or [User Forum](https://discuss.gogs.io/).
- Want to help with localization? Check out the [guide](http://gogs.io/docs/features/i18n.html)!
- Having trouble? Get help with [Troubleshooting](https://gogs.io/docs/intro/troubleshooting.html) or [User Forum](https://discuss.gogs.io/).
- Want to help with localization? Check out the [guide](https://gogs.io/docs/features/i18n.html)!
## Features
@@ -45,11 +45,11 @@ The goal of this project is to make the easiest, fastest, and most painless way
- Repository Git hooks/deploy keys
- Repository issues, pull requests and wiki
- Add/Remove repository collaborators
- Gravatar and custom source
- Gravatar and Federated avatar with custom source
- 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
@@ -63,13 +63,13 @@ The goal of this project is to make the easiest, fastest, and most painless way
## Installation
Make sure you install the [prerequisites](http://gogs.io/docs/installation) first.
Make sure you install the [prerequisites](https://gogs.io/docs/installation) first.
There are 5 ways to install Gogs:
- [Install from binary](http://gogs.io/docs/installation/install_from_binary.html)
- [Install from source](http://gogs.io/docs/installation/install_from_source.html)
- [Install from packages](http://gogs.io/docs/installation/install_from_packages.html)
- [Install from binary](https://gogs.io/docs/installation/install_from_binary.html)
- [Install from source](https://gogs.io/docs/installation/install_from_source.html)
- [Install from packages](https://gogs.io/docs/installation/install_from_packages.html)
- [Ship with Docker](https://github.com/gogits/gogs/tree/master/docker)
- [Install with Vagrant](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
@@ -77,6 +77,8 @@ There are 5 ways to install Gogs:
- [How To Set Up Gogs on Ubuntu 14.04](https://www.digitalocean.com/community/tutorials/how-to-set-up-gogs-on-ubuntu-14-04)
- [Run your own GitHub-like service with the help of Docker](http://blog.hypriot.com/post/run-your-own-github-like-service-with-docker/)
- [Dockerized Gogs git server and alpine postgres in 20 minutes or less](http://garthwaite.org/docker-gogs.html)
- [Host Your Own Private GitHub with Gogs.io](https://eladnava.com/host-your-own-private-github-with-gogs-io/)
- [使用 Gogs 搭建自己的 Git 服务器](https://mynook.info/blog/post/host-your-own-git-server-using-gogs) (Chinese)
- [阿里云上 Ubuntu 14.04 64 位安装 Gogs](http://my.oschina.net/luyao/blog/375654) (Chinese)
- [Installing Gogs on FreeBSD](https://www.codejam.info/2015/03/installing-gogs-on-freebsd.html)
@@ -85,6 +87,7 @@ There are 5 ways to install Gogs:
### Screencasts
- [How to install Gogs on a Linux Server (DigitalOcean)](https://www.youtube.com/watch?v=deSfX0gqefE)
- [Instalando Gogs no Ubuntu](https://www.youtube.com/watch?v=4UkHAR1F7ZA) (Português)
### Deploy to Cloud
@@ -96,6 +99,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 +109,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
@@ -118,7 +123,7 @@ There are 5 ways to install Gogs:
- Thanks [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
- Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan.
- Thanks [DigitalOcean](https://www.digitalocean.com) for hosting home and demo sites.
- Thanks [KeyCDN](https://www.keycdn.com/) for providing CDN service.
- Thanks [KeyCDN](https://www.keycdn.com/) and [QiNiu](http://www.qiniu.com/) for providing CDN service.
## Contributors

View File

@@ -9,11 +9,11 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 项目概览
- 有关基本用法和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
- 有关基本用法和变更日志,请通过 [使用手册](https://gogs.io/docs/intro/) 查看。
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
- 想要先睹为快?直接去 [在线体验](https://try.gogs.io/gogs/gogs) 。
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](http://gogs.io/docs/features/i18n.html)
- 使用过程中遇到问题?尝试从 [故障排查](https://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](https://gogs.io/docs/features/i18n.html)
## 功能特性
@@ -26,11 +26,11 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 支持仓库 Git 钩子和部署密钥
- 支持仓库工单Issue、合并请求Pull Request以及 Wiki
- 支持添加和删除仓库协作者
- 支持 Gravatar 以及自定义源
- 支持自定义源的 Gravatar 和 Federated Avatar
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([15 种语言]([more](https://crowdin.com/project/gogs))
- 支持多语言本地化([18 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求
@@ -44,13 +44,13 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 安装部署
在安装 Gogs 之前,您需要先安装 [基本环境](http://gogs.io/docs/installation)。
在安装 Gogs 之前,您需要先安装 [基本环境](https://gogs.io/docs/installation)。
然后,您可以通过以下 5 种方式来安装 Gogs
- [二进制安装](http://gogs.io/docs/installation/install_from_binary.html)
- [源码安装](http://gogs.io/docs/installation/install_from_source.html)
- [包管理安装](http://gogs.io/docs/installation/install_from_packages.html)
- [二进制安装](https://gogs.io/docs/installation/install_from_binary.html)
- [源码安装](https://gogs.io/docs/installation/install_from_source.html)
- [包管理安装](https://gogs.io/docs/installation/install_from_packages.html)
- [采用 Docker 部署](https://github.com/gogits/gogs/tree/master/docker)
- [通过 Vagrant 安装](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/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/)(团队交流)
### 产品支持
@@ -90,7 +92,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 提供 CDN 服务赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 和 [七牛云存储](http://www.qiniu.com/) 提供 CDN 服务赞助。
## 贡献成员

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

@@ -103,7 +103,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
RefName: task.RefName,
OldCommitID: task.OldCommitID,
NewCommitID: task.NewCommitID,
PusherID: user.Id,
PusherID: user.ID,
PusherName: user.Name,
RepoUserName: repoUser.Name,
RepoName: reponame,
@@ -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)
@@ -175,7 +175,7 @@ func runServ(c *cli.Context) {
fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
}
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
if err != nil {
if models.IsErrRepoNotExist(err) {
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, reponame)
@@ -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.7"},
{"github.com/gogits/git-module", git.Version, "0.3.4"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.10.3"},
}
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)
@@ -217,7 +226,8 @@ func runWeb(ctx *cli.Context) {
m.Group("/user/settings", func() {
m.Get("", user.Settings)
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), user.SettingsAvatar)
m.Combo("/avatar").Get(user.SettingsAvatar).
Post(binding.MultipartForm(auth.AvatarForm{}), user.SettingsAvatarPost)
m.Post("/avatar/delete", user.SettingsDeleteAvatar)
m.Combo("/email").Get(user.SettingsEmails).
Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
@@ -231,7 +241,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 +256,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 +305,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 +342,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 +357,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)
@@ -366,7 +376,7 @@ func runWeb(ctx *cli.Context) {
m.Group("/settings", func() {
m.Combo("").Get(org.Settings).
Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), org.SettingsAvatar)
m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), org.SettingsAvatar)
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
m.Group("/hooks", func() {
@@ -384,7 +394,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 +433,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,22 +442,24 @@ 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() {
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
// So they can apply their own enable/disable logic on routers.
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)
m.Group("/:index", func() {
m.Post("/label", repo.UpdateIssueLabel)
m.Post("/milestone", repo.UpdateIssueMilestone)
m.Post("/assignee", repo.UpdateIssueAssignee)
m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
}, reqRepoWriter)
m.Group("/:index", func() {
@@ -455,12 +467,15 @@ func runWeb(ctx *cli.Context) {
m.Post("/content", repo.UpdateIssueContent)
})
})
m.Post("/comments/:id", repo.UpdateCommentContent)
m.Group("/comments/:id", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
})
m.Group("/labels", func() {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
}, reqRepoWriter, middleware.RepoRef())
}, repo.MustEnableIssues, reqRepoWriter, context.RepoRef())
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
@@ -468,7 +483,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())
}, repo.MustEnableIssues, reqRepoWriter, context.RepoRef())
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
@@ -476,11 +491,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 +504,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 +519,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 +533,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 +558,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 +598,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
@@ -42,6 +44,10 @@ NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[ui.user]
; Number of repos that are showed in one page
REPO_PAGING_NUM = 15
[markdown]
; Enable hard line break extension
ENABLE_HARD_LINE_BREAK = false
@@ -53,12 +59,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 +76,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 +99,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 +173,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 +205,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
@@ -219,7 +229,12 @@ AVATAR_UPLOAD_PATH = data/avatars
; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar
; This value will be forced to be true in offline mode.
DISABLE_GRAVATAR = false
; Federated avatar lookup uses DNS to discover avatar associated
; with emails, see http://www.libravatar.org
; This value will be forced to be false in offline mode or Gravatar is disbaled.
ENABLE_FEDERATED_AVATAR = false
[attachment]
; Whether attachments are enabled. Defaults to `true`
@@ -308,7 +323,7 @@ RUN_AT_START = false
; Update mirrors
[cron.update_mirrors]
SCHEDULE = @every 1h
SCHEDULE = @every 10m
; Repository health check
[cron.repo_health_check]
@@ -316,7 +331,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 +339,17 @@ RUN_AT_START = true
SCHEDULE = @every 24h
[git]
MAX_GIT_DIFF_LINES = 10000
; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false
; 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]
@@ -335,16 +357,26 @@ MIGRATE = 600
MIRROR = 300
CLONE = 300
PULL = 300
GC = 60
[mirror]
; Default interval in hours between each check
DEFAULT_INTERVAL = 24
[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 +389,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,21 @@ 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>
Joubert RedRat <me+github AT redrat DOT com DOT br>
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 +48,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 +59,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>

72
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=Стъпки за инсталиране при първоначално стартиране
@@ -103,6 +96,8 @@ offline_mode=Включи офлайн режима
offline_mode_popup=Изключи CDN дори в продукционен режим, всички ресурсни файлове ще бъдат доставяни локално.
disable_gravatar=Изключи връзка с Gravatar
disable_gravatar_popup=Изключва Gravatar и външни източници, така че всички аватари трябва да са или качени от потребителите или да се ползват аватари по подразбиране.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Изключи саморегистрацията
disable_registration_popup=Изключи потребителската саморегистрация, само администратор може да създава профили.
enable_captcha=Включи Captcha
@@ -131,6 +126,7 @@ uname_holder=Име или ел. поща
password_holder=Парола
switch_dashboard_context=Превключи контекст на таблото
my_repos=Моите хранилища
show_more_repos=Покажи още хранилища...
collaborative_repos=Съвместни хранилища
my_orgs=Моите организации
my_mirrors=Моите огледала
@@ -140,6 +136,8 @@ issues.in_your_repos=Във Вашите хранилища
[explore]
repos=Хранилища
users=Потребители
search=Търсене
[auth]
create_new_account=Създай нов профил
@@ -153,6 +151,8 @@ forget_password=Забравена парола?
sign_up_now=Нуждаете се от профил? Регистрирайте се сега.
confirmation_mail_sent_prompt=Ново писмо за потвърждение е изпратено до <b>%s</b>. Моля проверете пощенската си кутия в рамките на следващите %d часа, за да завършите процеса на регистрация.
active_your_account=Активиране на профил
prohibit_login=Влизане забранено
prohibit_login_desc=Вашият профил е със забрана за влизане, моля свържете се с администратора.
resent_limit_prompt=За съжаление Вие съвсем наскоро изпратихте писмо за активация. Моля изчакайте 3 минути, след което опитайте отново.
has_unconfirmed_mail=Здравейте %s, имате непотвърден адрес на ел. поща (<b>%s</b>). Ако не сте получили писмо за потвърждение или имате нужда да се изпрати ново писмо, моля щракнете бутона по-долу.
resend_mail=Щракнете тук, за да се изпрати ново писмо за потвърждение
@@ -162,6 +162,7 @@ reset_password=Нулиране на паролата
invalid_code=За съжаление Вашия код за потвърждение е изтекъл или е невалиден.
reset_password_helper=Щракнете тук, за да нулирате паролата си
password_too_short=Размерът на паролата не може да бъде по-малък от 6 знака.
non_local_account=Нелокални потребители не могат да сменят паролата си през Gogs.
[mail]
activate_account=Моля активирайте Вашия профил
@@ -224,8 +225,7 @@ org_still_own_repo=Тази организация все още притежа
target_branch_not_exist=Целевият клон не съществува.
[user]
change_avatar=Сменете Вашия аватар на gravatar.com
change_custom_avatar=Сменете Вашия аватар в настройките
change_avatar=Проми своя аватар
join_on=Регистриран
repositories=Хранилища
activity=Публична дейност
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Потребителското име '%s' не е
[settings]
profile=Профил
password=Парола
avatar=Avatar
ssh_keys=SSH ключове
social=Социални профили
applications=Приложения
@@ -261,6 +262,8 @@ change_username_prompt=Този промяна ще засегне всички
continue=Продължи
cancel=Отказ
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Разреши потребителски аватар
choose_new_avatar=Избор на нов аватар
update_avatar=Запази настройките на аватара
@@ -347,7 +350,7 @@ fork_from=Разклонение от
fork_visiblity_helper=Не може да променяте видимостта на разклонено хранилище.
repo_desc=Описание
repo_lang=Програмен език
repo_lang_helper=Изберете .gitignore файлове
repo_gitignore_helper=Select .gitignore templates
license=Лиценз
license_helper=Изберете лицензионен файл
readme=Readme
@@ -355,6 +358,8 @@ readme_helper=Изберете шаблон на readme
auto_init=Инициализиране на това хранилище с избраните файлове и шаблон
create_repo=Създай хранилище
default_branch=Клон по подразбиране
mirror_prune=Окастряне
mirror_prune_desc=Премахва всички препратки за отдалечено проследяване, които не съществуват отдалечено
mirror_interval=Интервал на отразяване (часове)
mirror_address=Адрес на огледало
mirror_address_desc=Моля включете потребител и парола в адреса ако са нужни.
@@ -412,6 +417,7 @@ file_raw=Директен файл
file_history=История
file_view_raw=Виж директен файл
file_permalink=Постоянна връзка
file_too_large=Този файл е твърде голям за да се визуализира
commits.commits=Ревизии
commits.search=Търсене в ревизии
@@ -465,7 +471,8 @@ issues.next=Следваща
issues.open_title=Отворени
issues.closed_title=Затворени
issues.num_comments=%d коментара
issues.commented_at=`коментира <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`коментира <a href="#%s">%s</a>`
issues.delete_comment_confirm=Желаете ли да изтриете този коментар?
issues.no_content=Все още няма съдържание.
issues.close_issue=Затвори
issues.close_comment_issue=Kоментирай и затвори
@@ -566,6 +573,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=Основни настройки
@@ -573,13 +584,18 @@ settings.site=Официален сайт
settings.update_settings=Запази настройките
settings.change_reponame_prompt=Тази промяна ще засегне връзките, които се отнасят до това хранилището.
settings.advanced_settings=Разширени настройки
settings.wiki_desc=Включва уики за да може потребителите да създават документи
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Използвай външно уики
settings.external_wiki_url=URL адрес на външно уики
settings.external_wiki_url_desc=Посетителите ще бъдат пренасочени към този URL адрес от връзката за раздел уики.
settings.issues_desc=Включва вградена система за проследяване на задачи
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи
settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи
settings.tracker_issue_style=Стил на именуване на външна система за проследяване на задачи:
settings.tracker_issue_style.numeric=Цифров
settings.tracker_issue_style.alphanumeric=Символен
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
settings.danger_zone=Опасна зона
@@ -602,9 +618,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 +702,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_suppressed=Файловите разлики са ограничени, защото са твърде много
diff.too_many_files=Някои файлове не бяха показани, защото твърде много файлове са промени
release.releases=Версии
release.new_release=Нова версия
@@ -718,6 +734,7 @@ release.deletion=Изтрий версията
release.deletion_desc=При изтриване на тази версия ще се премахне и съответния Git маркер. Желаете ли да продължите?
release.deletion_success=Версията беше изтрита успешно!
release.tag_name_already_exist=Версия с това име на маркер вече съществува.
release.tag_name_invalid=Името на етикета е невалидно.
release.downloads=Изтегляния
[org]
@@ -885,6 +902,7 @@ users.edit_account=Редактирай профил
users.max_repo_creation=Макс. брой хранилища
users.max_repo_creation_desc=(Задайте -1 за да се използва глобалния лимит)
users.is_activated=Този профил е активиран
users.prohibit_login=Този профил има забрана за влизане
users.is_admin=Този профил има административни права
users.allow_git_hook=Този профил има разрешение да създава Git куки
users.allow_import_local=Този профил има права за импорт на локални хранилища
@@ -915,6 +933,7 @@ auths.enabled=Активно
auths.updated=Последна модификация
auths.auth_type=Тип на удостоверяване
auths.auth_name=Име на удостоверяване
auths.security_protocol=Протокол за защита
auths.domain=Домейн
auths.host=Сървър
auths.port=Порт
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL режим
config.db_ssl_mode_helper=(само за postgres)
config.db_path=Път
config.db_path_helper=(за "sqlite3" и "tidb")
config.service_config=Настройка на услугата
config.register_email_confirm=Изисквай потвърждение на адреси на ел. поща
config.disable_register=Изключи нови регистрации
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Изключи проверка минимален
config.enable_captcha=Включи Captcha
config.active_code_lives=Кодове за активиране
config.reset_password_code_lives=Кодове за изчистване на парола
config.webhook_config=Конфигурация на уеб-куки
config.queue_length=Дължина на опашка
config.deliver_timeout=Време за отказ при изпращане
config.skip_tls_verify=Пропусни проверка на TLS
config.mailer_config=Конфигурация на мейлър
config.mailer_enabled=Активен
config.mailer_disable_helo=Изключи HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Потребител
config.send_test_mail=Изпрати тестово писмо
config.test_mail_failed=Невъзможно изпращане на тестово писмо до '%s': %v
config.test_mail_sent=Тестово писмо беше изпратено до '%s'.
config.oauth_config=OAuth конфигурация
config.oauth_enabled=Активна
config.cache_config=Конфигурация на кеша
config.cache_adapter=Кеш адаптер
config.cache_interval=Кеш интервал
config.cache_conn=Кеш на връзката
config.session_config=Конфигурация на сесии
config.session_provider=Доставчик на сесии
config.provider_config=Конфигурация на доставчик
@@ -1027,9 +1052,24 @@ config.gc_interval_time=GC през интервал
config.session_life_time=Период на валидност на сесиите
config.https_only=HTTPS само
config.cookie_life_time=Период на валидност на бисквитките
config.picture_config=Конфигурация на изображения
config.picture_service=Услуги за снимки
config.disable_gravatar=Изключи Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Конфигурация на журнал
config.log_mode=Режим на журнал

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

File diff suppressed because it is too large Load Diff

268
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
@@ -103,6 +96,8 @@ offline_mode=Offline-Modus aktivieren
offline_mode_popup=CDN auch im Produktivmodus deaktivieren. Alle Dateien werden von diesem Server ausgeliefert.
disable_gravatar=Gravatar-Dienst deaktivieren
disable_gravatar_popup=Gravatar und benutzerdefinierte Quellen deaktivieren. Alle Profilbilder werden vom Nutzer hochgeladen oder sind das Standard-Profilbild.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Registrierung deaktivieren
disable_registration_popup=Registrierung neuer Benutzer deaktivieren. Nur Administratoren können Benutzerkonten anlegen.
enable_captcha=Captcha aktivieren
@@ -110,7 +105,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 +113,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
@@ -131,6 +126,7 @@ uname_holder=Benutzername oder E-Mail
password_holder=Passwort
switch_dashboard_context=Kontext der Übersichtsseite wechseln
my_repos=Meine Repositories
show_more_repos=Zeige mehr Repositories...
collaborative_repos=Gemeinschaftliche Repositories
my_orgs=Meine Organisationen
my_mirrors=Meine Mirrors
@@ -140,10 +136,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.
@@ -153,6 +151,8 @@ forget_password=Passwort vergessen?
sign_up_now=Benötigen Sie ein Konto? Registrieren Sie sich jetzt.
confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an <b>%s</b> gesendet. Bitte kontrollieren Sie Ihr Postfach innerhalb der nächsten %d Stunden, um die Registrierung abzuschließen.
active_your_account=Aktivieren Sie Ihr Konto
prohibit_login=Anmelden verboten
prohibit_login_desc=Ihrem Konto ist es nicht gestattet sich anzumelden. Bitte kontaktieren Sie den Administrator.
resent_limit_prompt=Es tut uns leid, aber Sie haben bereits eine Aktivierungs-E-Mail angefordert. Bitte warten Sie 3 Minuten und probieren Sie es dann nochmal.
has_unconfirmed_mail=Hallo %s, Sie haben eine unbestätigte E-Mail-Adresse (<b>%s</b>). Wenn Sie keine Bestätigungs-E-Mail erhalten haben oder eine neue benötigen, klicken Sie bitte auf den folgenden Button.
resend_mail=Hier klicken, um die Aktivierungs-E-Mail erneut zu versenden
@@ -162,6 +162,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 +186,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 +214,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Benutzernamen der Form '%s' sind nicht erlaubt.
[settings]
profile=Profil
password=Passwort
avatar=Avatar
ssh_keys=SSH-Schlüssel
social=Soziale Konten
applications=Anwendungen
@@ -250,23 +251,25 @@ 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
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Benutzerdefiniertes Profilbild aktivieren
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 +281,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 +296,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 +318,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 +326,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 +334,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 +350,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_gitignore_helper=Select .gitignore templates
license=Lizenz
license_helper=Wählen Sie eine Lizenz aus
readme=Readme
@@ -355,6 +358,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 +369,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 +382,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 +399,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,10 +413,11 @@ 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
file_too_large=Diese Datei ist zu groß zum Anzeigen
commits.commits=Commits
commits.search=Commits durchsuchen
@@ -448,9 +454,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
@@ -465,7 +471,8 @@ issues.next=Nächste
issues.open_title=Offen
issues.closed_title=Geschlossen
issues.num_comments=%d Kommentare
issues.commented_at=`hat <a id="%[1]s" href="#%[1]s">%[2]s</a> kommentiert`
issues.commented_at=`kommentierte <a href="#%s">%s</a>`
issues.delete_comment_confirm=Sind Sie sich sicher, dass Sie diesen Kommentar löschen wollen?
issues.no_content=Hier gibt es bis jetzt noch keinen Inhalt.
issues.close_issue=Schließen
issues.close_comment_issue=Kommentieren und schließen
@@ -474,7 +481,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 +517,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 +535,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 +554,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 +565,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 +573,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 +584,18 @@ 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=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
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.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumerisch
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 +606,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 +626,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 +635,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 +653,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 +681,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 +689,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 +699,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_suppressed=Datei-Diff unterdrückt, da er 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 +713,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
@@ -718,6 +734,7 @@ release.deletion=Release löschen
release.deletion_desc=Beim Löschen dieses Releases wird das entsprechende Git-Tag gelöscht. Möchten Sie fortfahren?
release.deletion_success=Release wurde erfolgreich gelöscht!
release.tag_name_already_exist=Ein Release mit diesem Tag existiert bereits.
release.tag_name_invalid=Tag-Name ist nicht gültig.
release.downloads=Downloads
[org]
@@ -791,7 +808,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 +823,7 @@ organizations=Organisationen
repositories=Repositories
authentication=Authentifizierung
config=Konfiguration
notices=System-Mitteilungen
notices=Systemmitteilungen
monitor=Monitoring
first_page=Erste
last_page=Letzte
@@ -829,8 +846,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 +878,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,23 +889,24 @@ 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
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.prohibit_login=Diesem Konto ist es nicht gestattet sich anzumelden
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 +933,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 +942,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 +962,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 +989,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 +1006,10 @@ 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 +1019,13 @@ 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 +1034,43 @@ 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.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Konfiguration des Loggings
config.log_mode=Log-Modus
monitor.cron=Cron-Tasks
@@ -1044,7 +1084,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 +1099,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 +1136,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
@@ -103,6 +96,8 @@ offline_mode = Enable Offline Mode
offline_mode_popup = Disable CDN even in production mode, all resource files will be served locally.
disable_gravatar = Disable Gravatar Service
disable_gravatar_popup = Disable Gravatar and custom sources, all avatars are uploaded by users or default.
federated_avatar_lookup = Enable Federated Avatars Lookup
federated_avatar_lookup_popup = Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration = Disable Self-registration
disable_registration_popup = Disable user self-registration, only admin can create accounts.
enable_captcha = Enable Captcha
@@ -131,6 +126,7 @@ uname_holder = Username or email
password_holder = Password
switch_dashboard_context = Switch Dashboard Context
my_repos = My Repositories
show_more_repos = Show more repositories...
collaborative_repos = Collaborative Repositories
my_orgs = My Organizations
my_mirrors = My Mirrors
@@ -140,6 +136,8 @@ issues.in_your_repos = In your repositories
[explore]
repos = Repositories
users = Users
search = Search
[auth]
create_new_account = Create New Account
@@ -153,6 +151,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 +162,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
[settings]
profile = Profile
password = Password
avatar = Avatar
ssh_keys = SSH Keys
social = Social Accounts
applications = Applications
@@ -261,7 +262,9 @@ change_username_prompt = This change will affect the way how links relate to you
continue = Continue
cancel = Cancel
enable_custom_avatar = Enable Custom Avatar
lookup_avatar_by_mail = Lookup Avatar by mail
federated_avatar_lookup = Federated Avatar Lookup
enable_custom_avatar = Use Custom Avatar
choose_new_avatar = Choose new avatar
update_avatar = Update Avatar Setting
delete_current_avatar = Delete Current Avatar
@@ -347,7 +350,7 @@ fork_from = Fork From
fork_visiblity_helper = You cannot alter the visibility of a forked repository.
repo_desc = Description
repo_lang = Language
repo_lang_helper = Select .gitignore files
repo_gitignore_helper = Select .gitignore templates
license = License
license_helper = Select a license file
readme = Readme
@@ -355,6 +358,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 +417,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
@@ -465,7 +471,8 @@ issues.next = Next
issues.open_title = Open
issues.closed_title = Closed
issues.num_comments = %d comments
issues.commented_at = `commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at = `commented <a href="#%s">%s</a>`
issues.delete_comment_confirm = Are you sure you want to delete this comment?
issues.no_content = There is no content yet.
issues.close_issue = Close
issues.close_comment_issue = Comment and close
@@ -566,6 +573,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
@@ -573,13 +584,18 @@ settings.site = Official Site
settings.update_settings = Update Settings
settings.change_reponame_prompt = This change will affect how links relate to the repository.
settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable wiki to allow people write documents
settings.wiki_desc = Enable wiki system
settings.use_internal_wiki = Use builtin wiki
settings.use_external_wiki = Use external wiki
settings.external_wiki_url = External Wiki URL
settings.external_wiki_url_desc = Visitors will be redirected to URL when they click on the tab.
settings.issues_desc = Enable builtin lightweight issue tracker
settings.issues_desc = Enable issue tracker
settings.use_internal_issue_tracker = Use 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
settings.tracker_issue_style.alphanumeric = Alphanumeric
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 +618,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 +702,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
@@ -718,6 +734,7 @@ 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.tag_name_already_exist = Release with this tag name already exists.
release.tag_name_invalid = Tag name is not valid.
release.downloads = Downloads
[org]
@@ -885,6 +902,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 +933,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 +962,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode = SSL Mode
config.db_ssl_mode_helper = (for "postgres" only)
config.db_path = Path
config.db_path_helper = (for "sqlite3" and "tidb")
config.service_config = Service Configuration
config.register_email_confirm = Require Email Confirmation
config.disable_register = Disable Registration
@@ -999,10 +1019,12 @@ config.disable_key_size_check = Disable Minimum Key Size Check
config.enable_captcha = Enable Captcha
config.active_code_lives = Active Code Lives
config.reset_password_code_lives = Reset Password Code Lives
config.webhook_config = Webhook Configuration
config.queue_length = Queue Length
config.deliver_timeout = Deliver Timeout
config.skip_tls_verify = Skip TLS Verify
config.mailer_config = Mailer Configuration
config.mailer_enabled = Enabled
config.mailer_disable_helo = Disable HELO
@@ -1012,12 +1034,15 @@ config.mailer_user = 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.oauth_config = OAuth Configuration
config.oauth_enabled = Enabled
config.cache_config = Cache Configuration
config.cache_adapter = Cache Adapter
config.cache_interval = Cache Interval
config.cache_conn = Cache Connection
config.session_config = Session Configuration
config.session_provider = Session Provider
config.provider_config = Provider Config
@@ -1027,9 +1052,24 @@ config.gc_interval_time = GC Interval Time
config.session_life_time = Session Life Time
config.https_only = HTTPS Only
config.cookie_life_time = Cookie Life Time
config.picture_config = Picture Configuration
config.picture_service = Picture Service
config.disable_gravatar = Disable Gravatar
config.enable_federated_avatar = Enable Federated Avatars
config.git_config = Git Configuration
config.git_disable_diff_highlight = Disable Diff Syntax Highlight
config.git_max_diff_lines = Max Diff Lines (for a single file)
config.git_max_diff_line_characters = Max Diff Characters (for a single line)
config.git_max_diff_files = Max Diff Files (to be shown)
config.git_gc_args = GC Arguments
config.git_migrate_timeout = Migration Timeout
config.git_mirror_timeout = Mirror Update Timeout
config.git_clone_timeout = Clone Operation Timeout
config.git_pull_timeout = Pull Operation Timeout
config.git_gc_timeout = GC Operation Timeout
config.log_config = Log Configuration
config.log_mode = Log Mode

98
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.
@@ -103,6 +96,8 @@ offline_mode=Activar el modo Sin Conexión
offline_mode_popup=Desactivar el CDN incluso en el modo de producción, todos los recursos se servirán localmente.
disable_gravatar=Desactivar el servicio Gravatar
disable_gravatar_popup=Desactivar Gravatar y cualquier otra fuente personalizada. Todos los avatares deben ser cargados por los usuarios o en su defecto se mostrará el avatar predeterminado.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Desactivar Auto-Registro
disable_registration_popup=Desactivar auto-registro del usuario, solo el administrador podrá crear cuentas nuevas.
enable_captcha=Activar la Captcha
@@ -131,6 +126,7 @@ uname_holder=Nombre de usuario o correo electrónico
password_holder=Contraseña
switch_dashboard_context=Cambiar el contexto del Dashboard
my_repos=Mis repositorios
show_more_repos=Mostrar más repositorios...
collaborative_repos=Repositorios colaborativos
my_orgs=Mis organizaciones
my_mirrors=Mis réplicas
@@ -140,9 +136,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.
@@ -153,6 +151,8 @@ forget_password=¿Has olvidado tu contraseña?
sign_up_now=¿Necesitas una cuenta? Regístrate ahora.
confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a <b>%s</b>. Por favor, comprueba tu bandeja de entrada en las siguientes %d horas para completar el proceso de registro.
active_your_account=Activa tu cuenta
prohibit_login=Ingreso prohibido
prohibit_login_desc=Su cuenta tiene prohibido ingresar al sistema, fovor contactar al administrador del sistema.
resent_limit_prompt=Lo sentimos, estás solicitando el reenvío del mail de activación con demasiada frecuencia. Por favor, espera 3 minutos.
has_unconfirmed_mail=Hola %s, tu correo electrónico (<b>%s</b>) no está confirmado. Si no has recibido un correo de confirmación o necesitas que lo enviemos de nuevo, por favor, haz click en el siguiente botón.
resend_mail=Haz click aquí para reenviar tu correo electrónico de activación
@@ -162,6 +162,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 +225,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=Cambiar tu avatar
join_on=Registrado el
repositories=Repositorios
activity=Actividad pública
followers=Seguidores
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=El patrón de nombre de usuario '%s' no está perm
[settings]
profile=Perfil
password=Contraseña
avatar=Avatar
ssh_keys=Claves SSH
social=Redes Sociales
applications=Aplicaciones
@@ -261,6 +262,8 @@ change_username_prompt=Este cambio afectará a los enlaces que hacen referencia
continue=Continuar
cancel=Cancelar
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Activar avatar personalizado
choose_new_avatar=Selecciona nuevo avatar
update_avatar=Actualizar configuración del avatar
@@ -346,8 +349,8 @@ 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_helper=Seleccione archivo .gitignore
repo_lang=Idioma
repo_gitignore_helper=Select .gitignore templates
license=Licencia
license_helper=Selecciona un fichero de licencia
readme=Readme
@@ -355,6 +358,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=Purgar
mirror_prune_desc=Remover referencias remotas que no existan remotamente
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 +383,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
@@ -412,6 +417,7 @@ file_raw=Raw
file_history=Histórico
file_view_raw=Ver Raw
file_permalink=Permalink
file_too_large=Este archivo es demasiado grande para ser mostrado
commits.commits=Commits
commits.search=Buscar Commits
@@ -465,7 +471,8 @@ issues.next=Página Siguiente
issues.open_title=Abierta
issues.closed_title=Cerrada
issues.num_comments=%d comentarios
issues.commented_at=`comentada <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at='comentado <a href="#%s"> %s'</a>
issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario?
issues.no_content=Aún no existe contenido.
issues.close_issue=Cerrar
issues.close_comment_issue=Comentar y cerrar
@@ -496,7 +503,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 +573,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
@@ -573,13 +584,18 @@ settings.site=Sitio oficial
settings.update_settings=Actualizar configuración
settings.change_reponame_prompt=Este cambio afectará a los enlaces al repositorio.
settings.advanced_settings=Ajustes avanzados
settings.wiki_desc=Habilitar la Wiki para que los colaboradores documenten
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Usar Wiki externa
settings.external_wiki_url=URL externa de la Wiki
settings.external_wiki_url_desc=Los visitantes serán redireccionados a la URL cuando hagan click en la barra.
settings.issues_desc=Habilitar tracker ligero de incidencias
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alfanumérico
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 +618,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 +696,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_suppressed=La diferencia del archivo ha sido suprimido porque es demasiado grande
diff.too_many_files=Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio
release.releases=Releases
release.new_release=Nueva Release
@@ -705,7 +721,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.
@@ -718,6 +734,7 @@ release.deletion=Eliminar Release
release.deletion_desc=Eliminar este Release eliminará la etiqueta correspondiente. ¿Desea continuar?
release.deletion_success=¡El release ha sido eliminado correctamente!
release.tag_name_already_exist=Ya existe una Release con esta etiqueta.
release.tag_name_invalid=Nombre de la etiqueta no es válido.
release.downloads=Descargas
[org]
@@ -885,6 +902,7 @@ users.edit_account=Editar Cuenta
users.max_repo_creation=Límite máximo de repositorios
users.max_repo_creation_desc=(Configura a -1 para usar el límite global por defecto)
users.is_activated=Esta cuenta está activada
users.prohibit_login=Esta cuenta no tiene permitido ingresar
users.is_admin=Esta cuenta tiene permisos de administrador
users.allow_git_hook=Esta cuenta tiene permisos para crear hooks de Git
users.allow_import_local=Esta cuenta dispone de permisos para importar repositorios locales
@@ -915,6 +933,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=Modo SSL
config.db_ssl_mode_helper=(sólo para "postgres")
config.db_path=Ruta
config.db_path_helper=(para "sqlite3" y "tidb")
config.service_config=Configuración del servicio
config.register_email_confirm=Solicitar Confirmación por Correo Electrónico
config.disable_register=Deshabilitar el Registro
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo d
config.enable_captcha=Activar Captcha
config.active_code_lives=Habilitar Vida del Código
config.reset_password_code_lives=Restablecer Contraseña de Vida del Código
config.webhook_config=Configuración de Webhooks
config.queue_length=Tamaño de Cola de Envío
config.deliver_timeout=Timeout de Entrega
config.skip_tls_verify=Omitir la Verificación TLS
config.mailer_config=Configuración del servidor de correo
config.mailer_enabled=Activado
config.mailer_disable_helo=Desactivar HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Usuario
config.send_test_mail=Enviar email de prueba
config.test_mail_failed=Fallo al enviar el email de prueba a '%s': %v
config.test_mail_sent=El email de prueba ha sido enviado a '%s'.
config.oauth_config=Configuración OAuth
config.oauth_enabled=Activado
config.cache_config=Configuración de la Caché
config.cache_adapter=Adaptador de la Caché
config.cache_interval=Intervalo de la Caché
config.cache_conn=Conexión de la Caché
config.session_config=Configuración de la Sesión
config.session_provider=Proveedor de la Sesión
config.provider_config=Configuración del Proveedor
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Intervalo de tiempo del GC
config.session_life_time=Tiempo de Vida de la Sesión
config.https_only=Sólo HTTPS
config.cookie_life_time=Tiempo de Vida de la Cookie
config.picture_config=Configuración de Imagen
config.picture_service=Servicio de Imágen
config.disable_gravatar=Desactivar Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Configuración del Log
config.log_mode=Modo del Log

72
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
@@ -103,6 +96,8 @@ offline_mode=Ota käyttöön Offline tila
offline_mode_popup=Poista käytöstä CDN myös tuotanto tilassa, kaikki resurssi tiedostot palvellaan paikallisesti.
disable_gravatar=Poista käytöstä Gravatar palvelu
disable_gravatar_popup=Poista käytöstä Gravatar ja mukautetut lähteet, kaikki profiilikuvat on käyttäjien palvelimelle lähettämiä tai oletus.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Poista käytöstä itse-rekisteröinti
disable_registration_popup=Poista käyttäjän itse rekisteröinti, vain ylläpito voi luoda tilejä.
enable_captcha=Ota käyttöön Captcha
@@ -131,6 +126,7 @@ uname_holder=Käyttäjätunnus tai sähköposti
password_holder=Salasana
switch_dashboard_context=Vaihda kojelaudan kontekstia
my_repos=Reponi
show_more_repos=Show more repositories...
collaborative_repos=Yhteistyö repot
my_orgs=Organisaationi
my_mirrors=Peilini
@@ -140,6 +136,8 @@ issues.in_your_repos=Repoissasi
[explore]
repos=Repot
users=Users
search=Search
[auth]
create_new_account=Luo uusi tili
@@ -153,6 +151,8 @@ forget_password=Unohtuiko salasana?
sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt.
confirmation_mail_sent_prompt=Uusi varmistus sähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %d tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi.
active_your_account=Aktivoi tilisi
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Sori, olet jo tilannut aktivointi sähköpostin lähiaikoina. Ole hyvä ja odota 3 minuuttia ja yritä sitten uudelleen.
has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (<b>%s</b>). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta.
resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi
@@ -162,6 +162,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Käyttäjätunnus mallia '%s' ei ole sallittu.
[settings]
profile=Profiili
password=Salasana
avatar=Avatar
ssh_keys=SSH avaimet
social=Sosiaaliset tilit
applications=Sovellukset
@@ -261,6 +262,8 @@ change_username_prompt=Tämä muutos vaikuttaa tapaan kuinka linkit liittyvät t
continue=Jatka
cancel=Peruuta
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Ota käyttöön mukautettu profiilikuva
choose_new_avatar=Valitse uusi profiilikuva
update_avatar=Päivitä profiilikuva asetus
@@ -347,7 +350,7 @@ fork_from=Forkkaa lähteestä
fork_visiblity_helper=Et voi muuttaa forkatun repon näkyvyyttä.
repo_desc=Kuvaus
repo_lang=Kieli
repo_lang_helper=Valitse .gitignore tiedostot
repo_gitignore_helper=Select .gitignore templates
license=Lisenssi
license_helper=Valitse lisenssitiedosto
readme=Lueminut-tiedosto
@@ -355,6 +358,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.
@@ -412,6 +417,7 @@ file_raw=Raaka
file_history=Historia
file_view_raw=Näytä raaka
file_permalink=Pysyvä linkki
file_too_large=This file is too large to be shown
commits.commits=Commitit
commits.search=Etsi commiteista
@@ -465,7 +471,8 @@ issues.next=Seuraava
issues.open_title=Avoinna
issues.closed_title=Suljettu
issues.num_comments=%d kommenttia
issues.commented_at=`kommentoi <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Sisältöä ei vielä ole.
issues.close_issue=Sulje
issues.close_comment_issue=Kommentoi ja sulje
@@ -566,6 +573,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
@@ -573,13 +584,18 @@ settings.site=Virallinen sivusto
settings.update_settings=Päivitä asetukset
settings.change_reponame_prompt=Tämä muutos vaikuttaa siihen miten linkit liittyvät repoon.
settings.advanced_settings=Lisäasetukset
settings.wiki_desc=Ota käyttöön wiki salliaksesi ihmisten kirjoittaa asiakirjoja
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Käytä ulkoista wikiä
settings.external_wiki_url=Ulkoinen Wiki URL
settings.external_wiki_url_desc=Vierailijat uudelleenohjataan URL-osoitteeseen kun he klikkaavat välilehteä.
settings.issues_desc=Ota käyttöön sisäänrakennettu kevyt vikaseuranta
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumeric
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 +618,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 +702,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_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=Julkaisut
release.new_release=Uusi julkaisu
@@ -718,6 +734,7 @@ release.deletion=Version poisto
release.deletion_desc=Tämän version poistaminen poistaa vastaavan Git tagin. Haluatko jatkaa?
release.deletion_success=Versio on poistettu onnistuneesti!
release.tag_name_already_exist=Versio tällä taginimellä on jo olemassa.
release.tag_name_invalid=Tag name is not valid.
release.downloads=Lataukset
[org]
@@ -885,6 +902,7 @@ users.edit_account=Muokkaa tiliä
users.max_repo_creation=Maksimi repojen määrä jonka voi luoda
users.max_repo_creation_desc=(Aseta -1 käyttääksesi globaalia oletusrajaa)
users.is_activated=Tämä tili on aktivoitu
users.prohibit_login=This account is prohibited to login
users.is_admin=Tällä tilillä on ylläpito-oikeudet
users.allow_git_hook=Tällä tilillä on oikeudet luoda Git koukkuja
users.allow_import_local=Tällä tilillä on oikeudet tuoda paikallisia repoja
@@ -915,6 +933,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL tila
config.db_ssl_mode_helper=(vain "postgres")
config.db_path=Polku
config.db_path_helper=("sqlite3" ja "tidb")
config.service_config=Palvelu asetukset
config.register_email_confirm=Vaadi sähköpostivahvistus
config.disable_register=Poista käytöstä rekisteröinti
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Poista käytöstä avaimen vähimmäiskoko tarkist
config.enable_captcha=Ota käyttöön Captcha
config.active_code_lives=Aktiivinen koodi elämät ennen vanhenemista
config.reset_password_code_lives=Nollaa salasana koodi elämät
config.webhook_config=Webkoukku asetukset
config.queue_length=Jonon pituus
config.deliver_timeout=Toimitus aikakatkaisu
config.skip_tls_verify=Ohita TLS tarkistaminen
config.mailer_config=Sähköpostipalvelin asetukset
config.mailer_enabled=Käytössä
config.mailer_disable_helo=Poista käytöstä HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Käyttäjä
config.send_test_mail=Lähetä testi sähköposti
config.test_mail_failed=Testi sähköpostin lähettäminen vastaanottajalle '%s': %v epäonnistui
config.test_mail_sent=Testi sähköposti on lähetetty vastaanottajalle '%s'.
config.oauth_config=OAuth asetukset
config.oauth_enabled=Käytössä
config.cache_config=Välimuistin asetukset
config.cache_adapter=Välimuistin sovitin
config.cache_interval=Välimuistin aikaväli
config.cache_conn=Välimuistin yhteys merkkijono
config.session_config=Istunnon asetukset
config.session_provider=Istunnon toimittaja
config.provider_config=Toimittajan asetukset
@@ -1027,9 +1052,24 @@ config.gc_interval_time=GC aikaväli aika
config.session_life_time=Istunnon elinikä
config.https_only=Vain HTTPS
config.cookie_life_time=Evästeen elinikä
config.picture_config=Kuva asetukset
config.picture_service=Kuva palvelu
config.disable_gravatar=Poista käytöstä Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Loki asetukset
config.log_mode=Loki tila

160
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>.
@@ -103,11 +96,13 @@ offline_mode=Activer le mode hors connexion
offline_mode_popup=Désactiver le CDN, même en production. Toutes les ressources seront distribuées en local.
disable_gravatar=Désactiver le service Gravatar
disable_gravatar_popup=Désactiver Gravatar et les sources personnalisées, tous les avatars sont téléchargés par les utilisateurs ou par défaut.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
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 +122,22 @@ 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
show_more_repos=Afficher plus de 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 +146,13 @@ 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
prohibit_login=Connexion interdite
prohibit_login_desc=Votre compte est interdit de se connecter, contactez ladministrateur du site.
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 +162,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 +218,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
@@ -241,11 +241,12 @@ form.name_pattern_not_allowed=Motif '%s' interdit pour les noms d'utilisateur.
[settings]
profile=Profil
password=Mot de Passe
avatar=Avatar
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 +262,32 @@ change_username_prompt=Cette modification affectera la manière dont les liens s
continue=Continuer
cancel=Annuler
enable_custom_avatar=Activer l'Avatar personnalisé
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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 +338,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>
@@ -347,7 +350,7 @@ fork_from=Fork de
fork_visiblity_helper=La visibilité d'un fork ne peut pas être modifiée.
repo_desc=Description
repo_lang=Langue
repo_lang_helper=Sélectionnez les fichiers .gitignore
repo_gitignore_helper=Select .gitignore templates
license=Licence
license_helper=Sélectionner un fichier de licence
readme=Fichier Readme
@@ -355,6 +358,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=Supprimez toute référence de suivi à distance qui n'existe plus sur le dépôt distant
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 +382,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,13 +410,14 @@ tags=Tags
issues=Tickets
pulls=Pull Requests
labels=Etiquettes
milestones=Étapes
milestones=Jalons
commits=Commits
releases=Publications
file_raw=Raw
file_history=Historique
file_view_raw=Voir le Raw
file_permalink=Lien permanent
file_too_large=Ce fichier est trop gros pour être afficher
commits.commits=Commits
commits.search=Rechercher des commits
@@ -430,7 +436,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 +448,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é
@@ -465,7 +471,8 @@ issues.next=Page Suivante
issues.open_title=Ouvert
issues.closed_title=Fermé
issues.num_comments=%d commentaires
issues.commented_at=`commenté à <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.commented_at=`a commenté <a href="#%s"> %s</a>`
issues.delete_comment_confirm=Êtes-vous certain de vouloir supprimer ce commentaire?
issues.no_content=Il n'existe pas encore de contenu.
issues.close_issue=Fermer
issues.close_comment_issue=Commenter et fermer
@@ -476,7 +483,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 +564,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 +573,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
@@ -573,13 +584,18 @@ settings.site=Site officiel
settings.update_settings=Valider
settings.change_reponame_prompt=Ce changement affectera comment les liens sont reliés avec le dépôt.
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki pour permettre l'écriture de documents
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Utiliser un wiki externe
settings.external_wiki_url=URL Wiki externe
settings.external_wiki_url_desc=Les visiteurs seront redirigés vers cette URL lorsqu'ils cliqueront sur l'onglet.
settings.issues_desc=Activer le bug-tracker léger intégré
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Utiliser un bug-tracker externe
settings.tracker_url_format=Format d'URL du bug tracker
settings.tracker_issue_style=Style de nommage des bugs du tracker externe :
settings.tracker_issue_style.numeric=Numérique
settings.tracker_issue_style.alphanumeric=Alphanumérique
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 +607,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=-Tous les forks deviendront indépendants après leffacement.
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 +627,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 +702,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_suppressed=Fichier diff supprimé car celui-ci est trop grand
diff.too_many_files=Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff
release.releases=Versions
release.new_release=Nouvelle version
@@ -713,15 +729,16 @@ 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 !
release.tag_name_already_exist=Une version avec ce nom de tag existe déjà.
release.tag_name_invalid=Nom de tag invalide.
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 +748,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 +853,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
@@ -885,6 +902,7 @@ users.edit_account=Modifier le Compte
users.max_repo_creation=Nombre maximum de dépôts créés
users.max_repo_creation_desc=(Mettre à -1 pour utiliser la limite globale par défaut)
users.is_activated=Ce compte est activé
users.prohibit_login=Ce compte est interdit de se connecter
users.is_admin=Ce compte possède un niveau d'accès administrateur
users.allow_git_hook=Ce compte dispose des autorisations pour créer des crochets de Git
users.allow_import_local=Ce compte dispose des permissions nécessaire à l'import des dépôts locaux
@@ -915,6 +933,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 +969,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 +994,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=Mode SSL
config.db_ssl_mode_helper=("postgres" uniquement)
config.db_path=Emplacement
config.db_path_helper=(pour « sqlite3 » et « TIDB »)
config.service_config=Configuration du Service
config.register_email_confirm=Nécessite une confirmation par e-mail
config.disable_register=Désactiver les inscriptions
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Désactiver la vérification de la taille de clé
config.enable_captcha=Activez le Captcha
config.active_code_lives=Limites de Code Actif
config.reset_password_code_lives=Réinitialiser le Mot De Passe des Limites de Code
config.webhook_config=Configuration Webhook
config.queue_length=Longueur de la file d'attente
config.deliver_timeout=Expiration d'Envoi
config.skip_tls_verify=Ne pas vérifier TLS
config.mailer_config=Configuration du service de mail
config.mailer_enabled=Activé
config.mailer_disable_helo=Désactiver HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Utilisateur
config.send_test_mail=Envoyer courriel de Test
config.test_mail_failed=Impossible d'envoyer un e-mail de test à '%s': %v
config.test_mail_sent=Un e-mail de test à été envoyé à '%s'.
config.oauth_config=Configuration OAuth
config.oauth_enabled=Activé
config.cache_config=Configuration du Cache
config.cache_adapter=Adaptateur du Cache
config.cache_interval=Intervales du Cache
config.cache_conn=Liaison du Cache
config.session_config=Configuration de session
config.session_provider=Fournisseur de session
config.provider_config=Configuration du fournisseur
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Intervals GC
config.session_life_time=Durée des sessions
config.https_only=HTTPS uniquement
config.cookie_life_time=Expiration du cookie
config.picture_config=Configuration d'Image
config.picture_service=Service d'Imagerie
config.disable_gravatar=Désactiver Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Configuration du Journal
config.log_mode=Mode du journal
@@ -1066,8 +1106,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>

292
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
@@ -103,6 +96,8 @@ offline_mode=Abilita Modalità Offline
offline_mode_popup=Disabilita il CDN anche in modalità produttiva, tutte le risorse saranno servite localmente.
disable_gravatar=Disattiva il servizio Gravatar
disable_gravatar_popup=Disabilita Gravatar e sorgenti customizzate, tutti gli avatar vengono caricati dagli utenti o come predefinito.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Disabilita Registrazione Manuale
disable_registration_popup=Disabilita la registrazione manuale degli utenti, solo gli amministratori possono creare account.
enable_captcha=Abilita Captcha
@@ -131,6 +126,7 @@ uname_holder=Nome Utente o E-mail
password_holder=Password
switch_dashboard_context=Cambia Dashboard Context
my_repos=I miei Repository
show_more_repos=Show more repositories...
collaborative_repos=Repository Condivisi
my_orgs=Le mie Organizzazioni
my_mirrors=I miei Mirror
@@ -140,6 +136,8 @@ issues.in_your_repos=Nei tuoi repository
[explore]
repos=Repository
users=Utenti
search=Cerca
[auth]
create_new_account=Crea un nuovo Account
@@ -153,6 +151,8 @@ forget_password=Password dimenticata?
sign_up_now=Bisogno di un account? Iscriviti ora.
confirmation_mail_sent_prompt=Una nuova email di conferma è stata inviata a <b>%s</b>, verifica la tua casella di posta entro le prossime %d ore per completare la registrazione.
active_your_account=Attiva il tuo Account
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Siamo spiacenti, si stanno inviando e-mail di attivazione troppo spesso. Si prega di attendere 3 minuti.
has_unconfirmed_mail=Ciao %s, hai un indirizzo di posta elettronica non confermato (<b>%s</b>). Se non hai ricevuto una e-mail di conferma o vuoi riceverla nuovamente, fare clic sul pulsante qui sotto.
resend_mail=Clicca qui per inviare nuovamente l'e-mail di attivazione
@@ -162,6 +162,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=La struttura del nome utente '%s' non è consentit
[settings]
profile=Profilo
password=Password
avatar=Avatar
ssh_keys=Chiavi SSH
social=Account Sociali
applications=Applicazioni
@@ -261,10 +262,12 @@ change_username_prompt=Questa modifica influenzerà il modo in cui i link si rif
continue=Continua
cancel=Annulla
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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.
@@ -347,7 +350,7 @@ fork_from=Forka da
fork_visiblity_helper=Non puoi cambiare la visibilità di un repository forkato.
repo_desc=Descrizione
repo_lang=Lingua
repo_lang_helper=Seleziona file .gitignore
repo_gitignore_helper=Select .gitignore templates
license=Licenza
license_helper=Selezionare un file di licenza
readme=Readme
@@ -355,6 +358,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.
@@ -412,6 +417,7 @@ file_raw=Originale
file_history=Cronologia
file_view_raw=Vedi originale
file_permalink=Permalink
file_too_large=This file is too large to be shown
commits.commits=Commits
commits.search=Ricerca una versione
@@ -465,23 +471,24 @@ issues.next=Pagina successiva
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.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
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 +507,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=Questo contributo è stato incluso 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 +564,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 +573,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
@@ -573,38 +584,41 @@ settings.site=Sito Ufficiale
settings.update_settings=Aggiorna Impostazioni
settings.change_reponame_prompt=Questa modifica influirà i link al repository.
settings.advanced_settings=Opzioni avanzate
settings.wiki_desc=Abilitare il wiki per consentire alle persone di scrivere documenti
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
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=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumeric
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 +627,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 +638,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 +656,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 +680,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_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=Rilasci
release.new_release=Nuovo Rilascio
@@ -702,22 +718,23 @@ 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.tag_name_invalid=Tag name is not valid.
release.downloads=Download
[org]
@@ -749,7 +766,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 +781,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 +811,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,9 +899,10 @@ 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.prohibit_login=This account is prohibited to login
users.is_admin=Questo account ha permessi di amministratore
users.allow_git_hook=Questo account ha il permesso di creare hooks di Git
users.allow_import_local=Questo account dispone delle autorizzazioni per importare repository locali
@@ -908,31 +926,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 +961,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 +988,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
@@ -989,20 +1008,23 @@ config.db_ssl_mode=Modalità SSL
config.db_ssl_mode_helper=(solo per "postgres")
config.db_path=Percorso
config.db_path_helper=(per "sqlite3" e "tidb")
config.service_config=Configurazione Servizio
config.register_email_confirm=Richiedono Conferma dell'Email
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
config.mailer_enabled=Attivo
config.mailer_disable_helo=Disattiva HELO
@@ -1010,14 +1032,17 @@ 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
config.cache_adapter=Adattatore Cache
config.cache_interval=Intervallo Cache
config.cache_conn=Connessione Cache
config.session_config=Configurazione Sessione
config.session_provider=Fornitore Sessione
config.provider_config=Impostazioni Provider
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Intervallo di tempo della GC
config.session_life_time=Durata Sessione
config.https_only=Solo HTTPS
config.cookie_life_time=Durata Cookie
config.picture_config=Configurazione Foto
config.picture_service=Servizio foto
config.disable_gravatar=Disabilita Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Configurazione Log
config.log_mode=Modalità Log
@@ -1045,18 +1085,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 +1112,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 +1136,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

184
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,12 @@ 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とカスタムソースを無効にして、全てのアバターをユーザーによってアップロードされたものかデフォルトなものにします。
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=自己登録を無効にする
disable_registration_popup=自己登録を無効にし、管理者のみがアカウント作成できる
enable_captcha=Captchaを有効にする
@@ -124,35 +119,40 @@ 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=自分のリポジトリ
show_more_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=アカウントを有効化
prohibit_login=ログイン禁止
prohibit_login_desc=あなたのアカウントはログインを禁止されています。サイト管理者にお問い合わせください。
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
resend_mail=アクティベーションメールを再送信するにはここをクリック
@@ -162,13 +162,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 +225,7 @@ org_still_own_repo=この組織はまだリポジトリの所有しています
target_branch_not_exist=ターゲットブランチが存在しない
[user]
change_avatar=gravatar.com で自分のアバターを変更
change_custom_avatar=設定で自分のアバターを変更
change_avatar=アバターを変更
join_on=参加しました
repositories=リポジトリ
activity=パブリック・アクティビティ
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=ユーザ名のパターン '%s' は許可され
[settings]
profile=プロフィール
password=パスワード
avatar=Avatar
ssh_keys=SSH キー
social=SNSアカウント
applications=アプリケーション
@@ -261,10 +262,12 @@ change_username_prompt=この変更はリンクをアカウントに関連付け
continue=続行
cancel=キャンセル
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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 +318,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 +331,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,18 +339,18 @@ 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ファイルを選択
repo_gitignore_helper=Select .gitignore templates
license=ライセンス
license_helper=ライセンス ファイルを選択
readme=Readme
@@ -355,6 +358,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 +368,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 +381,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,10 +413,11 @@ labels=ラベル
milestones=マイルストーン
commits=コミット
releases=リリース
file_raw=生データ
file_raw=Raw
file_history=履歴
file_view_raw=データを見る
file_view_raw=Rawデータを見る
file_permalink=パーマリンク
file_too_large=このファイルは大きすぎるため、表示できません。
commits.commits=コミット
commits.search=コミットの検索
@@ -448,8 +454,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=最新
@@ -465,10 +471,11 @@ issues.next=次ページ
issues.open_title=オープン
issues.closed_title=クローズ
issues.num_comments=%d コメント
issues.commented_at=`コメント <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
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 +483,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>
@@ -503,7 +510,7 @@ pulls.compare_compare=比較
pulls.filter_branch=フィルターブランチ
pulls.no_results=結果が見つかりませんでした。
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.has_pull_request=`既にプルリクエストがこれらのターゲット間に存在します: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=プルリクエストを作成します。
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
@@ -566,6 +573,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=基本設定
@@ -573,13 +584,18 @@ settings.site=公式サイト
settings.update_settings=設定の更新
settings.change_reponame_prompt=この変更はリンクがリポジトリに関連付ける方法に影響します。
settings.advanced_settings=拡張設定
settings.wiki_desc=Wikiでドキュメントの作成を許可
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=外部 wiki を使用します。
settings.external_wiki_url=外部 Wiki の URL
settings.external_wiki_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.issues_desc=組み込み簡易課題トラッカーを有効
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumeric
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 +618,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 +702,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_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=リリース
release.new_release=新しいリリース
@@ -718,6 +734,7 @@ release.deletion=リリースの削除
release.deletion_desc=このリリースを削除すると、対応するGitのタグも削除されます。よろしいですか
release.deletion_success=リリースが正常に削除されました。
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
release.tag_name_invalid=Tag name is not valid.
release.downloads=Downloads
[org]
@@ -725,7 +742,7 @@ org_name_holder=組織名
org_full_name_holder=組織のフルネーム
org_name_helper=偉大な組織の名は短く覚えやすいです。
create_org=組織を作成
repo_updated=更新した
repo_updated=最終更新
people=人々
invite_someone=誰かを招待
teams=チーム
@@ -753,8 +770,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 を追加します。
@@ -885,6 +902,7 @@ users.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=アカウントがアクティブされました
users.prohibit_login=This account is prohibited to login
users.is_admin=このアカウントには管理者の権限を持つ
users.allow_git_hook=このアカウントには Git のフックを作成する権限を持つ
users.allow_import_local=This account has permissions to import local repositories
@@ -912,9 +930,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=ポート
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL モード
config.db_ssl_mode_helper=(「postgres」のみ
config.db_path=パス
config.db_path_helper=(for "sqlite3" and "tidb")
config.service_config=サービスの構成
config.register_email_confirm=電子メールの確認を必要
config.disable_register=登録を無効にする
@@ -999,10 +1019,12 @@ config.disable_key_size_check=最小キー サイズ チェックを無効にし
config.enable_captcha=Captchaを有効にする
config.active_code_lives=コードリンクの有効期限をアクティブ
config.reset_password_code_lives=パスワードリンクの有効期限をリセット
config.webhook_config=Webhook設定
config.queue_length=キューの長さ
config.deliver_timeout=送信タイムアウト
config.skip_tls_verify=TLSの確認を省略
config.mailer_config=メーラーの構成
config.mailer_enabled=有効にした
config.mailer_disable_helo=HELOコマンド無効
@@ -1012,24 +1034,42 @@ 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.oauth_config=OAuth 構成
config.oauth_enabled=Enabled
config.cache_config=キャッシュの構成
config.cache_adapter=キャッシュ アダプター
config.cache_interval=キャッシュ間隔
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=セッションのライフタイム
config.https_only=HTTPS のみ
config.cookie_life_time=クッキーのライフタイム
config.picture_config=画像構成
config.picture_service=画像サービス
config.disable_gravatar=グラバターを無効にする
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=ログの構成
config.log_mode=ログ モード
@@ -1059,8 +1099,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 +1126,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

100
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
@@ -103,6 +96,8 @@ offline_mode=Iespējot bezsaistes režīmu
offline_mode_popup=Atspējot CDN arī produkcijas režīmā, visi resursu faili tiks piegādāti no servera.
disable_gravatar=Atspējot Gravatar pakalpojumu
disable_gravatar_popup=Atspējot Gravatar un citus avotus, visus avatarus augšupielādēts lietotāji vai izmantos noklusēto attēlu.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Atspējot lietotāju reģistrāciju
disable_registration_popup=Atspējot lietotāju reģistrāciju, tikai administrators varēs izveidot jaunus lietotāju kontus.
enable_captcha=Iespējot drošības kodu
@@ -131,6 +126,7 @@ uname_holder=Lietotājvārds vai e-pasts
password_holder=Parole
switch_dashboard_context=Mainīt infopaneļa kontekstu
my_repos=Mani repozitoriji
show_more_repos=Parādīt vairāk repozitorojus...
collaborative_repos=Sadarbības repozitoriji
my_orgs=Manas organizācijas
my_mirrors=Mani spoguļi
@@ -140,6 +136,8 @@ issues.in_your_repos=Jūsu repozitorijos
[explore]
repos=Repozitoriji
users=Lietotāji
search=Meklēt
[auth]
create_new_account=Izveidot jaunu kontu
@@ -153,6 +151,8 @@ forget_password=Aizmirsi paroli?
sign_up_now=Nepieciešams konts? Reģistrējies tagad.
confirmation_mail_sent_prompt=Jauns apstiprināšanas e-pasts ir nosūtīts uz <b>%s</b>, lūdzu, pārbaudies savu e-pasta kontu tuvāko %d stundu laikā, lai pabeigtu reģistrācijas procesu.
active_your_account=Aktivizēt savu kontu
prohibit_login=Aizliegt pieteikšanos
prohibit_login_desc=Ar Jūsu kontu nav atļauts pieteikties, sazinoties ar lapas administratoru.
resent_limit_prompt=Atvainojiet, Jūs sūtījāt aktivizācijas e-pastu pārāk bieži. Lūdzu, gaidiet 3 minūtes.
has_unconfirmed_mail=Sveiki %s, Jums ir neapstiprināta e-pasta adrese (<b>%s</b>). Ja neesat saņēmis apstiprināšanas e-pastu vai Jums ir nepieciešams nosūtīt jaunu, lūdzu, nospiediet pogu, kas atrodas zemāk.
resend_mail=Nospiediet šeit, lai vēlreiz nosūtītu aktivizācijas e-pastu
@@ -162,6 +162,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=Tikai lokālie konti var nomainīt savu paroli Gogs.
[mail]
activate_account=Lūdzu, aktivizējiet savu kontu
@@ -224,8 +225,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=Mainīt profila attēlu
join_on=Pievienojās
repositories=Repozitoriji
activity=Publiskā aktivitāte
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
[settings]
profile=Profils
password=Parole
avatar=Avatar
ssh_keys=SSH atslēgas
social=Sociālie konti
applications=Lietotnes
@@ -261,10 +262,12 @@ change_username_prompt=Šī izmaiņa ietekmēs saites, kas norāda uz Jūsu kont
continue=Turpināt
cancel=Atcelt
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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.
@@ -347,7 +350,7 @@ fork_from=Atdalīt no
fork_visiblity_helper=Atdalītam repozitorijam nav iespējams nomainīt tā redzamību
repo_desc=Apraksts
repo_lang=Valoda
repo_lang_helper=Izvēlieties .gitignore failus
repo_gitignore_helper=Select .gitignore templates
license=Licence
license_helper=Izvēlieties licences failu
readme=LasiMani
@@ -355,6 +358,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=Izmest
mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē
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.
@@ -412,6 +417,7 @@ file_raw=Neapstrādāts
file_history=Vēsture
file_view_raw=Rādīt neapstrādātu
file_permalink=Patstāvīgā saite
file_too_large=Šis fails ir par lielu, lai to parādītu
commits.commits=Revīzijas
commits.search=Meklēt revīzijas
@@ -465,7 +471,8 @@ issues.next=Nākamā
issues.open_title=Atvērta
issues.closed_title=Slēgta
issues.num_comments=%d komentāri
issues.commented_at=`komentēja <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=` komentēja <a href="#%s">%s</a>`
issues.delete_comment_confirm=Vai patiešām vēlaties dzēst šo komentāru?
issues.no_content=Vēl nav satura.
issues.close_issue=Aizvērt
issues.close_comment_issue=Komentēt un aizvērt
@@ -476,7 +483,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 +564,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 +573,10 @@ wiki.last_updated=Pēdējo reizi labota %s
settings=Iestatījumi
settings.options=Opcijas
settings.collaboration=Sadarbība
settings.collaboration.admin=Administrators
settings.collaboration.write=Rakstīšanas
settings.collaboration.read=Skatīšanās
settings.collaboration.undefined=Nedefinētas
settings.hooks=Tīmekļa āķi
settings.githooks=Git āķi
settings.basic_settings=Pamatiestatījumi
@@ -573,13 +584,18 @@ settings.site=Oficiālā mājas lapa
settings.update_settings=Mainīt iestatījumus
settings.change_reponame_prompt=Šī izmaiņa ietekmēs saites, kas ir saistītas ar šo repozitoriju.
settings.advanced_settings=Papildu iestatījumi
settings.wiki_desc=Iespējot vikivietni, lai atļautu cilvēkiem rakstīt dokumentus
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Izmantot ārējo vikivietni
settings.external_wiki_url=Ārējās Vikivietnes adrese
settings.external_wiki_url_desc=Apmeklētāji tiks novirzīti uz adresi, kad viņi uzklikšķinās uz cilnes.
settings.issues_desc=Iespējot iebūvētu vieglu problēmu sekotāju
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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=Ārējā problēmu reģistra nosaukumu stils:
settings.tracker_issue_style.numeric=Cipari
settings.tracker_issue_style.alphanumeric=Burti un cipari
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 +610,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=- Visi atdalītie repozitoriji kļūs neatkarīgi pēc dzēšanas.
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 +627,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 +702,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_suppressed=Failā izmaiņas netiks attēlotas, jo tās ir par lielu
diff.too_many_files=Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels
release.releases=Laidieni
release.new_release=Jauns laidiens
@@ -718,6 +734,7 @@ release.deletion=Laidiena dzēšana
release.deletion_desc=Dzēšot šo laidienu tiks dzēsts arī atbilstošs Git tags. Vai vēlaties turpināt?
release.deletion_success=Laidiens tika veiksmīgi dzēsts!
release.tag_name_already_exist=Laidiens ar šādu taga nosaukumu jau eksistē.
release.tag_name_invalid=Nekorekts birkas nosaukams.
release.downloads=Lejupielādes
[org]
@@ -885,6 +902,7 @@ users.edit_account=Labot kontu
users.max_repo_creation=Maksimāls repozitoriju veidošanas limits
users.max_repo_creation_desc=(Uzlikt -1 lai izmantotu globālu limitu pēc noklusējuma)
users.is_activated=Konts ir aktivizēts
users.prohibit_login=Šim kontam ir aizliegts autorizēties
users.is_admin=Šim kontam ir administratora piekļuves tiesības
users.allow_git_hook=Šim kontam ir tiesības pievienot/labot Git āķus
users.allow_import_local=Šim kontam ir tiesības importēt lokālus repozitorijus
@@ -915,6 +933,7 @@ auths.enabled=Iespējota
auths.updated=Atjaunināta
auths.auth_type=Autentifikācijas tips
auths.auth_name=Autentifikācijas nosaukums
auths.security_protocol=Drošības protokols
auths.domain=Domēns
auths.host=Resursdators
auths.port=Ports
@@ -950,7 +969,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL režīms
config.db_ssl_mode_helper=(tikai PostgreSQL datu bāzei)
config.db_path=Ceļš
config.db_path_helper=(priekš "sqlite3" and "tidb")
config.service_config=Pakalpojuma konfigurācija
config.register_email_confirm=Pieprasīt e-pasta apstiprināšanu
config.disable_register=Atspējot jaunu lietotāju reģistrāciju
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi
config.enable_captcha=Iespējot drošības kodu
config.active_code_lives=Aktīvā koda ilgums
config.reset_password_code_lives=Paroles atiestatīšanas koda ilgums
config.webhook_config=Tīkla āķu konfigurācija
config.queue_length=Rindas garums
config.deliver_timeout=Piegādes noildze
config.skip_tls_verify=Izlaist TLS pārbaudi
config.mailer_config=Sūtītāja konfigurācija
config.mailer_enabled=Iespējots
config.mailer_disable_helo=Atspējot HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Lietotājs
config.send_test_mail=Nosūtīt pārbaudes e-pastu
config.test_mail_failed=Neizdevās nosūtīt pārbaudes e-pasta vēstuli uz '%s': %v
config.test_mail_sent=Pārbaudes e-pasta vēstule tika nosūtīta uz '%s'.
config.oauth_config=OAuth konfigurācija
config.oauth_enabled=Iespējota
config.cache_config=Kešatmiņas konfigurācija
config.cache_adapter=Kešatmiņas adapteris
config.cache_interval=Kešatmiņas intervāls
config.cache_conn=Kešatmiņas pieslēguma parametri
config.session_config=Sesijas konfigurācja
config.session_provider=Sesijas nodrošinātājs
config.provider_config=Pakalpojumu sniedzēja konfigurācija
@@ -1027,9 +1052,24 @@ config.gc_interval_time=GC laika intervāls
config.session_life_time=Sesijas ilgums
config.https_only=Tikai HTTPS
config.cookie_life_time=Sīkdatņu glabāšanas ilgums
config.picture_config=Attēlu konfigurācija
config.picture_service=Lokāli attēli
config.disable_gravatar=Atspējot Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Žurnalizēšanas konfigurācija
config.log_mode=Žurnalizēšanas veids
@@ -1066,8 +1106,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>

188
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
@@ -103,6 +96,8 @@ offline_mode=Off line modus inschakelen
offline_mode_popup=Schakel CDN uit in productiemodus, alle bestanden worden lokaal aangeboden.
disable_gravatar=Gravatar Service uitschakelen
disable_gravatar_popup=Schakel Gravatar en andere bronnen uit, alle avatars worden door gebruikers geüpload of zijn standaard.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Schakel zelfregistratie uit
disable_registration_popup=Schakel zelfregistratie uit, alleen admins kunnen accounts maken.
enable_captcha=Inschakelen Captcha
@@ -131,6 +126,7 @@ uname_holder=Gebruikersnaam of e-mail
password_holder=Wachtwoord
switch_dashboard_context=Wissel voorpaginacontext
my_repos=Mijn repositories
show_more_repos=Show more repositories...
collaborative_repos=Gedeelde repositories
my_orgs=Mijn organisaties
my_mirrors=Mijn mirrors
@@ -140,6 +136,8 @@ issues.in_your_repos=In uw repositories
[explore]
repos=Repositories
users=Gebruikers
search=Zoeken
[auth]
create_new_account=Maak nieuw account aan
@@ -153,6 +151,8 @@ forget_password=Wachtwoord vergeten?
sign_up_now=Een account nodig? Meld u nu aan.
confirmation_mail_sent_prompt=Een bevestigingsemail is gestuurd naar <b>%s</b>, Bevestig u aanvraag binnen %d uren om uw registratie te voltooien.
active_your_account=Activeer uw account
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Sorry, u heeft te snel na elkaar een aanvraag gedaan voor een activatie mail. Wacht drie minuten voor uw volgende aanvraag.
has_unconfirmed_mail=Beste %s, u heeft een onbevestigd e-mailadres (<b>%s</b>). Als u nog geen bevestiging heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop.
resend_mail=Klik hier om uw activatie mail nog een keer te verzenden
@@ -162,6 +162,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Het gebruikersnaam patroon '%s' is niet toegestaan
[settings]
profile=Profiel
password=Wachtwoord
avatar=Avatar
ssh_keys=SSH-sleutels
social=Sociale netwerk-accounts
applications=Toepassingen
@@ -261,10 +262,12 @@ change_username_prompt=Deze verandering zal de weg links hebben betrekking op uw
continue=Doorgaan
cancel=Annuleren
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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.
@@ -347,7 +350,7 @@ fork_from=Afsplitsing van
fork_visiblity_helper=U kunt de zichtbaarheid van een geforkte repository niet aanpassen.
repo_desc=Omschrijving
repo_lang=Taal
repo_lang_helper=Selecteer .gitignore bestanden
repo_gitignore_helper=Select .gitignore templates
license=Licentie
license_helper=Selecteer een licentie bestand
readme=Leesmij-bestand
@@ -355,6 +358,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.
@@ -412,6 +417,7 @@ file_raw=Ruwe
file_history=Geschiedenis
file_view_raw=Weergave ruwe
file_permalink=Permalink
file_too_large=This file is too large to be shown
commits.commits=Commits
commits.search=Zoeken
@@ -465,7 +471,8 @@ issues.next=Volgende
issues.open_title=Open
issues.closed_title=Gesloten
issues.num_comments=%d opmerkingen
issues.commented_at=`gaf commentaar op <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Er is nog geen inhoud.
issues.close_issue=Sluit
issues.close_comment_issue=Sluit en geef commentaar
@@ -474,9 +481,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 +513,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 +524,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 +564,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 +573,52 @@ 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=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
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.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumeric
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 +627,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 +681,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 +697,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_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=Nieuwe release
@@ -697,7 +713,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,9 +731,10 @@ 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.tag_name_invalid=Tag name is not valid.
release.downloads=Downloads
[org]
@@ -749,8 +766,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 +776,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 +786,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 +842,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,12 +896,13 @@ 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.prohibit_login=This account is prohibited to login
users.is_admin=Dit account heeft beheerdersrechten
users.allow_git_hook=Deze account beschikt over machtigingen voor het maken van Git haken
users.allow_import_local=Dit account mag lokale repositories importeren
@@ -907,7 +925,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 +933,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 +955,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!
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL modus
config.db_ssl_mode_helper=(alleen voor "postgres")
config.db_path=Pad
config.db_path_helper=(voor "sqlite3" en "tidb")
config.service_config=Serviceconfiguratie
config.register_email_confirm=E-mailbevestiging registreren
config.disable_register=Registratie uitgeschakeld
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Controle op key-lengte uitschakelen
config.enable_captcha=CAPTCHA inschakelen
config.active_code_lives=Actieve Code leven
config.reset_password_code_lives=Reset wachtwoord Code leven
config.webhook_config=Webhook configuratie
config.queue_length=Lengte van wachtrij
config.deliver_timeout=Bezorging verlooptijd
config.skip_tls_verify=TLS certificaat controle overslaan
config.mailer_config=Mailerconfiguatie
config.mailer_enabled=Ingeschakeld
config.mailer_disable_helo=Schakel HELO uit
@@ -1012,12 +1034,15 @@ config.mailer_user=Gebruiker
config.send_test_mail=Testbericht verzenden
config.test_mail_failed=Verzending van een testmail naar '%s' is mislukt: %v
config.test_mail_sent=Test-email is verstuurd naar '%s'.
config.oauth_config=OAuth-configuratie
config.oauth_enabled=Ingeschakeld
config.cache_config=Cache-configuratie
config.cache_adapter=Cache-adapter
config.cache_interval=Cache-interval
config.cache_conn=Cache-connectie
config.session_config=Sessieconfiguratie
config.session_provider=Sessieprovider
config.provider_config=Provider config
@@ -1027,9 +1052,24 @@ config.gc_interval_time=GC interval time
config.session_life_time=Sessie duur
config.https_only=Alleen HTTPS
config.cookie_life_time=Cookie duur leeftijd
config.picture_config=Foto configuratie
config.picture_service=Foto service
config.disable_gravatar=Gravatar uitschakelen
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Logconfiguratie
config.log_mode=Log-modus
@@ -1045,13 +1085,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

154
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
@@ -103,6 +96,8 @@ offline_mode=Włącz tryb offline
offline_mode_popup=Wyłącz CDN, nawet w trybie produkcyjnym, wszystkie pliki zasobów będą podawane lokalnie.
disable_gravatar=Wyłącz usługę Gravatar
disable_gravatar_popup=Wyłącz Gravatar i niestandardowe źrodła, awatary muszą być przesyłane przez użytkowników.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Wyłącz samodzielną rejestrację
disable_registration_popup=Wyłącz samodzielną rejestrację użytkownika, tylko administrator będzie mógł tworzyć konta.
enable_captcha=Włącz Captcha
@@ -124,13 +119,14 @@ 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
password_holder=Hasło
switch_dashboard_context=Przełącz kontekst pulpitu
my_repos=Moje repozytoria
show_more_repos=Pokaż więcej repozytoriów...
collaborative_repos=Wspólne repozytoria
my_orgs=Moje organizacje
my_mirrors=Moje kopie lustrzane
@@ -140,6 +136,8 @@ issues.in_your_repos=W Twoich repozytoriach
[explore]
repos=Repozytoria
users=Użytkownicy
search=Wyszukiwanie
[auth]
create_new_account=Załóż nowe konto
@@ -153,6 +151,8 @@ forget_password=Zapomniałeś hasła?
sign_up_now=Potrzebujesz konta? Zarejestruj się teraz.
confirmation_mail_sent_prompt=Nowa wiadomość e-mail z potwierdzeniem została wysłana do <b>%s</b>, proszę sprawdzić swoją skrzynkę odbiorczą w ciągu najbliższych godzin %d aby dokończyć proces rejestracji.
active_your_account=Aktywuj swoje konto
prohibit_login=Logowanie zabronione
prohibit_login_desc=Nie możesz się zalogować na to konto, skontaktuj się z administratorem strony.
resent_limit_prompt=Niestety, zbyt często wysyłasz e-mail aktywacyjny. Proszę odczekać 3 minuty.
has_unconfirmed_mail=Witaj, %s, masz niepotwierdzony adres e-mail (<b>%s</b>). Jeśli nie otrzymałeś wiadomości e-mail z potwierdzeniem lub potrzebujesz wysłać nową, kliknij na poniższy przycisk.
resend_mail=Kliknij tutaj, aby wysłać e-mail aktywacyjny
@@ -162,6 +162,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=Nie lokalne konta nie mogą zmieniać haseł przez Gogs.
[mail]
activate_account=Prosimy aktywować swoje konto
@@ -224,8 +225,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=Zmień swój awatar
join_on=Dołączył
repositories=Repozytoria
activity=Publiczna aktywność
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Wzorzec nazwy użytkownika "%s" jest niedozwolony.
[settings]
profile=Profil
password=Hasło
avatar=Avatar
ssh_keys=Klucze SSH
social=Konta społecznościowe
applications=Aplikacje
@@ -261,10 +262,12 @@ change_username_prompt=Ta zmiana wpłynie na sposób w jaki łącza odnoszą si
continue=Kontynuuj
cancel=Anuluj
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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.
@@ -347,7 +350,7 @@ fork_from=Forkuj z
fork_visiblity_helper=Fork nie może zmieniać swojej widoczności
repo_desc=Opis
repo_lang=Język
repo_lang_helper=Wybierz pliki .gitignore
repo_gitignore_helper=Select .gitignore templates
license=Licencja
license_helper=Wybierz plik licencji
readme=Readme
@@ -355,6 +358,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=Wyczyść
mirror_prune_desc=Usuń wszystkie śledzone odwołania które nie istnieją w zdalnym repozytorium
mirror_interval=Częstotliwość kopiowania (godziny)
mirror_address=Adres kopii lustrzanej
mirror_address_desc=Proszę podać wymagane poświadczenia użytkownika w adresie.
@@ -412,6 +417,7 @@ file_raw=Czysty
file_history=Historia
file_view_raw=Zobacz czysty
file_permalink=Bezpośredni odnośnik
file_too_large=Ten plik jest zbyt duży, aby go wyświetlić
commits.commits=Commity
commits.search=Przeszukaj commity
@@ -465,7 +471,8 @@ issues.next=Następny
issues.open_title=Otwarty
issues.closed_title=Zamknięty
issues.num_comments=%d komentarzy
issues.commented_at=`komentuje <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`skomentował <a href="#%s">%s</a>`
issues.delete_comment_confirm=Czy na pewno chcesz usunąć ten komentarz?
issues.no_content=Nie ma jeszcze treści.
issues.close_issue=Zamknij
issues.close_comment_issue=Skomentuj i zamknij
@@ -476,7 +483,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 +564,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 +573,10 @@ wiki.last_updated=Ostatnia aktualizacja %s
settings=Ustawienia
settings.options=Opcje
settings.collaboration=Współpraca
settings.collaboration.admin=Administrator
settings.collaboration.write=Zapis
settings.collaboration.read=Odczyt
settings.collaboration.undefined=Niezdefiniowany
settings.hooks=Webhooki
settings.githooks=Hooki Git
settings.basic_settings=Ustawienia podstawowe
@@ -573,38 +584,41 @@ settings.site=Oficjalna Strona
settings.update_settings=Aktualizuj ustawienia
settings.change_reponame_prompt=Zmiana nazwy repozytorium wpłynie na linki do niego.
settings.advanced_settings=Ustawienia zaawansowane
settings.wiki_desc=Włączenie Wiki pozwoli innym pisać dokumenty
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Użyj zewnętrznego Wiki
settings.external_wiki_url=Adres URL zewnętrznego Wiki
settings.external_wiki_url_desc=Odwiedzający zostaną przekierowani do adresu URL po kliknięciu zakładki.
settings.issues_desc=Włącz wbudowany lekki system zgłaszania problemów
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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=Styl nazw zewnętrznego systemu zgłaszania problemów:
settings.tracker_issue_style.numeric=Numeryczny
settings.tracker_issue_style.alphanumeric=Alfanumeryczne
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=Wszystkie forki staną się niezależne po usunięciu.
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 +627,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 +702,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_suppressed=Plik diff jest za duży
diff.too_many_files=Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików
release.releases=Wydania
release.new_release=Nowe wydanie
@@ -708,7 +724,7 @@ release.write=Napisz
release.preview=Podgląd
release.loading=Ładowanie...
release.prerelease_desc=To jest wersja wstępna
release.prerelease_helper=Chcemy zwrócić uwagę, że ta wersja jest oznaczona jako eksperymentalna.
release.prerelease_helper=Oznacz to wydanie jako wersję wstępną.
release.cancel=Anuluj
release.publish=Publikuj wersję
release.save_draft=Zapisz szkic
@@ -718,6 +734,7 @@ release.deletion=Usuwanie wydania
release.deletion_desc=Usunięcie tego wydania spowoduje usunięcie odpowiednich tagów Git. Czy chcesz kontynuować?
release.deletion_success=Wydanie zostało pomyślnie usunięte!
release.tag_name_already_exist=Wersja o tej nazwie tagu już istnieje.
release.tag_name_invalid=Nazwa tagu jest niepoprawna.
release.downloads=Pliki do pobrania
[org]
@@ -885,6 +902,7 @@ users.edit_account=Edytuj konto
users.max_repo_creation=Maksymalna liczba repozytoriów
users.max_repo_creation_desc=(Ustaw -1, aby użyć globalnego limitu)
users.is_activated=To konto jest aktywne
users.prohibit_login=Nie możesz się zalogować na to konto
users.is_admin=To konto ma uprawnienia administratora
users.allow_git_hook=To konto posiada uprawnienia do tworzenia hooków Git
users.allow_import_local=To konto ma uprawnienia do importu lokalnych repozytoriów
@@ -915,6 +933,7 @@ auths.enabled=Włączono
auths.updated=Zaktualizowano
auths.auth_type=Typ uwierzytelniania
auths.auth_name=Nazwa uwierzytelniania
auths.security_protocol=Protokół zabezpieczeń
auths.domain=Domena
auths.host=Host
auths.port=Port
@@ -928,7 +947,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 +969,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 +987,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=Tryb SSL
config.db_ssl_mode_helper=(tylko dla "postgres")
config.db_path=Ścieżka
config.db_path_helper=(dla "sqlite3" i "tidb")
config.service_config=Konfiguracja usługi
config.register_email_confirm=Wymagaj potwierdzenia e-mail
config.disable_register=Wyłącz rejestrację
@@ -999,25 +1019,30 @@ config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
config.enable_captcha=Włącz Captcha
config.active_code_lives=Ważność kodów aktywacyjnych
config.reset_password_code_lives=Czas życia kodu resetowania hasła
config.webhook_config=Konfiguracja webhooka
config.queue_length=Długość kolejki
config.deliver_timeout=Limit czasu zdarzenia
config.skip_tls_verify=Pomiń weryfikację protokołu TLS
config.mailer_config=Konfiguracja poczty
config.mailer_enabled=Aktywne
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
config.cache_adapter=Adapter cache
config.cache_interval=Interwał pamięci podręcznej
config.cache_conn=Połączenie z pamięcią podręczną
config.session_config=Konfiguracja sesji
config.session_provider=Dostawca sesji
config.provider_config=Konfiguracja dostawcy
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Interwał odśmiecania
config.session_life_time=Czas życia sesji
config.https_only=Tylko HTTPS
config.cookie_life_time=Czas życia ciasteczka
config.picture_config=Ustawienia obrazów
config.picture_service=Serwis obrazów
config.disable_gravatar=Wyłącz Gravatara
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Konfiguracja dziennika
config.log_mode=Tryb dziennika
@@ -1063,11 +1103,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>

106
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
@@ -103,6 +96,8 @@ offline_mode=Ativar modo off-line
offline_mode_popup=Desative o CDN mesmo em modo de produção, todos os recursos serão disponibilizados localmente.
disable_gravatar=Desativar serviço Gravatar
disable_gravatar_popup=Desabilitar o Gravatar e fontes personalizadas, todos os avatares são enviados por usuários ou padrão.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Desativar auto-registro
disable_registration_popup=Desativar o auto-registro de usuário, para que somente o administrador possa criar contas.
enable_captcha=Habilitar captcha
@@ -131,6 +126,7 @@ uname_holder=Nome de Usuário ou E-mail
password_holder=Senha
switch_dashboard_context=Trocar Contexto do Painel de Controle
my_repos=Meus Repositórios
show_more_repos=Mostrar mais repositórios...
collaborative_repos=Repositórios Colaborativos
my_orgs=Minhas Organizações
my_mirrors=Meus Espelhos
@@ -140,6 +136,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
@@ -153,6 +151,8 @@ forget_password=Esqueceu a senha?
sign_up_now=Precisa de uma conta? Cadastre-se agora.
confirmation_mail_sent_prompt=Um novo e-mail de confirmação foi enviado para <b>%s</b>, por favor, verifique sua caixa de entrada nas próximas %d horas para completar seu registro.
active_your_account=Ativar Sua Conta
prohibit_login=Login proibido
prohibit_login_desc=Sua conta foi proibida de efetuar login, por favor contate o administrador do site.
resent_limit_prompt=Desculpe, você está enviando um e-mail de ativação com muita frequência. Por favor, aguarde 3 minutos.
has_unconfirmed_mail=Oi %s, você possui um endereço de e-mail não confirmado (<b>%s</b>). Se você não recebeu um e-mail de confirmação ou precisa reenviar um novo, clique no botão abaixo.
resend_mail=Clique aqui para reenviar seu e-mail de ativação
@@ -162,6 +162,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 +225,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
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome
[settings]
profile=Perfil
password=Senha
avatar=Avatar
ssh_keys=Chaves SSH
social=Contas Sociais
applications=Aplicativos
@@ -261,10 +262,12 @@ change_username_prompt=Essa alteração afetará os links para a sua conta.
continue=Continuar
cancel=Cancelar
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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.
@@ -347,7 +350,7 @@ fork_from=Fork de
fork_visiblity_helper=Não é possível alterar a visibilidade de um repositório forkado.
repo_desc=Descrição
repo_lang=Linguagem
repo_lang_helper=Selecione arquivos .gitignore
repo_gitignore_helper=Select .gitignore templates
license=Licença
license_helper=Selecione um arquivo de licença
readme=Leia-me
@@ -355,6 +358,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.
@@ -412,6 +417,7 @@ file_raw=Cru
file_history=Histórico
file_view_raw=Ver cru
file_permalink=Link permanente
file_too_large=Este arquivo é muito grande para ser exibido
commits.commits=Commits
commits.search=Pesquisar commits
@@ -465,7 +471,8 @@ issues.next=Próxima página
issues.open_title=aberto
issues.closed_title=fechado
issues.num_comments=%d comentários
issues.commented_at=`comentado <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`comentado <a href="#%s">%s</a>`
issues.delete_comment_confirm=Tem certeza que deseja deletar este comentário?
issues.no_content=Nenhum conteúdo textual.
issues.close_issue=Fechar
issues.close_comment_issue=Comentar e fechar
@@ -476,7 +483,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 +564,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,20 +573,29 @@ 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
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Usar wiki externa
settings.external_wiki_url=URL externa da wiki
settings.external_wiki_url_desc=Os visitantes serão redirecionados para a URL quando clicarem na aba.
settings.issues_desc=Habilitar gerenciamento de "problemas" nativo
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alfanumérico
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 +610,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 +627,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 +702,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_suppressed=Diferenças do arquivo suprimidas por serem muito extensas
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
@@ -718,6 +734,7 @@ release.deletion=Deleção de versão
release.deletion_desc=Deletar esta versão vai deletar a tag do git correspondente. Você deseja continuar?
release.deletion_success=A versão foi deletada com sucesso!
release.tag_name_already_exist=Já existiu versão com esse nome de tag.
release.tag_name_invalid=Nome de tag não é válido.
release.downloads=Downloads
[org]
@@ -763,7 +780,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
@@ -885,6 +902,7 @@ users.edit_account=Editar Conta
users.max_repo_creation=Limite máximo de criação de repositórios
users.max_repo_creation_desc=(Use "-1" para utilizar o limite padrão)
users.is_activated=Esta conta está ativada
users.prohibit_login=Esta conta está proibida de efetuar login
users.is_admin=Esta conta tem permissões de administrador
users.allow_git_hook=Esta conta tem permissões para criar hooks do Git
users.allow_import_local=Esta conta tem permissões para importar repositórios locais
@@ -915,6 +933,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 +969,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
@@ -989,6 +1008,7 @@ config.db_ssl_mode=Modo SSL
config.db_ssl_mode_helper=(apenas para "postgres")
config.db_path=Caminho
config.db_path_helper=(para "sqlite3" e "tidb")
config.service_config=Configuração do Serviço
config.register_email_confirm=Requerer Confirmação de E-mail
config.disable_register=Desabilitar Registro
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Desativar verificação de tamanho mínimo da chav
config.enable_captcha=Habilitar o Captcha
config.active_code_lives=Ativar Code Lives
config.reset_password_code_lives=Redefinir Senha de Code Lives
config.webhook_config=Configuração de Hook da Web
config.queue_length=Tamanho da fila
config.deliver_timeout=Intervalo de Entrega
config.skip_tls_verify=Pular Verificar TLS
config.mailer_config=Configuração de Correio
config.mailer_enabled=Habilitado
config.mailer_disable_helo=Desabilitar HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Usuário
config.send_test_mail=Enviar email de teste
config.test_mail_failed=Falha ao enviar o email de teste para '%s': %v
config.test_mail_sent=O email de teste foi enviado para '%s'.
config.oauth_config=Configuração do OAuth
config.oauth_enabled=Habilitado
config.cache_config=Configuração de Cache
config.cache_adapter=Adaptador de Cache
config.cache_interval=Intervalo de Cache
config.cache_conn=Conexão de Cache
config.session_config=Configuração da Sessão
config.session_provider=Provedor da Sessão
config.provider_config=Configuração do Provedor
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Tempo de Intervalo do GC
config.session_life_time=Tempo de Vida da Sessão
config.https_only=Apenas HTTPS
config.cookie_life_time=Tempo de Vida do Cookie
config.picture_config=Configuração da Imagem
config.picture_service=Serviço de Imagens
config.disable_gravatar=Desativar Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Configuração de Log
config.log_mode=Modo do Log
@@ -1066,8 +1106,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>

80
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=Установочные шаги для первого запуска
@@ -103,6 +96,8 @@ offline_mode=Включение офлайн режима
offline_mode_popup=Отключить CDN даже в производственном режиме, все файлы ресурсов будут раздаваться локально.
disable_gravatar=Отключить службу Gravatar
disable_gravatar_popup=Отключить Gravatar и пользовательские источники, все аватары по-умолчанию загружаются пользователями.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Отключить самостоятельную регистрацию
disable_registration_popup=Запретить пользователям самостоятельную регистрацию, только администратор может создавать аккаунты.
enable_captcha=Включить капчу
@@ -131,6 +126,7 @@ uname_holder=Имя пользователь или E-mail
password_holder=Пароль
switch_dashboard_context=Переключить контекст панели управления
my_repos=Мои репозитории
show_more_repos=Show more repositories...
collaborative_repos=Совместные репозитории
my_orgs=Мои организации
my_mirrors=Мои зеркала
@@ -140,6 +136,8 @@ issues.in_your_repos=В ваших репозиториях
[explore]
repos=Репозитории
users=Пользователи
search=Поиск
[auth]
create_new_account=Создать новый аккаунт
@@ -153,6 +151,8 @@ forget_password=Забыли пароль?
sign_up_now=Нужен аккаунт? Зарегистрируйтесь.
confirmation_mail_sent_prompt=Новое письмо для подтверждения было направлено на <b>%s</b>, пожалуйста, проверьте ваш почтовый ящик в течение %d часов для завершения регистрации.
active_your_account=Активируйте свой аккаунт
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Извините, вы уже запросили активацию по электронной почте недавно. Пожалуйста, подождите 3 минуты, а затем повторите попытку.
has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (<b>%s</b>). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже.
resend_mail=Нажмите здесь, чтобы переотправить активационное письмо
@@ -162,6 +162,7 @@ reset_password=Сброс пароля
invalid_code=Извините, ваш код подтверждения истек или не является допустимым.
reset_password_helper=Нажмите здесь, чтобы сбросить свой пароль
password_too_short=Длина пароля не менее 6 символов.
non_local_account=Нелокальные аккаунты не могут изменить пароль через Gogs.
[mail]
activate_account=Пожалуйста активируйте свой аккаунт
@@ -224,8 +225,7 @@ org_still_own_repo=Данная организация все еще являе
target_branch_not_exist=Целевая ветка не существует
[user]
change_avatar=Измените ваш аватар на gravatar.com
change_custom_avatar=Измените ваш аватар в настройках
change_avatar=Изменить аватар
join_on=Присоединился
repositories=Репозитории
activity=Активность
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=Имя пользователя «%s» не доп
[settings]
profile=Профиль
password=Пароль
avatar=Avatar
ssh_keys=SSH ключи
social=Учетные записи в соцсетях
applications=Приложения
@@ -261,6 +262,8 @@ change_username_prompt=Это изменение может повлечь за
continue=Далее
cancel=Отмена
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Включить собственный аватар
choose_new_avatar=Выбрать новый аватар
update_avatar=Обновить настройку аватара
@@ -347,7 +350,7 @@ fork_from=Ответвление от
fork_visiblity_helper=Ответвленному репозиторию нельзя поменять уровень видимости
repo_desc=Описание
repo_lang=Язык
repo_lang_helper=Выберите файлы .gitignore
repo_gitignore_helper=Select .gitignore templates
license=Лицензия
license_helper=Выберите файл лицензии
readme=Readme
@@ -355,6 +358,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=Укажите необходимые учетные данные в адрес.
@@ -412,6 +417,7 @@ file_raw=Исходник
file_history=История
file_view_raw=Посмотреть исходник
file_permalink=Постоянная ссылка
file_too_large=This file is too large to be shown
commits.commits=Коммиты
commits.search=Поиск коммитов
@@ -465,7 +471,8 @@ issues.next=Следующая страница
issues.open_title=Открыто
issues.closed_title=Закрыто
issues.num_comments=комментариев: %d
issues.commented_at=` прокомментировал <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Пока нет содержимого.
issues.close_issue=Закрыть
issues.close_comment_issue=Прокомментировать и закрыть
@@ -566,6 +573,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=Основные параметры
@@ -573,13 +584,18 @@ settings.site=Официальный сайт
settings.update_settings=Обновить настройки
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
settings.advanced_settings=Расширенные настройки
settings.wiki_desc=Включить Вики, чтобы позволить людям писать документы
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Использовать внешнюю Wiki
settings.external_wiki_url=URL-адрес внешней Вики
settings.external_wiki_url_desc=Посетители будут перенаправлены на URL-адрес, когда они кликнут по вкладке.
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач:
settings.tracker_issue_style.numeric=Numeric
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
settings.pulls_desc=Включить публичные запросы на слияние
settings.danger_zone=Опасная зона
@@ -602,9 +618,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 +695,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_suppressed=File diff suppressed because it is too large
diff.too_many_files=Некоторые файлы не были показать из-за большого количества измененных файлов
release.releases=Релизы
release.new_release=Новый релиз
@@ -718,6 +734,7 @@ release.deletion=Удаление релиза
release.deletion_desc=Удаление этого релиза удалит соответствующую Git метку. Вы хотите продолжить?
release.deletion_success=Релиз был успешно удален!
release.tag_name_already_exist=Релиз с этим именем метки уже существует.
release.tag_name_invalid=Tag name is not valid.
release.downloads=Загрузки
[org]
@@ -885,6 +902,7 @@ users.edit_account=Изменение учетной записи
users.max_repo_creation=Ограничение максимального количества создаваемых репозиториев
users.max_repo_creation_desc=(Установить -1 для использования стандартного глобального значения предела)
users.is_activated=Эта учетная запись активирована
users.prohibit_login=This account is prohibited to login
users.is_admin=У этой учетной записи есть права администратора
users.allow_git_hook=Пользователь имеет право создать Git перехватчик
users.allow_import_local=Пользователь имеет право импортировать локальные репозитории
@@ -915,6 +933,7 @@ auths.enabled=Включено
auths.updated=Обновлено
auths.auth_type=Тип аутентификации
auths.auth_name=Имя аутентификации
auths.security_protocol=Протокол безопасности
auths.domain=Домен
auths.host=Хост
auths.port=Порт
@@ -989,6 +1008,7 @@ config.db_ssl_mode=Режим SSL
config.db_ssl_mode_helper=(только для «postgres»)
config.db_path=Путь
config.db_path_helper=(для "SQLite3" и "TiDB")
config.service_config=Сервисная конфигурация
config.register_email_confirm=Требуется подтверждение по электронной почте
config.disable_register=Отключить регистрацию
@@ -999,10 +1019,12 @@ config.disable_key_size_check=Отключить проверку на мини
config.enable_captcha=Включить капчу
config.active_code_lives=Время жизни кода для активации
config.reset_password_code_lives=Время жизни кода сброса пароля
config.webhook_config=Настройка автоматического обновления репозиции
config.queue_length=Длина очереди
config.deliver_timeout=Задержка доставки
config.skip_tls_verify=Пропустить TLS проверка
config.mailer_config=Настройки почты
config.mailer_enabled=Включено
config.mailer_disable_helo=Отключить HELO
@@ -1012,12 +1034,15 @@ config.mailer_user=Пользователь
config.send_test_mail=Отправить тестовое письмо
config.test_mail_failed=Не удалось отправить тестовое письмо «%s»: %v
config.test_mail_sent=Тестовое письмо было отправлено «%s».
config.oauth_config=Конфигурация OAuth
config.oauth_enabled=Включено
config.cache_config=Настройки кеша
config.cache_adapter=Адаптер кэша
config.cache_interval=Интервал кэширования
config.cache_conn=Подключение кэша
config.session_config=Конфигурация сессии
config.session_provider=Провайдер сессии
config.provider_config=Конфигурация провайдера
@@ -1027,9 +1052,24 @@ config.gc_interval_time=Интервал работы сборщика мусо
config.session_life_time=Время жизни сессии
config.https_only=Только HTTPS
config.cookie_life_time=Время жизни файла cookie
config.picture_config=Настройка изображения
config.picture_service=Сервис изображений
config.disable_gravatar=Отключить Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Конфигурация журнала
config.log_mode=Режим журналирования
@@ -1060,7 +1100,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>`

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

File diff suppressed because it is too large Load Diff

74
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=首次运行安装程序
@@ -103,6 +96,8 @@ offline_mode=启用离线模式
offline_mode_popup=在部署模式下也禁用从 CDN 获取文件,所以的资源都将从本地服务器获取。
disable_gravatar=禁用 Gravatar 服务
disable_gravatar_popup=禁用 Gravatar 和自定义源,仅使用由用户上传的或默认的头像。
federated_avatar_lookup=启用 Federated Avatars 查找
federated_avatar_lookup_popup=启用 Federated Avatars 查找以使用开源的 Libravatar 服务。
disable_registration=禁止用户自主注册
disable_registration_popup=禁止用户自行注册功能,只有管理员可以添加帐号。
enable_captcha=启用验证码服务
@@ -131,6 +126,7 @@ uname_holder=用户名或邮箱
password_holder=密码
switch_dashboard_context=切换控制面板用户
my_repos=我的仓库
show_more_repos=显示更多仓库...
collaborative_repos=参与协作的仓库
my_orgs=我的组织
my_mirrors=我的镜像
@@ -139,7 +135,9 @@ view_home=访问 %s
issues.in_your_repos=属于该用户仓库的
[explore]
repos=探索仓库
repos=仓库
users=用户
search=搜索
[auth]
create_new_account=创建帐户
@@ -153,6 +151,8 @@ forget_password=忘记密码?
sign_up_now=还没帐户?马上注册。
confirmation_mail_sent_prompt=一封新的确认邮件已经被发送至 <b>%s</b>,请检查您的收件箱并在 %d 小时内完成确认注册操作。
active_your_account=激活您的帐户
prohibit_login=禁止登录
prohibit_login_desc=您的帐户被禁止登录,请联系网站管理员。
resent_limit_prompt=对不起,您请求发送激活邮件过于频繁,请等待 3 分钟后再试!
has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 <b>%s</b> 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。
resend_mail=单击此处重新发送确认邮件
@@ -162,6 +162,7 @@ reset_password=重置密码
invalid_code=对不起,您的确认代码已过期或已失效。
reset_password_helper=单击此处重置密码
password_too_short=密码长度不能少于 6 位!
non_local_account=非本地类型的帐户无法通过 Gogs 修改密码。
[mail]
activate_account=请激活您的帐户
@@ -224,8 +225,7 @@ org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转
target_branch_not_exist=目标分支不存在。
[user]
change_avatar=到 gravatar.com 上修改您的头像
change_custom_avatar=到个人设置中修改头像
change_avatar=修改头像
join_on=加入于
repositories=仓库列表
activity=公开活动
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
[settings]
profile=个人信息
password=修改密码
avatar=头像设置
ssh_keys=管理 SSH 密钥
social=社交帐号绑定
applications=管理授权应用
@@ -261,6 +262,8 @@ change_username_prompt=该操作将会影响到所有与您帐户有关的链接
continue=继续操作
cancel=取消操作
lookup_avatar_by_mail=通过邮箱地址获取头像
federated_avatar_lookup=Federated Avatar 查找
enable_custom_avatar=启动自定义头像
choose_new_avatar=选择新的头像
update_avatar=更新头像设置
@@ -347,7 +350,7 @@ fork_from=派生自
fork_visiblity_helper=派生仓库无法修改可见性
repo_desc=仓库描述
repo_lang=仓库语言
repo_lang_helper=选择 .gitignore 文件
repo_gitignore_helper=选择 .gitignore 模板
license=授权许可
license_helper=请选择授权许可文件
readme=自述文档
@@ -355,6 +358,8 @@ readme_helper=请选择自述文档模板
auto_init=使用选定的文件和模板初始化仓库
create_repo=创建仓库
default_branch=默认分支
mirror_prune=修剪
mirror_prune_desc=当远程追踪的引用被删除时本地也同步删除
mirror_interval=镜像同步周期(小时)
mirror_address=镜像地址
mirror_address_desc=请在镜像地址中写入必要的用户凭据信息。
@@ -412,6 +417,7 @@ file_raw=原始文件
file_history=文件历史
file_view_raw=查看原始文件
file_permalink=永久链接
file_too_large=文件过大导致无法显示
commits.commits=次代码提交
commits.search=搜索提交历史
@@ -465,7 +471,8 @@ issues.next=下一页
issues.open_title=开启中
issues.closed_title=已关闭
issues.num_comments=%d 条评论
issues.commented_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 评论`
issues.commented_at=`评论于 <a href="#%s">%s</a>`
issues.delete_comment_confirm=您确定要删除该条评论吗?
issues.no_content=这个人很懒,什么都没留下。
issues.close_issue=关闭
issues.close_comment_issue=评论并关闭
@@ -566,6 +573,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=基本设置
@@ -573,13 +584,18 @@ settings.site=官方网站
settings.update_settings=更新仓库设置
settings.change_reponame_prompt=该操作将会影响到所有与该仓库有关的链接
settings.advanced_settings=高级设置
settings.wiki_desc=启用 Wiki 以允许用户协作文档
settings.wiki_desc=启用 Wiki 系统
settings.use_internal_wiki=使用内置 Wiki 系统
settings.use_external_wiki=使用外部 Wiki
settings.external_wiki_url=外部 Wiki 链接
settings.external_wiki_url_desc=当访问者单击分页标签时,将会被重定向到该链接。
settings.issues_desc=启用内置的轻量级工单管理系统
settings.issues_desc=启用工单管理系统
settings.use_internal_issue_tracker=使用内置的轻量级工单管理系统
settings.use_external_issue_tracker=使用外部的工单管理系统
settings.tracker_url_format=外部工单管理系统的 URL 格式
settings.tracker_issue_style=外部工单管理系统命名风格:
settings.tracker_issue_style.numeric=纯数字形式
settings.tracker_issue_style.alphanumeric=英文字母数字组合形式
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
settings.pulls_desc=启用合并请求以接受社区贡献
settings.danger_zone=危险操作区
@@ -602,9 +618,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 +702,8 @@ diff.show_unified_view=合并视图
diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二进制
diff.view_file=查看文件
diff.file_suppressed=文件差异内容过多而无法显示
diff.too_many_files=部分文件因为文件数量过多而无法显示
release.releases=版本发布
release.new_release=发布新版
@@ -718,6 +734,7 @@ release.deletion=删除版本发布操作
release.deletion_desc=删除该版本发布将会移除相应的 Git 标签。是否继续?
release.deletion_success=版本发布删除成功!
release.tag_name_already_exist=已经存在使用相同标签进行发布的版本。
release.tag_name_invalid=标签名称不是有效的名称。
release.downloads=下载附件
[org]
@@ -885,6 +902,7 @@ users.edit_account=编辑用户信息
users.max_repo_creation=最大允许创建仓库数量
users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值)
users.is_activated=该用户已被激活
users.prohibit_login=该帐户被禁止登录
users.is_admin=该用户具有管理员权限
users.allow_git_hook=该用户具有创建 Git 钩子的权限
users.allow_import_local=该用户具有导入本地仓库的权限
@@ -915,6 +933,7 @@ auths.enabled=已启用
auths.updated=最后更新时间
auths.auth_type=认证类型
auths.auth_name=认证名称
auths.security_protocol=安全协议
auths.domain=域名
auths.host=主机地址
auths.port=主机端口
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL 模式
config.db_ssl_mode_helper=(仅限 "postgres" 使用)
config.db_path=数据库路径
config.db_path_helper=(用于 "sqlite3" 和 "tidb"
config.service_config=服务配置
config.register_email_confirm=注册邮件确认
config.disable_register=关闭注册功能
@@ -999,10 +1019,12 @@ config.disable_key_size_check=禁用密钥最小长度检查
config.enable_captcha=启用验证码服务
config.active_code_lives=激活用户链接有效期
config.reset_password_code_lives=重置密码链接有效期
config.webhook_config=Web 钩子配置
config.queue_length=队列长度
config.deliver_timeout=推送超时
config.skip_tls_verify=忽略 TLS 验证
config.mailer_config=邮件配置
config.mailer_enabled=启用服务
config.mailer_disable_helo=禁用 HELO 操作
@@ -1012,12 +1034,15 @@ config.mailer_user=发送者帐号
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 配置
config.cache_adapter=Cache 适配器
config.cache_interval=Cache 周期
config.cache_conn=Cache 连接字符串
config.session_config=Session 配置
config.session_provider=Session 提供者
config.provider_config=提供者配置
@@ -1027,9 +1052,24 @@ config.gc_interval_time=GC 周期
config.session_life_time=Session 生命周期
config.https_only=仅限 HTTPS
config.cookie_life_time=Cookie 生命周期
config.picture_config=图片配置
config.picture_service=图片服务
config.disable_gravatar=禁用 Gravatar 头像
config.enable_federated_avatar=启用 Federated Avatars
config.git_config=Git 配置
config.git_disable_diff_highlight=禁用差异对比语法高亮
config.git_max_diff_lines=差异对比显示的最大行数(单个文件)
config.git_max_diff_line_characters=差异对比显示的最大字符数(单行)
config.git_max_diff_files=差异对比显示的最大文件数
config.git_gc_args=GC 参数
config.git_migrate_timeout=迁移操作超时
config.git_mirror_timeout=镜像更新操作超时
config.git_clone_timeout=克隆操作超时
config.git_pull_timeout=拉取操作超时
config.git_gc_timeout=GC 操作超时
config.log_config=日志配置
config.log_mode=日志模式

130
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=電子郵件服務設定
@@ -103,6 +96,8 @@ offline_mode=啓用離線模式
offline_mode_popup=在部署模式下也禁用從 CDN 獲取文件,所有的資源將從本地伺服器獲取。
disable_gravatar=禁用 Gravatar 服務
disable_gravatar_popup=禁用 Gravatar 和自定義源,僅使用由用戶上傳或默認的頭像。
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=禁止用戶自主註冊
disable_registration_popup=禁止用戶自主註冊功能,只有管理員可以添加帳號。
enable_captcha=啟用驗證碼服務
@@ -124,13 +119,14 @@ 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=用戶名或郵箱
password_holder=密碼
switch_dashboard_context=切換控制面版用戶
my_repos=我的倉庫
show_more_repos=Show more repositories...
collaborative_repos=參與協作的倉庫
my_orgs=我的組織
my_mirrors=我的鏡像
@@ -140,6 +136,8 @@ issues.in_your_repos=屬於該用戶倉庫的
[explore]
repos=探索倉庫
users=用戶
search=搜索
[auth]
create_new_account=創建帳戶
@@ -153,6 +151,8 @@ forget_password=忘記密碼?
sign_up_now=還沒帳戶?馬上註冊。
confirmation_mail_sent_prompt=一封新的確認郵件已經被發送至 <b>%s</b>,請檢查您的收件箱並在 %d 小時內完成確認註冊操作。
active_your_account=激活您的帳戶
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=對不起,您請求發送激活郵件過於頻繁,請等待 3 分鐘後再試!
has_unconfirmed_mail=%s 您好,您有一封發送至( <b>%s</b>) 但未被確認的郵件。如果您未收到激活郵件,或需要重新發送,請單擊下方的按鈕。
resend_mail=單擊此處重新發送確認郵件
@@ -162,6 +162,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 +225,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=公開活動
@@ -241,6 +241,7 @@ form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
[settings]
profile=個人信息
password=修改密碼
avatar=Avatar
ssh_keys=管理 SSH 密鑰
social=社交帳號綁定
applications=管理授權應用
@@ -261,10 +262,12 @@ change_username_prompt=該操作將會影響到所有與您帳戶有關的鏈接
continue=繼續操作
cancel=取消操作
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
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=您的頭像設置更新成功!
@@ -347,7 +350,7 @@ fork_from=派生自
fork_visiblity_helper=派生倉庫無法修改可見性。
repo_desc=倉庫描述
repo_lang=倉庫語言
repo_lang_helper=請選擇 .gitignore 文件
repo_gitignore_helper=Select .gitignore templates
license=授權許可
license_helper=請選擇授權許可文件
readme=Readme
@@ -355,6 +358,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 +392,7 @@ unwatch=取消關注
watch=關註
unstar=取消讚好
star=讚好
fork=派生
fork=複刻
no_desc=暫無描述
quick_guide=快速幫助
@@ -412,6 +417,7 @@ file_raw=原始文件
file_history=文件歷史
file_view_raw=查看原始文件
file_permalink=永久連結
file_too_large=This file is too large to be shown
commits.commits=次代碼提交
commits.search=搜索提交歷史
@@ -465,7 +471,8 @@ issues.next=下一頁
issues.open_title=開啟中
issues.closed_title=已關閉
issues.num_comments=%d 條評論
issues.commented_at=`於 <a id="%[1]s" href="#%[1]s">%[2]s</a> 評論`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=尚未有任何內容
issues.close_issue=關閉
issues.close_comment_issue=關閉及評論
@@ -476,7 +483,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 +500,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 +564,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 +573,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=基本設置
@@ -573,19 +584,24 @@ settings.site=官方網站
settings.update_settings=更新倉庫設置
settings.change_reponame_prompt=該操作將會影響到所有與該倉庫有關的鏈接
settings.advanced_settings=高級設置
settings.wiki_desc=啟用 Wiki 以允許用戶協作文檔
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=使用外部 wiki
settings.external_wiki_url=外部 Wiki 連結
settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到 URL。
settings.issues_desc=啟用內置的輕量級問題管理系統
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
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
settings.tracker_issue_style.alphanumeric=Alphanumeric
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 +610,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 +627,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 +702,8 @@ diff.show_unified_view=統一視圖
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二進制
diff.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=版本發佈
release.new_release=發佈新版本
@@ -718,6 +734,7 @@ release.deletion=刪除版本發布操作
release.deletion_desc=刪除該版本發布將會移除相應的 Git 標籤。是否繼續?
release.deletion_success=版本發布刪除成功!
release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
release.tag_name_invalid=Tag name is not valid.
release.downloads=下載附件
[org]
@@ -885,6 +902,7 @@ users.edit_account=編輯用戶信息
users.max_repo_creation=最大儲存庫新增限制
users.max_repo_creation_desc=(設定 -1 使用全域預設限制)
users.is_activated=該用戶已被激活
users.prohibit_login=This account is prohibited to login
users.is_admin=該用戶具有管理員權限
users.allow_git_hook=該帳戶具有創建 Git 鉤子的權限
users.allow_import_local=該用戶具有導入本地倉庫的權限
@@ -915,6 +933,7 @@ auths.enabled=已啟用
auths.updated=最後更新時間
auths.auth_type=認證類型
auths.auth_name=認證名稱
auths.security_protocol=Security Protocol
auths.domain=域名
auths.host=主機地址
auths.port=主機端口
@@ -968,17 +987,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=數據庫類型
@@ -989,6 +1008,7 @@ config.db_ssl_mode=SSL 模式
config.db_ssl_mode_helper=(僅限 "postgres" 使用)
config.db_path=數據庫路徑
config.db_path_helper=(用於 "sqlite3" 和 "tidb"
config.service_config=服務配置
config.register_email_confirm=註冊電子郵件確認
config.disable_register=關閉註冊功能
@@ -999,25 +1019,30 @@ config.disable_key_size_check=禁用密鑰最小長度檢查
config.enable_captcha=啟用驗證碼服務
config.active_code_lives=激活用戶連結有效期
config.reset_password_code_lives=重置密碼連結有效期
config.webhook_config=Web 鉤子配置
config.queue_length=隊列長度
config.deliver_timeout=推送超時
config.skip_tls_verify=忽略 TLS 驗證
config.mailer_config=郵件配置
config.mailer_enabled=啟用服務
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 配置
config.cache_adapter=Cache 適配器
config.cache_interval=Cache 周期
config.cache_conn=Cache 連接字符串
config.session_config=Session 配置
config.session_provider=Session 提供者
config.provider_config=提供者配置
@@ -1027,9 +1052,24 @@ config.gc_interval_time=垃圾收集周期
config.session_life_time=Session 生命周期
config.https_only=僅限 HTTPS
config.cookie_life_time=Cookie 生命周期
config.picture_config=圖片配置
config.picture_service=圖片服務
config.disable_gravatar=禁用 Gravatar 頭像
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=日誌配置
config.log_mode=日誌模式

1143
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
```
@@ -69,11 +71,29 @@ Most of settings are obvious and easy to understand, but there are some settings
- **HTTP Port**: Use port you want Gogs to listen on inside Docker container. For example, your Gogs listens on `3000` inside Docker, and you expose it by `10080:3000`, but you still use `3000` for this value.
- **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values (e.g. `http://192.168.99.100:10080/`).
Full documentation of application settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
Full documentation of application settings can be found [here](https://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

150
glide.lock generated Normal file
View File

@@ -0,0 +1,150 @@
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: 0b58b37b664c21f3010e836f1b931e1d0b0b0685
- name: github.com/go-xorm/core
version: 5bf745d7d163f4380e6c2bba8c4afa60534dd087
- name: github.com/go-xorm/xorm
version: c6c705684057842d9854e8299dd51abb06ae29f5
- name: github.com/gogits/chardet
version: 2404f777256163ea3eadb273dada5dcb037993c0
- name: github.com/gogits/cron
version: 7f3990acf1833faa5ebd0e86f0a4c72a4b5eba3c
- name: github.com/gogits/git-module
version: 18dd87dc5eac9ee7076133c8363803f2192d5713
- name: github.com/gogits/go-gogs-client
version: d1020b4da5474f7533f5b11084dcfd5536cf2e71
- 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: 80f8150043c80fb52dee6bc863a709cdac7ec8f8
subpackages:
- oid
- name: github.com/mattn/go-sqlite3
version: e118d4451349065b8e7ce0f0af32e033995363f8
- name: github.com/mcuadros/go-version
version: d52711f8d6bea8dc01efafdb68ad95a4e2606630
- name: github.com/microcosm-cc/bluemonday
version: 9dc199233bf72cc1aad9b61f73daf2f0075b9ee4
- name: github.com/msteinert/pam
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
- name: github.com/nfnt/resize
version: 891127d8d1b52734debe1b3c3d7e747502b6c366
- name: github.com/russross/blackfriday
version: 93622da34e54fb6529bfb7c57e710f37a8d9cbd8
- name: github.com/satori/go.uuid
version: 0aa62d5ddceb50dbcb909d790b5345affd3669b6
- name: github.com/sergi/go-diff
version: ec7fdbb58eb3e300c8595ad5ac74a5aa50019cc7
subpackages:
- diffmatchpatch
- name: github.com/strk/go-libravatar
version: 5eed7bff870ae19ef51c5773dbc8f3e9fcbd0982
- 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: bc89c496413265e715159bdc8478ee9a92fdc265
subpackages:
- ssh
- curve25519
- ed25519
- ed25519/internal/edwards25519
- name: golang.org/x/net
version: 57bfaa875b96fb91b4766077f34470528d4b03e9
subpackages:
- html
- html/charset
- html/atom
- name: golang.org/x/sys
version: a646d33e2ee3172a661fc09bca23bb4889a41bc8
subpackages:
- windows/svc
- windows
- name: golang.org/x/text
version: 2910a502d2bf9e43193af9d68ca516529614eed3
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: cf53f9204df4fbdd7ec4164b57fa6184ba168292
- name: gopkg.in/ldap.v2
version: d0a5ced67b4dc310b9158d63a2c6f9c5ec13f105
- name: gopkg.in/macaron.v1
version: 7564489a79f3f96b7ac8034652b35eeebb468eb4
- name: gopkg.in/redis.v2
version: e6179049628164864e6e84e973cfb56335748dea
devImports: []

58
glide.yaml Normal file
View File

@@ -0,0 +1,58 @@
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: github.com/strk/go-libravatar
- 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.71.0809"
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.
@@ -40,11 +67,11 @@ func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
return mode, nil
}
if u.Id == repo.OwnerID {
if u.ID == repo.OwnerID {
return ACCESS_MODE_OWNER, nil
}
a := &Access{UserID: u.Id, RepoID: repo.ID}
a := &Access{UserID: u.ID, RepoID: repo.ID}
if has, err := e.Get(a); !has || err != nil {
return mode, err
}
@@ -70,7 +97,7 @@ func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) {
// GetRepositoryAccesses finds all repositories with their access mode where a user has access but does not own.
func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
accesses := make([]*Access, 0, 10)
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
if err := x.Find(&accesses, &Access{UserID: u.ID}); err != nil {
return nil, err
}
@@ -86,7 +113,7 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
}
if err = repo.GetOwner(); err != nil {
return nil, err
} else if repo.OwnerID == u.Id {
} else if repo.OwnerID == u.ID {
continue
}
repos[repo] = access.Mode
@@ -94,23 +121,17 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
return repos, nil
}
// GetAccessibleRepositories finds all repositories where a user has access but does not own.
func (u *User) GetAccessibleRepositories() ([]*Repository, error) {
accesses := make([]*Access, 0, 10)
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
return nil, err
// GetAccessibleRepositories finds repositories which the user has access but does not own.
// If limit is smaller than 1 means returns all found results.
func (user *User) GetAccessibleRepositories(limit int) (repos []*Repository, _ error) {
sess := x.Where("owner_id !=? ", user.ID).Desc("updated_unix")
if limit > 0 {
sess.Limit(limit)
repos = make([]*Repository, 0, limit)
} else {
repos = make([]*Repository, 0, 10)
}
if len(accesses) == 0 {
return []*Repository{}, nil
}
repoIDs := make([]int64, 0, len(accesses))
for _, access := range accesses {
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, sess.Join("INNER", "access", "access.user_id = ? AND access.repo_id = repository.id", user.ID).Find(&repos)
}
func maxAccessMode(modes ...AccessMode) AccessMode {
@@ -200,7 +221,7 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err
return fmt.Errorf("getMembers '%d': %v", t.ID, err)
}
for _, m := range t.Members {
accessMap[m.Id] = maxAccessMode(accessMap[m.Id], t.Authorize)
accessMap[m.ID] = maxAccessMode(accessMap[m.ID], t.Authorize)
}
}

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().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()
}
}
@@ -179,7 +184,7 @@ func (a *Action) GetIssueContent() string {
func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: u.Id,
ActUserID: u.ID,
ActUserName: u.Name,
ActEmail: u.Email,
OpType: ACTION_CREATE_REPO,
@@ -188,7 +193,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", u.Id, repo.ID, err)
return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err)
}
log.Trace("action.newRepoAction: %s/%s", u.Name, repo.Name)
@@ -202,7 +207,7 @@ func NewRepoAction(u *User, repo *Repository) (err error) {
func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserID: actUser.ID,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
OpType: ACTION_RENAME_REPO,
@@ -229,10 +234,13 @@ func issueIndexTrimRight(c rune) bool {
}
type PushCommit struct {
Sha1 string
Message string
AuthorEmail string
AuthorName string
Sha1 string
Message string
AuthorEmail string
AuthorName string
CommitterEmail string
CommitterName string
Timestamp time.Time
}
type PushCommits struct {
@@ -251,21 +259,33 @@ func NewPushCommits() *PushCommits {
func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit {
commits := make([]*api.PayloadCommit, len(pc.Commits))
for i, cmt := range pc.Commits {
author_username := ""
author, err := GetUserByEmail(cmt.AuthorEmail)
for i, commit := range pc.Commits {
authorUsername := ""
author, err := GetUserByEmail(commit.AuthorEmail)
if err == nil {
author_username = author.Name
authorUsername = author.Name
}
committerUsername := ""
committer, err := GetUserByEmail(commit.CommitterEmail)
if err == nil {
// TODO: check errors other than email not found.
committerUsername = committer.Name
}
commits[i] = &api.PayloadCommit{
ID: cmt.Sha1,
Message: cmt.Message,
URL: fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1),
ID: commit.Sha1,
Message: commit.Message,
URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1),
Author: &api.PayloadAuthor{
Name: cmt.AuthorName,
Email: cmt.AuthorEmail,
UserName: author_username,
Name: commit.AuthorName,
Email: commit.AuthorEmail,
UserName: authorUsername,
},
Committer: &api.PayloadCommitter{
Name: commit.CommitterName,
Email: commit.CommitterEmail,
UserName: committerUsername,
},
Timestamp: commit.Timestamp,
}
}
return commits
@@ -283,7 +303,7 @@ func (push *PushCommits) AvatarLink(email string) string {
log.Error(4, "GetUserByEmail: %v", err)
}
} else {
push.avatars[email] = u.AvatarLink()
push.avatars[email] = u.RelAvatarLink()
}
}
@@ -465,8 +485,8 @@ func CommitRepoAction(
}
}
if len(commit.Commits) > setting.FeedMaxCommitNum {
commit.Commits = commit.Commits[:setting.FeedMaxCommitNum]
if len(commit.Commits) > setting.UI.FeedMaxCommitNum {
commit.Commits = commit.Commits[:setting.UI.FeedMaxCommitNum]
}
bs, err := json.Marshal(commit)
@@ -477,14 +497,14 @@ func CommitRepoAction(
refName := git.RefEndName(refFullName)
if err = NotifyWatchers(&Action{
ActUserID: u.Id,
ActUserID: u.ID,
ActUserName: userName,
ActEmail: actEmail,
OpType: opType,
Content: string(bs),
RepoID: repo.ID,
RepoUserName: repoUserName,
RepoName: repoName,
RepoName: repo.Name,
RefName: refName,
IsPrivate: repo.IsPrivate,
}); err != nil {
@@ -501,7 +521,7 @@ func CommitRepoAction(
}
payloadSender := &api.PayloadUser{
UserName: pusher.Name,
ID: pusher.Id,
ID: pusher.ID,
AvatarUrl: pusher.AvatarLink(),
}
@@ -512,7 +532,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,
@@ -548,7 +568,7 @@ func CommitRepoAction(
func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserID: actUser.ID,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
OpType: ACTION_TRANSFER_REPO,
@@ -556,14 +576,14 @@ 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)
return fmt.Errorf("notify watchers '%d/%d': %v", actUser.ID, repo.ID, err)
}
// Remove watch for organization.
if repo.Owner.IsOrganization() {
if err = watchRepo(e, repo.Owner.Id, repo.ID, false); err != nil {
if err = watchRepo(e, repo.Owner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watch repository: %v", err)
}
}
@@ -579,7 +599,7 @@ func TransferRepoAction(actUser, oldOwner, newOwner *User, repo *Repository) err
func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Issue) error {
return notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserID: actUser.ID,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
OpType: ACTION_MERGE_PULL_REQUEST,
@@ -597,21 +617,22 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
}
// GetFeeds returns action list of given user in given context.
// userID is the user who's requesting, ctxUserID is the user/org that is requested.
// userID can be -1, if isProfile is true or in order to skip the permission check.
func GetFeeds(ctxUserID, userID, offset int64, isProfile bool) ([]*Action, error) {
// actorID is the user who's requesting, ctxUserID is the user/org that is requested.
// actorID can be -1 when isProfile is true or to skip the permission check.
func GetFeeds(ctxUser *User, actorID, offset int64, isProfile bool) ([]*Action, error) {
actions := make([]*Action, 0, 20)
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", ctxUserID)
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id = ?", ctxUser.ID)
if isProfile {
sess.And("is_private=?", false).And("act_user_id=?", ctxUserID)
} else if ctxUserID != -1 {
ctxUser := &User{Id: ctxUserID}
if err := ctxUser.GetUserRepositories(userID); err != nil {
return nil, err
sess.And("is_private = ?", false).And("act_user_id = ?", ctxUser.ID)
} else if actorID != -1 && ctxUser.IsOrganization() {
// FIXME: only need to get IDs here, not all fields of repository.
repos, _, err := ctxUser.GetUserRepositories(actorID, 1, ctxUser.NumRepos)
if err != nil {
return nil, fmt.Errorf("GetUserRepositories: %v", err)
}
var repoIDs []int64
for _, repo := range ctxUser.Repos {
for _, repo := range repos {
repoIDs = append(repoIDs, repo.ID)
}

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().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")
}
// ________ .__ __ .__
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
@@ -375,7 +387,7 @@ func IsErrReleaseAlreadyExist(err error) bool {
}
func (err ErrReleaseAlreadyExist) Error() string {
return fmt.Sprintf("Release tag already exist [tag_name: %s]", err.TagName)
return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName)
}
type ErrReleaseNotExist struct {
@@ -389,7 +401,20 @@ func IsErrReleaseNotExist(err error) bool {
}
func (err ErrReleaseNotExist) Error() string {
return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
}
type ErrInvalidTagName struct {
TagName string
}
func IsErrInvalidTagName(err error) bool {
_, ok := err.(ErrInvalidTagName)
return ok
}
func (err ErrInvalidTagName) Error() string {
return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName)
}
// __________ .__
@@ -409,7 +434,7 @@ func IsErrBranchNotExist(err error) bool {
}
func (err ErrBranchNotExist) Error() string {
return fmt.Sprintf("Branch does not exist [name: %s]", err.Name)
return fmt.Sprintf("branch does not exist [name: %s]", err.Name)
}
// __ __ ___. .__ __
@@ -508,7 +533,8 @@ func (err ErrCommentNotExist) Error() string {
// \/ \/ \/ \/
type ErrLabelNotExist struct {
ID int64
LabelID int64
RepoID int64
}
func IsErrLabelNotExist(err error) bool {
@@ -517,7 +543,7 @@ func IsErrLabelNotExist(err error) bool {
}
func (err ErrLabelNotExist) Error() string {
return fmt.Sprintf("label does not exist [id: %d]", err.ID)
return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID)
}
// _____ .__.__ __

View File

@@ -26,6 +26,7 @@ import (
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template/highlight"
)
@@ -48,10 +49,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 {
@@ -70,17 +71,18 @@ var (
)
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
var buf bytes.Buffer
buf := bytes.NewBuffer(nil)
for i := range diffs {
if diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD {
switch {
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD:
buf.Write(addedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
} else if diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL {
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL:
buf.Write(removedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
} else if diffs[i].Type == diffmatchpatch.DiffEqual {
case diffs[i].Type == diffmatchpatch.DiffEqual:
buf.WriteString(html.EscapeString(diffs[i].Text))
}
}
@@ -90,62 +92,86 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM
// get an specific line by type (add or del) and file line number
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
difference := 0
var (
difference = 0
addCount = 0
delCount = 0
matchDiffLine *DiffLine
)
LOOP:
for _, diffLine := range diffSection.Lines {
if diffLine.Type == DIFF_LINE_PLAIN {
// get the difference of line numbers between ADD and DEL versions
switch diffLine.Type {
case DIFF_LINE_ADD:
addCount++
case DIFF_LINE_DEL:
delCount++
default:
if matchDiffLine != nil {
break LOOP
}
difference = diffLine.RightIdx - diffLine.LeftIdx
continue
addCount = 0
delCount = 0
}
if lineType == DIFF_LINE_DEL {
switch lineType {
case DIFF_LINE_DEL:
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
return diffLine
matchDiffLine = diffLine
}
} else if lineType == DIFF_LINE_ADD {
case DIFF_LINE_ADD:
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
return diffLine
matchDiffLine = diffLine
}
}
}
if addCount == delCount {
return matchDiffLine
}
return nil
}
var diffMatchPatch = diffmatchpatch.New()
func init() {
diffMatchPatch.DiffEditCost = 100
}
// computes inline diff for the given line
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
var compareDiffLine *DiffLine
var diff1, diff2 string
getDefaultReturn := func() template.HTML {
if setting.Git.DisableDiffHighlight {
return template.HTML(html.EscapeString(diffLine.Content[1:]))
}
// just compute diff for adds and removes
if diffLine.Type != DIFF_LINE_ADD && diffLine.Type != DIFF_LINE_DEL {
return getDefaultReturn()
}
var (
compareDiffLine *DiffLine
diff1 string
diff2 string
)
// try to find equivalent diff line. ignore, otherwise
if diffLine.Type == DIFF_LINE_ADD {
switch diffLine.Type {
case DIFF_LINE_ADD:
compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
if compareDiffLine == nil {
return getDefaultReturn()
return template.HTML(html.EscapeString(diffLine.Content[1:]))
}
diff1 = compareDiffLine.Content
diff2 = diffLine.Content
} else {
case DIFF_LINE_DEL:
compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
if compareDiffLine == nil {
return getDefaultReturn()
return template.HTML(html.EscapeString(diffLine.Content[1:]))
}
diff1 = diffLine.Content
diff2 = compareDiffLine.Content
default:
return template.HTML(html.EscapeString(diffLine.Content[1:]))
}
dmp := diffmatchpatch.New()
diffRecord := dmp.DiffMain(diff1[1:], diff2[1:], true)
diffRecord = dmp.DiffCleanupSemantic(diffRecord)
diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true)
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
return diffToHTML(diffRecord, diffLine.Type)
}
@@ -160,7 +186,9 @@ type DiffFile struct {
IsDeleted bool
IsBin bool
IsRenamed bool
IsSubmodule bool
Sections []*DiffSection
IsIncomplete bool
}
func (diffFile *DiffFile) GetType() int {
@@ -174,6 +202,7 @@ func (diffFile *DiffFile) GetHighlightClass() string {
type Diff struct {
TotalAddition, TotalDeletion int
Files []*DiffFile
IsIncomplete bool
}
func (diff *Diff) NumFiles() int {
@@ -182,7 +211,8 @@ func (diff *Diff) NumFiles() int {
const DIFF_HEAD = "diff --git "
func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
// TODO: move this function to gogits/git-module
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
var (
diff = &Diff{Files: make([]*DiffFile, 0)}
@@ -193,15 +223,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 +243,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,8 +327,14 @@ 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.
// Check file diff type and is submodule.
for {
line, err := input.ReadString('\n')
if err != nil {
@@ -332,6 +361,9 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
curFile.Name = b
}
if curFile.Type > 0 {
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
break
}
}
@@ -366,13 +398,13 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
return diff, nil
}
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxlines int) (*Diff, error) {
repo, err := git.OpenRepository(repoPath)
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return nil, err
}
commit, err := repo.GetCommit(afterCommitID)
commit, err := gitRepo.GetCommit(afterCommitID)
if err != nil {
return nil, err
}
@@ -405,7 +437,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 +449,59 @@ 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)
type RawDiffType string
const (
RAW_DIFF_NORMAL RawDiffType = "diff"
RAW_DIFF_PATCH RawDiffType = "patch"
)
// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
// TODO: move this function to gogits/git-module
func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}
commit, err := repo.GetCommit(commitID)
if err != nil {
return fmt.Errorf("GetCommit: %v", err)
}
var cmd *exec.Cmd
switch diffType {
case RAW_DIFF_NORMAL:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "show", commitID)
} else {
c, _ := commit.Parent(0)
cmd = exec.Command("git", "diff", "-M", c.ID.String(), commitID)
}
case RAW_DIFF_PATCH:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", "--root", commitID)
} else {
c, _ := commit.Parent(0)
query := fmt.Sprintf("%s...%s", commitID, c.ID.String())
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", query)
}
default:
return fmt.Errorf("invalid diffType: %s", diffType)
}
stderr := new(bytes.Buffer)
cmd.Dir = repoPath
cmd.Stdout = writer
cmd.Stderr = stderr
if err = cmd.Run(); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
return nil
}
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacteres, maxFiles)
}

View File

@@ -33,38 +33,3 @@ func TestDiffToHTML(t *testing.T) {
dmp.Diff{dmp.DiffEqual, " biz"},
}, DIFF_LINE_DEL))
}
// test if GetLine is return the correct lines
func TestGetLine(t *testing.T) {
ds := DiffSection{Lines: []*DiffLine{
&DiffLine{LeftIdx: 28, RightIdx: 28, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 29, RightIdx: 29, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 30, RightIdx: 30, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 31, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 0, RightIdx: 31, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 32, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 32, RightIdx: 33, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 33, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 34, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 35, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 36, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 0, RightIdx: 34, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 35, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 36, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 37, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 37, RightIdx: 38, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 38, RightIdx: 39, Type: DIFF_LINE_PLAIN},
}}
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 31), ds.Lines[4])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 31), ds.Lines[3])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 33), ds.Lines[11])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 34), ds.Lines[12])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 35), ds.Lines[13])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 36), ds.Lines[14])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 34), ds.Lines[7])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 35), ds.Lines[8])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 36), ds.Lines[9])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 37), ds.Lines[10])
}

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,41 @@ 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().Unix()
i.UpdatedUnix = i.CreatedUnix
}
func (i *Issue) BeforeUpdate() {
i.UpdatedUnix = time.Now().Unix()
i.DeadlineUnix = i.Deadline.Unix()
}
func (issue *Issue) loadAttributes(e Engine) (err error) {
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
if err != nil {
return fmt.Errorf("getRepositoryByID: %v", err)
}
return nil
}
func (issue *Issue) LoadAttributes() error {
return issue.loadAttributes(x)
}
func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -74,6 +100,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 +126,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 +136,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 +151,29 @@ 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 {
var path string
if issue.IsPull {
path = "pulls"
} else {
path = "issues"
}
return fmt.Sprintf("%s/%s/%d", issue.Repo.FullLink(), path, 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)
}
@@ -130,7 +187,7 @@ func (i *Issue) addLabel(e *xorm.Session, label *Label) error {
return newIssueLabel(e, i, label)
}
// AddLabel adds new label to issue by given ID.
// AddLabel adds a new label to the issue.
func (i *Issue) AddLabel(label *Label) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
@@ -145,57 +202,76 @@ func (i *Issue) AddLabel(label *Label) (err error) {
return sess.Commit()
}
func (i *Issue) getLabels(e Engine) (err error) {
if len(i.Labels) > 0 {
func (issue *Issue) addLabels(e *xorm.Session, labels []*Label) error {
return newIssueLabels(e, issue, labels)
}
// AddLabels adds a list of new labels to the issue.
func (issue *Issue) AddLabels(labels []*Label) error {
return NewIssueLabels(issue, labels)
}
func (issue *Issue) getLabels(e Engine) (err error) {
if len(issue.Labels) > 0 {
return nil
}
i.Labels, err = getLabelsByIssueID(e, i.ID)
issue.Labels, err = getLabelsByIssueID(e, issue.ID)
if err != nil {
return fmt.Errorf("getLabelsByIssueID: %v", err)
}
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)
func (issue *Issue) removeLabel(e *xorm.Session, label *Label) error {
return deleteIssueLabel(e, issue, label)
}
// RemoveLabel removes a label from issue by given ID.
func (i *Issue) RemoveLabel(label *Label) (err error) {
func (issue *Issue) RemoveLabel(label *Label) (err error) {
return DeleteIssueLabel(issue, label)
}
func (issue *Issue) clearLabels(e *xorm.Session) (err error) {
if err = issue.getLabels(e); err != nil {
return fmt.Errorf("getLabels: %v", err)
}
for i := range issue.Labels {
if err = issue.removeLabel(e, issue.Labels[i]); err != nil {
return fmt.Errorf("removeLabel: %v", err)
}
}
return nil
}
func (issue *Issue) ClearLabels() (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = i.removeLabel(sess, label); err != nil {
if err = issue.clearLabels(sess); err != nil {
return err
}
return sess.Commit()
}
func (i *Issue) ClearLabels() (err error) {
// ReplaceLabels removes all current labels and add new labels to the issue.
func (issue *Issue) ReplaceLabels(labels []*Label) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = i.getLabels(sess); err != nil {
return err
}
for idx := range i.Labels {
if err = i.removeLabel(sess, i.Labels[idx]); err != nil {
return err
}
if err = issue.clearLabels(sess); err != nil {
return fmt.Errorf("clearLabels: %v", err)
} else if err = issue.addLabels(sess, labels); err != nil {
return fmt.Errorf("addLabels: %v", err)
}
return sess.Commit()
@@ -285,6 +361,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 +396,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 +437,7 @@ func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64,
}
}
return nil
return issue.loadAttributes(e)
}
// NewIssue creates new issue with labels for repository.
@@ -359,9 +452,13 @@ 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,
ActUserID: issue.Poster.ID,
ActUserName: issue.Poster.Name,
ActEmail: issue.Poster.Email,
OpType: ACTION_CREATE_ISSUE,
@@ -371,11 +468,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 +500,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 +515,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 +527,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,7 +547,11 @@ type IssuesOptions struct {
// Issues returns a list of issues by given conditions.
func Issues(opts *IssuesOptions) ([]*Issue, error) {
sess := x.Limit(setting.IssuePagingNum, (opts.Page-1)*setting.IssuePagingNum)
if opts.Page <= 0 {
opts.Page = 1
}
sess := x.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
if opts.RepoID > 0 {
sess.Where("issue.repo_id=?", opts.RepoID).And("issue.is_closed=?", opts.IsClosed)
@@ -458,7 +560,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,46 +579,37 @@ 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.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)
issues := make([]*Issue, 0, setting.UI.IssuePagingNum)
return issues, sess.Find(&issues)
}
@@ -569,7 +662,7 @@ func newIssueUsers(e *xorm.Session, repo *Repository, issue *Issue) error {
isNeedAddPoster := true
for _, u := range users {
iu.ID = 0
iu.UID = u.Id
iu.UID = u.ID
iu.IsPoster = iu.UID == issue.PosterID
if isNeedAddPoster && iu.IsPoster {
isNeedAddPoster = false
@@ -629,18 +722,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 +748,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() {
ids = append(ids, user.ID)
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 +821,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 +832,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 +894,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("poster_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 +1023,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 +1064,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.Unix()
}
func (m *Milestone) BeforeUpdate() {
@@ -965,25 +1085,38 @@ func (m *Milestone) BeforeUpdate() {
} else {
m.Completeness = 0
}
m.DeadlineUnix = m.Deadline.Unix()
m.ClosedDateUnix = m.ClosedDate.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.
@@ -1040,10 +1173,10 @@ func GetAllRepoMilestones(repoID int64) ([]*Milestone, error) {
// GetMilestones returns a list of milestones of given repository and status.
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
miles := make([]*Milestone, 0, setting.IssuePagingNum)
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := x.Where("repo_id=? AND is_closed=?", repoID, isClosed)
if page > 0 {
sess = sess.Limit(setting.IssuePagingNum, (page-1)*setting.IssuePagingNum)
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
}
return miles, sess.Find(&miles)
}
@@ -1252,7 +1385,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().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().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,
PosterID: opts.Doer.ID,
Poster: opts.Doer,
IssueID: opts.Issue.ID,
CommitID: opts.CommitID,
CommitSHA: opts.CommitSHA,
@@ -124,7 +155,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
// Compose comment action, could be plain comment, close or reopen issue/pull request.
// This object will be used to notify watchers in the end of function.
act := &Action{
ActUserID: opts.Doer.Id,
ActUserID: opts.Doer.ID,
ActUserName: opts.Doer.Name,
ActEmail: opts.Doer.Email,
Content: fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]),
@@ -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.
@@ -310,3 +345,29 @@ func UpdateComment(c *Comment) error {
_, err := x.Id(c.ID).AllCols().Update(c)
return err
}
// DeleteCommentByID deletes a comment by given ID.
func DeleteCommentByID(id int64) error {
comment, err := GetCommentByID(id)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(comment.ID).Delete(new(Comment)); err != nil {
return err
}
if comment.Type == COMMENT_TYPE_COMMENT {
if _, err = sess.Exec("UPDATE `issue` SET num_comments = num_comments - 1 WHERE id = ?", comment.IssueID); err != nil {
return err
}
}
return sess.Commit()
}

View File

@@ -11,6 +11,8 @@ import (
"strings"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/base"
)
// Label represents a label of repository for issues.
@@ -56,48 +58,65 @@ func NewLabel(l *Label) error {
return err
}
func getLabelByID(e Engine, id int64) (*Label, error) {
if id <= 0 {
return nil, ErrLabelNotExist{id}
// getLabelInRepoByID returns a label by ID in given repository.
// If pass repoID as 0, then ORM will ignore limitation of repository
// and can return arbitrary label with any valid ID.
func getLabelInRepoByID(e Engine, repoID, labelID int64) (*Label, error) {
if labelID <= 0 {
return nil, ErrLabelNotExist{labelID, repoID}
}
l := &Label{ID: id}
l := &Label{
ID: labelID,
RepoID: repoID,
}
has, err := x.Get(l)
if err != nil {
return nil, err
} else if !has {
return nil, ErrLabelNotExist{l.ID}
return nil, ErrLabelNotExist{l.ID, l.RepoID}
}
return l, nil
}
// GetLabelByID returns a label by given ID.
func GetLabelByID(id int64) (*Label, error) {
return getLabelByID(x, id)
return getLabelInRepoByID(x, 0, id)
}
// GetLabelInRepoByID returns a label by ID in given repository.
func GetLabelInRepoByID(repoID, labelID int64) (*Label, error) {
return getLabelInRepoByID(x, repoID, labelID)
}
// GetLabelsInRepoByIDs returns a list of labels by IDs in given repository,
// it silently ignores label IDs that are not belong to the repository.
func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
labels := make([]*Label, 0, len(labelIDs))
return labels, x.Where("repo_id = ?", repoID).In("id", base.Int64sToStrings(labelIDs)).Find(&labels)
}
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
func GetLabelsByRepoID(repoID int64) ([]*Label, error) {
labels := make([]*Label, 0, 10)
return labels, x.Where("repo_id=?", repoID).Find(&labels)
return labels, x.Where("repo_id = ?", repoID).Find(&labels)
}
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
issueLabels, err := getIssueLabels(e, issueID)
if err != nil {
return nil, fmt.Errorf("getIssueLabels: %v", err)
} else if len(issueLabels) == 0 {
return []*Label{}, nil
}
var label *Label
labels := make([]*Label, 0, len(issueLabels))
for idx := range issueLabels {
label, err = getLabelByID(e, issueLabels[idx].LabelID)
if err != nil && !IsErrLabelNotExist(err) {
return nil, fmt.Errorf("getLabelByID: %v", err)
}
labels = append(labels, label)
labelIDs := make([]int64, len(issueLabels))
for i := range issueLabels {
labelIDs[i] = issueLabels[i].LabelID
}
return labels, nil
labels := make([]*Label, 0, len(labelIDs))
return labels, e.Where("id > 0").In("id", base.Int64sToStrings(labelIDs)).Find(&labels)
}
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
@@ -117,7 +136,7 @@ func UpdateLabel(l *Label) error {
// DeleteLabel delete a label of given repository.
func DeleteLabel(repoID, labelID int64) error {
l, err := GetLabelByID(labelID)
_, err := GetLabelInRepoByID(repoID, labelID)
if err != nil {
if IsErrLabelNotExist(err) {
return nil
@@ -131,11 +150,12 @@ func DeleteLabel(repoID, labelID int64) error {
return err
}
if _, err = x.Where("label_id=?", labelID).Delete(new(IssueLabel)); err != nil {
if _, err = sess.Id(labelID).Delete(new(Label)); err != nil {
return err
} else if _, err = sess.Delete(l); err != nil {
} else if _, err = sess.Where("label_id = ?", labelID).Delete(new(IssueLabel)); err != nil {
return err
}
return sess.Commit()
}
@@ -154,7 +174,7 @@ type IssueLabel struct {
}
func hasIssueLabel(e Engine, issueID, labelID int64) bool {
has, _ := e.Where("issue_id=? AND label_id=?", issueID, labelID).Get(new(IssueLabel))
has, _ := e.Where("issue_id = ? AND label_id = ?", issueID, labelID).Get(new(IssueLabel))
return has
}
@@ -180,6 +200,10 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
// NewIssueLabel creates a new issue-label relation.
func NewIssueLabel(issue *Issue, label *Label) (err error) {
if HasIssueLabel(issue.ID, label.ID) {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
@@ -193,6 +217,35 @@ func NewIssueLabel(issue *Issue, label *Label) (err error) {
return sess.Commit()
}
func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error) {
for i := range labels {
if hasIssueLabel(e, issue.ID, labels[i].ID) {
continue
}
if err = newIssueLabel(e, issue, labels[i]); err != nil {
return fmt.Errorf("newIssueLabel: %v", err)
}
}
return nil
}
// NewIssueLabels creates a list of issue-label relations.
func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = newIssueLabels(sess, issue, labels); err != nil {
return err
}
return sess.Commit()
}
func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) {
issueLabels := make([]*IssueLabel, 0, 10)
return issueLabels, e.Where("issue_id=?", issueID).Asc("label_id").Find(&issueLabels)

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().Unix()
s.UpdatedUnix = s.CreatedUnix
}
func (s *LoginSource) BeforeUpdate() {
s.UpdatedUnix = time.Now().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
}
}
@@ -491,7 +534,7 @@ func UserSignIn(uname, passwd string) (*User, error) {
return u, nil
}
return nil, ErrUserNotExist{u.Id, u.Name}
return nil, ErrUserNotExist{u.ID, u.Name}
default:
var source LoginSource
@@ -520,5 +563,5 @@ func UserSignIn(uname, passwd string) (*User, error) {
log.Warn("Failed to login '%s' via '%s': %v", uname, source.Name, err)
}
return nil, ErrUserNotExist{u.Id, u.Name}
return nil, ErrUserNotExist{u.ID, u.Name}
}

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.Unix())
case "created":
fieldSQL += com.ToStr(bean.Created.Unix())
case "updated":
fieldSQL += com.ToStr(bean.Updated.Unix())
case "closed_date":
fieldSQL += com.ToStr(bean.ClosedDate.Unix())
case "merged":
fieldSQL += com.ToStr(bean.Merged.Unix())
case "next_update":
fieldSQL += com.ToStr(bean.NextUpdate.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"
)
@@ -30,9 +27,10 @@ type Engine interface {
Exec(string, ...interface{}) (sql.Result, error)
Find(interface{}, ...interface{}) error
Get(interface{}) (bool, error)
Id(interface{}) *xorm.Session
Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error)
Id(interface{}) *xorm.Session
Iterate(interface{}, xorm.IterFunc) error
Sql(string, ...interface{}) *xorm.Session
Where(string, ...interface{}) *xorm.Session
}
@@ -44,27 +42,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 +98,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 +120,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)
@@ -226,7 +207,7 @@ func GetStatistic() (stats Statistic) {
stats.Counter.User = CountUsers()
stats.Counter.Org = CountOrganizations()
stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
stats.Counter.Repo = CountRepositories()
stats.Counter.Repo = CountRepositories(true)
stats.Counter.Watch, _ = x.Count(new(Watch))
stats.Counter.Star, _ = x.Count(new(Star))
stats.Counter.Action, _ = x.Count(new(Action))

File diff suppressed because it is too large Load Diff

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.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()
}
}
@@ -158,7 +163,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
pr.HasMerged = true
pr.Merged = time.Now()
pr.MergerID = doer.Id
pr.MergerID = doer.ID
if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
return fmt.Errorf("update pull request: %v", err)
}
@@ -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(),
@@ -240,14 +245,15 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
},
Sender: &api.PayloadUser{
UserName: doer.Name,
ID: doer.Id,
AvatarUrl: setting.AppUrl + doer.RelAvatarLink(),
ID: doer.ID,
AvatarUrl: doer.AvatarLink(),
},
}
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
go HookQueue.Add(pr.BaseRepo.ID)
go AddTestPullRequestTask(pr.BaseRepo.ID, pr.BaseBranch)
return nil
}
@@ -327,7 +333,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
// Notify watchers.
act := &Action{
ActUserID: pull.Poster.Id,
ActUserID: pull.Poster.ID,
ActUserName: pull.Poster.Name,
ActEmail: pull.Poster.Email,
OpType: ACTION_CREATE_PULL_REQUEST,
@@ -337,9 +343,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 +362,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,21 @@ 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() {
if r.CreatedUnix == 0 {
r.CreatedUnix = time.Now().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,7 +69,12 @@ 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 {
if strings.Contains(err.Error(), "is not a valid tag name") {
return ErrInvalidTagName{rel.TagName}
}
return err
}
} else {
@@ -70,6 +83,7 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
return fmt.Errorf("GetTagCommit: %v", err)
}
rel.Sha1 = commit.ID.String()
rel.NumCommits, err = commit.CommitsCount()
if err != nil {
return fmt.Errorf("CommitsCount: %v", err)
@@ -125,7 +139,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

@@ -19,7 +19,6 @@ import (
"strings"
"sync"
"time"
"unicode/utf8"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
@@ -129,8 +128,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 +169,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 +177,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().Unix()
repo.UpdatedUnix = repo.CreatedUnix
}
func (repo *Repository) BeforeUpdate() {
repo.UpdatedUnix = time.Now().Unix()
}
func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
@@ -195,8 +205,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 +258,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 +345,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 +357,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 +458,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,
@@ -453,7 +476,7 @@ func (repo *Repository) ComposePayload() *api.PayloadRepo {
func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) {
has, err := e.Get(&Repository{
OwnerID: u.Id,
OwnerID: u.ID,
LowerName: strings.ToLower(repoName),
})
return has && com.IsDir(RepoPath(u.Name, repoName)), err
@@ -471,6 +494,11 @@ type CloneLink struct {
Git string
}
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
func ComposeHTTPSCloneURL(owner, repo string) string {
return fmt.Sprintf("%s%s/%s.git", setting.AppUrl, owner, repo)
}
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
repoName := repo.Name
if isWiki {
@@ -484,7 +512,7 @@ func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
} else {
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSH.Domain, repo.Owner.Name, repoName)
}
cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.Name, repoName)
cl.HTTPS = ComposeHTTPSCloneURL(repo.Owner.Name, repo.Name)
return cl
}
@@ -493,46 +521,31 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(false)
}
var (
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
reservedPatterns = []string{"*.git", "*.keys", "*.wiki"}
)
// IsUsableName checks if name is reserved or pattern of name is not allowed.
func IsUsableName(name string) error {
name = strings.TrimSpace(strings.ToLower(name))
if utf8.RuneCountInString(name) == 0 {
return ErrNameEmpty
}
for i := range reservedNames {
if name == reservedNames[i] {
return ErrNameReserved{name}
}
}
for _, pat := range reservedPatterns {
if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
(pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
return ErrNamePatternNotAllowed{pat}
}
}
return nil
}
// 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.Unix()
}
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -541,6 +554,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 +633,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 +723,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: setting.Mirror.DefaultInterval,
EnablePrune: true,
NextUpdate: time.Now().Add(time.Duration(setting.Mirror.DefaultInterval) * time.Hour),
}); err != nil {
return repo, fmt.Errorf("InsertOne: %v", err)
}
@@ -898,8 +916,17 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
return nil
}
var (
reservedRepoNames = []string{".", ".."}
reservedRepoPatterns = []string{"*.git", "*.wiki"}
)
func IsUsableRepoName(name string) error {
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
}
func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
if err = IsUsableName(repo.Name); err != nil {
if err = IsUsableRepoName(repo.Name); err != nil {
return err
}
@@ -936,7 +963,7 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
}
}
if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
} else if err = newRepoAction(e, u, repo); err != nil {
return fmt.Errorf("newRepoAction: %v", err)
@@ -952,7 +979,7 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
}
repo := &Repository{
OwnerID: u.Id,
OwnerID: u.ID,
Owner: u,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
@@ -996,11 +1023,14 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
return repo, sess.Commit()
}
func countRepositories(showPrivate bool) int64 {
sess := x.NewSession()
func countRepositories(userID int64, private bool) int64 {
sess := x.Where("id > 0")
if !showPrivate {
sess.Where("is_private=?", false)
if userID > 0 {
sess.And("owner_id = ?", userID)
}
if !private {
sess.And("is_private=?", false)
}
count, err := sess.Count(new(Repository))
@@ -1011,20 +1041,29 @@ func countRepositories(showPrivate bool) int64 {
}
// CountRepositories returns number of repositories.
func CountRepositories() int64 {
return countRepositories(true)
// Argument private only takes effect when it is false,
// set it true to count all repositories.
func CountRepositories(private bool) int64 {
return countRepositories(-1, private)
}
// CountPublicRepositories returns number of public repositories.
func CountPublicRepositories() int64 {
return countRepositories(false)
// CountUserRepositories returns number of repositories user owns.
// Argument private only takes effect when it is false,
// set it true to count all repositories.
func CountUserRepositories(userID int64, private bool) int64 {
return countRepositories(userID, private)
}
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 {
@@ -1066,7 +1105,7 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
// Note: we have to set value here to make sure recalculate accesses is based on
// new owner.
repo.OwnerID = newOwner.Id
repo.OwnerID = newOwner.ID
repo.Owner = newOwner
// Update repository.
@@ -1083,10 +1122,10 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
// Dummy object.
collaboration := &Collaboration{RepoID: repo.ID}
for _, c := range collaborators {
collaboration.UserID = c.Id
if c.Id == newOwner.Id || newOwner.IsOrgMember(c.Id) {
collaboration.UserID = c.ID
if c.ID == newOwner.ID || newOwner.IsOrgMember(c.ID) {
if _, err = sess.Delete(collaboration); err != nil {
return fmt.Errorf("remove collaborator '%d': %v", c.Id, err)
return fmt.Errorf("remove collaborator '%d': %v", c.ID, err)
}
}
}
@@ -1127,19 +1166,20 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
}
// Update repository count.
if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.Id); err != nil {
if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil {
return fmt.Errorf("increase new owner repository count: %v", err)
} else if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", owner.Id); err != nil {
} else if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", owner.ID); err != nil {
return fmt.Errorf("decrease old owner repository count: %v", err)
}
if err = watchRepo(sess, newOwner.Id, repo.ID, true); err != nil {
if err = watchRepo(sess, newOwner.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
} else if err = transferRepoAction(sess, u, owner, newOwner, repo); err != nil {
return fmt.Errorf("transferRepoAction: %v", err)
}
// Rename remote repository to new path and delete local copy.
os.MkdirAll(UserPath(newOwner.Name), os.ModePerm)
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository directory: %v", err)
}
@@ -1161,7 +1201,7 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) {
oldRepoName = strings.ToLower(oldRepoName)
newRepoName = strings.ToLower(newRepoName)
if err = IsUsableName(newRepoName); err != nil {
if err = IsUsableRepoName(newRepoName); err != nil {
return err
}
@@ -1172,7 +1212,7 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
return ErrRepoAlreadyExist{u.Name, newRepoName}
}
repo, err := GetRepositoryByName(u.Id, oldRepoName)
repo, err := GetRepositoryByName(u.ID, oldRepoName)
if err != nil {
return fmt.Errorf("GetRepositoryByName: %v", err)
}
@@ -1364,20 +1404,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)
}
}
@@ -1398,7 +1426,7 @@ func GetRepositoryByRef(ref string) (*Repository, error) {
return nil, err
}
return GetRepositoryByName(user.Id, repoName)
return GetRepositoryByName(user.ID, repoName)
}
// GetRepositoryByName returns the repository by given name under user if exists.
@@ -1432,25 +1460,36 @@ func GetRepositoryByID(id int64) (*Repository, error) {
return getRepositoryByID(x, id)
}
// 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")
// GetUserRepositories returns a list of repositories of given user.
func GetUserRepositories(userID int64, private bool, page, pageSize int) ([]*Repository, error) {
sess := x.Where("owner_id = ?", userID).Desc("updated_unix")
if !private {
sess.Where("is_private=?", false)
sess.And("is_private=?", false)
}
return repos, sess.Find(&repos, &Repository{OwnerID: uid})
if page <= 0 {
page = 1
}
sess.Limit(pageSize, (page-1)*pageSize)
repos := make([]*Repository, 0, pageSize)
return repos, sess.Find(&repos)
}
// GetUserRepositories returns a list of mirror repositories of given user.
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
return repos, x.Where("owner_id = ?", userID).And("is_mirror = ?", true).Find(&repos)
}
// 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) {
return x.Count(&Repository{OwnerID: u.Id})
return x.Count(&Repository{OwnerID: u.ID})
}
// GetRepositoryCount returns the total number of repositories of user.
@@ -1458,32 +1497,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.
@@ -1617,22 +1673,24 @@ func MirrorUpdate() {
log.Trace("Doing: MirrorUpdate")
mirrors := make([]*Mirror, 0, 10)
if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.NextUpdate.After(time.Now()) {
return nil
}
if m.Repo == nil {
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
return nil
}
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 {
@@ -1683,14 +1741,17 @@ func GitFsck() {
}
func GitGcRepos() error {
args := append([]string{"gc"}, setting.Git.GcArgs...)
args := append([]string{"gc"}, setting.Git.GCArgs...)
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if err := repo.GetOwner(); err != nil {
return err
}
_, stderr, err := process.ExecDir(-1, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", "git", args...)
_, stderr, err := process.ExecDir(
time.Duration(setting.Git.Timeout.GC)*time.Second,
RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection",
"git", args...)
if err != nil {
return fmt.Errorf("%v: %v", err, stderr)
}
@@ -1764,9 +1825,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 {
@@ -1796,6 +1874,74 @@ func CheckRepoStats() {
// ***** END: Repository.NumForks *****
}
type RepositoryList []*Repository
func (repos RepositoryList) loadAttributes(e Engine) error {
if len(repos) == 0 {
return nil
}
// Load owners.
set := make(map[int64]*User)
for i := range repos {
set[repos[i].OwnerID] = nil
}
userIDs := make([]int64, 0, len(set))
for userID := range set {
userIDs = append(userIDs, userID)
}
users := make([]*User, 0, len(userIDs))
if err := e.Where("id > 0").In("id", userIDs).Find(&users); err != nil {
return fmt.Errorf("find users: %v", err)
}
for i := range users {
set[users[i].ID] = users[i]
}
for i := range repos {
repos[i].Owner = set[repos[i].OwnerID]
}
return nil
}
func (repos RepositoryList) LoadAttributes() error {
return repos.loadAttributes(x)
}
type MirrorRepositoryList []*Repository
func (repos MirrorRepositoryList) loadAttributes(e Engine) error {
if len(repos) == 0 {
return nil
}
// Load mirrors.
repoIDs := make([]int64, 0, len(repos))
for i := range repos {
if !repos[i].IsMirror {
continue
}
repoIDs = append(repoIDs, repos[i].ID)
}
mirrors := make([]*Mirror, 0, len(repoIDs))
if err := e.Where("id > 0").In("repo_id", repoIDs).Find(&mirrors); err != nil {
return fmt.Errorf("find mirrors: %v", err)
}
set := make(map[int64]*Mirror)
for i := range mirrors {
set[mirrors[i].RepoID] = mirrors[i]
}
for i := range repos {
repos[i].Mirror = set[repos[i].ID]
}
return nil
}
func (repos MirrorRepositoryList) LoadAttributes() error {
return repos.loadAttributes(x)
}
// __ __ __ .__
// / \ / \_____ _/ |_ ____ | |__
// \ \/\/ /\__ \\ __\/ ___\| | \
@@ -1810,40 +1956,40 @@ type Watch struct {
RepoID int64 `xorm:"UNIQUE(watch)"`
}
func isWatching(e Engine, uid, repoId int64) bool {
has, _ := e.Get(&Watch{0, uid, repoId})
func isWatching(e Engine, userID, repoID int64) bool {
has, _ := e.Get(&Watch{0, userID, repoID})
return has
}
// IsWatching checks if user has watched given repository.
func IsWatching(uid, repoId int64) bool {
return isWatching(x, uid, repoId)
func IsWatching(userID, repoID int64) bool {
return isWatching(x, userID, repoID)
}
func watchRepo(e Engine, uid, repoId int64, watch bool) (err error) {
func watchRepo(e Engine, userID, repoID int64, watch bool) (err error) {
if watch {
if isWatching(e, uid, repoId) {
if isWatching(e, userID, repoID) {
return nil
}
if _, err = e.Insert(&Watch{RepoID: repoId, UserID: uid}); err != nil {
if _, err = e.Insert(&Watch{RepoID: repoID, UserID: userID}); err != nil {
return err
}
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?", repoId)
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?", repoID)
} else {
if !isWatching(e, uid, repoId) {
if !isWatching(e, userID, repoID) {
return nil
}
if _, err = e.Delete(&Watch{0, uid, repoId}); err != nil {
if _, err = e.Delete(&Watch{0, userID, repoID}); err != nil {
return err
}
_, err = e.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", repoId)
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repoID)
}
return err
}
// Watch or unwatch repository.
func WatchRepo(uid, repoId int64, watch bool) (err error) {
return watchRepo(x, uid, repoId, watch)
func WatchRepo(userID, repoID int64, watch bool) (err error) {
return watchRepo(x, userID, repoID, watch)
}
func getWatchers(e Engine, repoID int64) ([]*Watch, error) {
@@ -1914,34 +2060,34 @@ type Star struct {
}
// Star or unstar repository.
func StarRepo(uid, repoId int64, star bool) (err error) {
func StarRepo(userID, repoID int64, star bool) (err error) {
if star {
if IsStaring(uid, repoId) {
if IsStaring(userID, repoID) {
return nil
}
if _, err = x.Insert(&Star{UID: uid, RepoID: repoId}); err != nil {
if _, err = x.Insert(&Star{UID: userID, RepoID: repoID}); err != nil {
return err
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoId); err != nil {
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoID); err != nil {
return err
}
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", uid)
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", userID)
} else {
if !IsStaring(uid, repoId) {
if !IsStaring(userID, repoID) {
return nil
}
if _, err = x.Delete(&Star{0, uid, repoId}); err != nil {
if _, err = x.Delete(&Star{0, userID, repoID}); err != nil {
return err
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoId); err != nil {
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoID); err != nil {
return err
}
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", uid)
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", userID)
}
return err
}
// IsStaring checks if user has starred given repository.
func IsStaring(uid, repoId int64) bool {
has, _ := x.Get(&Star{0, uid, repoId})
func IsStaring(userID, repoID int64) bool {
has, _ := x.Get(&Star{0, userID, repoID})
return has
}
@@ -1972,7 +2118,7 @@ func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
repo := &Repository{
OwnerID: u.Id,
OwnerID: u.ID,
Owner: u,
Name: name,
LowerName: strings.ToLower(name),

View File

@@ -6,35 +6,34 @@ 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.
func (repo *Repository) AddCollaborator(u *User) error {
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: u.Id,
UserID: u.ID,
}
has, err := x.Get(collaboration)

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

@@ -5,12 +5,10 @@
package models
import (
"bufio"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
@@ -24,17 +22,17 @@ import (
"github.com/go-xorm/xorm"
"golang.org/x/crypto/ssh"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
)
const (
// "### autogenerated by gitgos, DO NOT EDIT\n"
_TPL_PUBLICK_KEY = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
)
var sshOpLocker = sync.Mutex{}
var sshOpLocker sync.Mutex
type KeyType int
@@ -43,68 +41,81 @@ const (
KEY_TYPE_DEPLOY
)
// PublicKey represents a SSH or deploy key.
// PublicKey represents a user or deploy SSH public 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().Unix()
}
func (k *PublicKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().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())
}
}
// OmitEmail returns content of public key but without e-mail address.
// OmitEmail returns content of public key without email address.
func (k *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(k.Content, " ")[:2], " ")
}
// GetAuthorizedString generates and returns formatted public key string for authorized_keys file.
func (key *PublicKey) GetAuthorizedString() string {
// AuthorizedString returns formatted public key string for authorized_keys file.
func (key *PublicKey) AuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, key.ID, setting.CustomConf, key.Content)
}
func extractTypeFromBase64Key(key string) (string, error) {
b, err := base64.StdEncoding.DecodeString(key)
if err != nil || len(b) < 4 {
return "", fmt.Errorf("Invalid key format: %v", err)
return "", fmt.Errorf("invalid key format: %v", err)
}
keyLength := int(binary.BigEndian.Uint32(b))
if len(b) < 4+keyLength {
return "", fmt.Errorf("Invalid key format: not enough length")
return "", fmt.Errorf("invalid key format: not enough length %d", keyLength)
}
return string(b[4 : 4+keyLength]), nil
}
// parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253)
// parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253).
func parseKeyString(content string) (string, error) {
// Transform all legal line endings to a single "\n"
s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1)
lines := strings.Split(s, "\n")
// Transform all legal line endings to a single "\n".
content = strings.NewReplacer("\r\n", "\n", "\r", "\n").Replace(content)
lines := strings.Split(content, "\n")
var keyType, keyContent, keyComment string
if len(lines) == 1 {
// Parse openssh format
// Parse OpenSSH format.
parts := strings.SplitN(lines[0], " ", 3)
switch len(parts) {
case 0:
return "", errors.New("Empty key")
return "", errors.New("empty key")
case 1:
keyContent = parts[0]
case 2:
@@ -116,17 +127,15 @@ func parseKeyString(content string) (string, error) {
keyComment = parts[2]
}
// If keyType is not given, extract it from content. If given, validate it
// If keyType is not given, extract it from content. If given, validate it.
t, err := extractTypeFromBase64Key(keyContent)
if err != nil {
return "", fmt.Errorf("extractTypeFromBase64Key: %v", err)
}
if len(keyType) == 0 {
if t, err := extractTypeFromBase64Key(keyContent); err == nil {
keyType = t
} else {
return "", err
}
} else {
if t, err := extractTypeFromBase64Key(keyContent); err != nil || keyType != t {
return "", err
}
keyType = t
} else if keyType != t {
return "", fmt.Errorf("key type and content does not match: %s - %s", keyType, t)
}
} else {
// Parse SSH2 file format.
@@ -144,11 +153,11 @@ func parseKeyString(content string) (string, error) {
}
}
if t, err := extractTypeFromBase64Key(keyContent); err == nil {
keyType = t
} else {
return "", err
t, err := extractTypeFromBase64Key(keyContent)
if err != nil {
return "", fmt.Errorf("extractTypeFromBase64Key: %v", err)
}
keyType = t
}
return keyType + " " + keyContent + " " + keyComment, nil
}
@@ -163,7 +172,7 @@ func writeTmpKeyFile(content string) (string, error) {
defer tmpFile.Close()
if _, err = tmpFile.WriteString(content); err != nil {
return "", fmt.Errorf("tmpFile.WriteString: %v", err)
return "", fmt.Errorf("WriteString: %v", err)
}
return tmpFile.Name(), nil
}
@@ -183,7 +192,7 @@ func SSHKeyGenParsePublicKey(key string) (string, int, error) {
stdout, stderr, err := process.Exec("SSHKeyGenParsePublicKey", setting.SSH.KeygenPath, "-lf", tmpName)
if err != nil {
return "", 0, fmt.Errorf("Fail to parse public key: %s - %s", err, stderr)
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
}
if strings.Contains(stdout, "is not a public key file") {
return "", 0, ErrKeyUnableVerify{stdout}
@@ -191,7 +200,7 @@ func SSHKeyGenParsePublicKey(key string) (string, int, error) {
fields := strings.Split(stdout, " ")
if len(fields) < 4 {
return "", 0, fmt.Errorf("Invalid public key line: %s", stdout)
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
}
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
@@ -216,7 +225,7 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
if strings.Contains(err.Error(), "ssh: unknown key algorithm") {
return "", 0, ErrKeyUnableVerify{err.Error()}
}
return "", 0, fmt.Errorf("ssh.ParsePublicKey: %v", err)
return "", 0, fmt.Errorf("ParsePublicKey: %v", err)
}
// The ssh library can parse the key, so next we find out what key exactly we have.
@@ -248,15 +257,14 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
return "ecdsa", 384, nil
case ssh.KeyAlgoECDSA521:
return "ecdsa", 521, nil
case "ssh-ed25519": // TODO replace with ssh constant when available
case "ssh-ed25519": // TODO: replace with ssh constant when available
return "ed25519", 256, nil
}
return "", 0, fmt.Errorf("Unsupported key length detection for type: %s", pkey.Type())
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
}
// CheckPublicKeyString checks if the given public key string is recognized by SSH.
//
// The function returns the actual public key line on success.
// It returns the actual public key line on success.
func CheckPublicKeyString(content string) (_ string, err error) {
if setting.SSH.Disabled {
return "", errors.New("SSH is disabled")
@@ -276,16 +284,19 @@ func CheckPublicKeyString(content string) (_ string, err error) {
content = strings.TrimSpace(content)
var (
fnName string
keyType string
length int
)
if setting.SSH.StartBuiltinServer {
fnName = "SSHNativeParsePublicKey"
keyType, length, err = SSHNativeParsePublicKey(content)
} else {
fnName = "SSHKeyGenParsePublicKey"
keyType, length, err = SSHKeyGenParsePublicKey(content)
}
if err != nil {
return "", fmt.Errorf("ParsePublicKey: %v", err)
return "", fmt.Errorf("%s: %v", fnName, err)
}
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
@@ -295,13 +306,13 @@ func CheckPublicKeyString(content string) (_ string, err error) {
if minLen, found := setting.SSH.MinimumKeySizes[keyType]; found && length >= minLen {
return content, nil
} else if found && length < minLen {
return "", fmt.Errorf("Key length is not enough: got %d, needs %d", length, minLen)
return "", fmt.Errorf("key length is not enough: got %d, needs %d", length, minLen)
}
return "", fmt.Errorf("Key type is not allowed: %s", keyType)
return "", fmt.Errorf("key type is not allowed: %s", keyType)
}
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(keys ...*PublicKey) error {
// appendAuthorizedKeysToFile appends new SSH keys' content to authorized_keys file.
func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
@@ -312,13 +323,13 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
// FIXME: following command does not support in Windows.
// Note: chmod command does not support in Windows.
if !setting.IsWindows {
fi, err := f.Stat()
if err != nil {
return err
}
// .ssh directory should have mode 700, and authorized_keys file should have mode 600.
if fi.Mode().Perm() > 0600 {
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
@@ -329,7 +340,7 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
}
for _, key := range keys {
if _, err = f.WriteString(key.GetAuthorizedString()); err != nil {
if _, err = f.WriteString(key.AuthorizedString()); err != nil {
return err
}
}
@@ -376,7 +387,7 @@ func addKey(e Engine, key *PublicKey) (err error) {
if setting.SSH.StartBuiltinServer {
return nil
}
return saveAuthorizedKeyFile(key)
return appendAuthorizedKeysToFile(key)
}
// AddPublicKey adds new public key to database and authorized_keys file.
@@ -387,7 +398,7 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
}
// Key name of same user cannot be duplicated.
has, err := x.Where("owner_id=? AND name=?", ownerID, name).Get(new(PublicKey))
has, err := x.Where("owner_id = ? AND name = ?", ownerID, name).Get(new(PublicKey))
if err != nil {
return nil, err
} else if has {
@@ -442,62 +453,7 @@ func SearchPublicKeyByContent(content string) (*PublicKey, error) {
// ListPublicKeys returns a list of public keys belongs to given user.
func ListPublicKeys(uid int64) ([]*PublicKey, error) {
keys := make([]*PublicKey, 0, 5)
return keys, x.Where("owner_id=?", uid).Find(&keys)
}
// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
fr, err := os.Open(p)
if err != nil {
return err
}
defer fr.Close()
fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
defer fw.Close()
isFound := false
keyword := fmt.Sprintf("key-%d", key.ID)
buf := bufio.NewReader(fr)
for {
line, errRead := buf.ReadString('\n')
line = strings.TrimSpace(line)
if errRead != nil {
if errRead != io.EOF {
return errRead
}
// Reached end of file, if nothing to read then break,
// otherwise handle the last line.
if len(line) == 0 {
break
}
}
// Found the line and copy rest of file.
if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
isFound = true
continue
}
// Still finding the line, copy the line that currently read.
if _, err = fw.WriteString(line + "\n"); err != nil {
return err
}
if errRead == io.EOF {
break
}
}
if !isFound {
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
}
return nil
return keys, x.Where("owner_id = ?", uid).Find(&keys)
}
// UpdatePublicKey updates given public key.
@@ -506,35 +462,14 @@ func UpdatePublicKey(key *PublicKey) error {
return err
}
func deletePublicKey(e *xorm.Session, keyID int64) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
key := &PublicKey{ID: keyID}
has, err := e.Get(key)
if err != nil {
return err
} else if !has {
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
if len(keyIDs) == 0 {
return nil
}
if _, err = e.Id(key.ID).Delete(new(PublicKey)); err != nil {
return err
}
// Don't need to rewrite this file if builtin SSH server is enabled.
if setting.SSH.StartBuiltinServer {
return nil
}
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
tmpPath := fpath + ".tmp"
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
return err
} else if err = os.Remove(fpath); err != nil {
return err
}
return os.Rename(tmpPath, fpath)
_, err := e.In("id", strings.Join(base.Int64sToStrings(keyIDs), ",")).Delete(new(PublicKey))
return err
}
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
@@ -548,8 +483,8 @@ func DeletePublicKey(doer *User, id int64) (err error) {
}
// Check if user has access to delete this key.
if !doer.IsAdmin && doer.Id != key.OwnerID {
return ErrKeyAccessDenied{doer.Id, key.ID, "public"}
if !doer.IsAdmin && doer.ID != key.OwnerID {
return ErrKeyAccessDenied{doer.ID, key.ID, "public"}
}
sess := x.NewSession()
@@ -558,14 +493,20 @@ func DeletePublicKey(doer *User, id int64) (err error) {
return err
}
if err = deletePublicKey(sess, id); err != nil {
if err = deletePublicKeys(sess, id); err != nil {
return err
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
}
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
// outsite any session scope independently.
func RewriteAllPublicKeys() error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
@@ -579,7 +520,7 @@ func RewriteAllPublicKeys() error {
defer os.Remove(tmpPath)
err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
_, err = f.WriteString((bean.(*PublicKey)).GetAuthorizedString())
_, err = f.WriteString((bean.(*PublicKey)).AuthorizedString())
return err
})
f.Close()
@@ -608,21 +549,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().Unix()
}
func (k *DeployKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().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())
}
@@ -640,14 +595,14 @@ func (k *DeployKey) GetContent() error {
func checkDeployKey(e Engine, keyID, repoID int64, name string) error {
// Note: We want error detail, not just true or false here.
has, err := e.Where("key_id=? AND repo_id=?", keyID, repoID).Get(new(DeployKey))
has, err := e.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
if err != nil {
return err
} else if has {
return ErrDeployKeyAlreadyExist{keyID, repoID}
}
has, err = e.Where("repo_id=? AND name=?", repoID, name).Get(new(DeployKey))
has, err = e.Where("repo_id = ? AND name = ?", repoID, name).Get(new(DeployKey))
if err != nil {
return err
} else if has {
@@ -675,7 +630,7 @@ func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string
// HasDeployKey returns true if public key is a deploy key of given repository.
func HasDeployKey(keyID, repoID int64) bool {
has, _ := x.Where("key_id=? AND repo_id=?", keyID, repoID).Get(new(DeployKey))
has, _ := x.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
return has
}
@@ -769,7 +724,7 @@ func DeleteDeployKey(doer *User, id int64) error {
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !yes {
return ErrKeyAccessDenied{doer.Id, key.ID, "deploy"}
return ErrKeyAccessDenied{doer.ID, key.ID, "deploy"}
}
}
@@ -780,15 +735,15 @@ func DeleteDeployKey(doer *User, id int64) error {
}
if _, err = sess.Id(key.ID).Delete(new(DeployKey)); err != nil {
return fmt.Errorf("delete deploy key[%d]: %v", key.ID, err)
return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err)
}
// Check if this is the last reference to same key content.
has, err := sess.Where("key_id=?", key.KeyID).Get(new(DeployKey))
has, err := sess.Where("key_id = ?", key.KeyID).Get(new(DeployKey))
if err != nil {
return err
} else if !has {
if err = deletePublicKey(sess, key.KeyID); err != nil {
if err = deletePublicKeys(sess, key.KeyID); err != nil {
return err
}
}
@@ -799,5 +754,5 @@ func DeleteDeployKey(doer *User, id int64) error {
// ListDeployKeys returns all deploy keys by given repository ID.
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
keys := make([]*DeployKey, 0, 5)
return keys, x.Where("repo_id=?", repoID).Find(&keys)
return keys, x.Where("repo_id = ?", repoID).Find(&keys)
}

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().Unix()
}
func (t *AccessToken) BeforeUpdate() {
t.UpdatedUnix = time.Now().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

@@ -56,10 +56,14 @@ func ListToPushCommits(l *list.List) *PushCommits {
actEmail = commit.Committer.Email
}
commits = append(commits,
&PushCommit{commit.ID.String(),
commit.Message(),
commit.Author.Email,
commit.Author.Name,
&PushCommit{
Sha1: commit.ID.String(),
Message: commit.Message(),
AuthorEmail: commit.Author.Email,
AuthorName: commit.Author.Name,
CommitterEmail: commit.Committer.Email,
CommitterName: commit.Committer.Name,
Timestamp: commit.Author.When,
})
}
return &PushCommits{l.Len(), commits, "", nil}
@@ -108,7 +112,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
return fmt.Errorf("GetUserByName: %v", err)
}
repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName)
repo, err := GetRepositoryByName(repoUser.ID, opts.RepoName)
if err != nil {
return fmt.Errorf("GetRepositoryByName: %v", err)
}
@@ -133,7 +137,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
commit := &PushCommits{}
if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, actEmail,
if err = CommitRepoAction(opts.PusherID, repoUser.ID, opts.PusherName, actEmail,
repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, commit, opts.OldCommitID, opts.NewCommitID); err != nil {
return fmt.Errorf("CommitRepoAction (tag): %v", err)
}
@@ -159,7 +163,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
}
if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, repoUser.Email,
if err = CommitRepoAction(opts.PusherID, repoUser.ID, opts.PusherName, repoUser.Email,
repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, ListToPushCommits(l),
opts.OldCommitID, opts.NewCommitID); err != nil {
return fmt.Errorf("CommitRepoAction (branch): %v", err)

View File

@@ -12,13 +12,13 @@ import (
"errors"
"fmt"
"image"
"image/jpeg"
_ "image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"
"time"
"unicode/utf8"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
@@ -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 (
@@ -52,7 +52,7 @@ var (
// User represents the object of individual and member of organization.
type User struct {
Id int64
ID int64 `xorm:"pk autoincr"`
LowerName string `xorm:"UNIQUE NOT NULL"`
Name string `xorm:"UNIQUE NOT NULL"`
FullName string
@@ -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().Unix()
u.UpdatedUnix = u.CreatedUnix
}
func (u *User) BeforeUpdate() {
if u.MaxRepoCreation < -1 {
u.MaxRepoCreation = -1
}
u.UpdatedUnix = time.Now().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()
}
}
@@ -125,7 +137,7 @@ func (u *User) IsLocal() bool {
// HasForkedRepo checks if user has already forked a repository with given ID.
func (u *User) HasForkedRepo(repoID int64) bool {
_, has := HasForkedRepo(u.Id, repoID)
_, has := HasForkedRepo(u.ID, repoID)
return has
}
@@ -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() {
@@ -182,7 +184,7 @@ func (u *User) HomeLink() string {
// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
func (u *User) GenerateEmailActivateCode(email string) string {
code := base.CreateTimeLimitCode(
com.ToStr(u.Id)+email+u.LowerName+u.Passwd+u.Rands,
com.ToStr(u.ID)+email+u.LowerName+u.Passwd+u.Rands,
setting.Service.ActiveCodeLives, nil)
// Add tail hex username
@@ -197,7 +199,7 @@ func (u *User) GenerateActivateCode() string {
// CustomAvatarPath returns user custom avatar file path.
func (u *User) CustomAvatarPath() string {
return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.Id))
return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.ID))
}
// GenerateRandomAvatar generates a random avatar for user.
@@ -220,17 +222,20 @@ func (u *User) GenerateRandomAvatar() error {
}
defer fw.Close()
if err = jpeg.Encode(fw, img, nil); err != nil {
if err = png.Encode(fw, img); err != nil {
return fmt.Errorf("Encode: %v", err)
}
log.Info("New random avatar created: %d", u.Id)
log.Info("New random avatar created: %d", u.ID)
return nil
}
// RelAvatarLink returns relative avatar link to the site domain,
// which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service.
func (u *User) RelAvatarLink() string {
defaultImgUrl := "/img/avatar_default.jpg"
if u.Id == -1 {
defaultImgUrl := setting.AppSubUrl + "/img/avatar_default.png"
if u.ID == -1 {
return defaultImgUrl
}
@@ -239,7 +244,7 @@ func (u *User) RelAvatarLink() string {
if !com.IsExist(u.CustomAvatarPath()) {
return defaultImgUrl
}
return "/avatars/" + com.ToStr(u.Id)
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
case setting.DisableGravatar, setting.OfflineMode:
if !com.IsExist(u.CustomAvatarPath()) {
if err := u.GenerateRandomAvatar(); err != nil {
@@ -247,16 +252,16 @@ func (u *User) RelAvatarLink() string {
}
}
return "/avatars/" + com.ToStr(u.Id)
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
}
return setting.GravatarSource + u.Avatar
return base.AvatarLink(u.AvatarEmail)
}
// AvatarLink returns user gravatar link.
// AvatarLink returns user avatar absolute link.
func (u *User) AvatarLink() string {
link := u.RelAvatarLink()
if link[0] == '/' && link[1] != '/' {
return setting.AppSubUrl + link
return setting.AppUrl + link[1:]
}
return link
}
@@ -264,7 +269,7 @@ func (u *User) AvatarLink() string {
// User.GetFollwoers returns range of user's followers.
func (u *User) GetFollowers(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.follow_id=?", u.Id)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.follow_id=?", u.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
} else {
@@ -274,13 +279,13 @@ func (u *User) GetFollowers(page int) ([]*User, error) {
}
func (u *User) IsFollowing(followID int64) bool {
return IsFollowing(u.Id, followID)
return IsFollowing(u.ID, followID)
}
// GetFollowing returns range of user's following.
func (u *User) GetFollowing(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.user_id=?", u.Id)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.user_id=?", u.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
} else {
@@ -319,7 +324,7 @@ func (u *User) UploadAvatar(data []byte) error {
return fmt.Errorf("Decode: %v", err)
}
m := resize.Resize(290, 290, img, resize.NearestNeighbor)
m := resize.Resize(avatar.AVATAR_SIZE, avatar.AVATAR_SIZE, img, resize.NearestNeighbor)
sess := x.NewSession()
defer sessionRelease(sess)
@@ -348,7 +353,7 @@ func (u *User) UploadAvatar(data []byte) error {
// DeleteAvatar deletes the user's custom avatar.
func (u *User) DeleteAvatar() error {
log.Trace("DeleteAvatar[%d]: %s", u.Id, u.CustomAvatarPath())
log.Trace("DeleteAvatar[%d]: %s", u.ID, u.CustomAvatarPath())
os.Remove(u.CustomAvatarPath())
u.UseCustomAvatar = false
@@ -378,21 +383,21 @@ 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.
func (u *User) IsUserOrgOwner(orgId int64) bool {
return IsOrganizationOwner(orgId, u.Id)
return IsOrganizationOwner(orgId, u.ID)
}
// IsPublicMember returns true if user public his/her membership in give organization.
func (u *User) IsPublicMember(orgId int64) bool {
return IsPublicMembership(orgId, u.Id)
return IsPublicMembership(orgId, u.ID)
}
func (u *User) getOrganizationCount(e Engine) (int64, error) {
return e.Where("uid=?", u.Id).Count(new(OrgUser))
return e.Where("uid=?", u.ID).Count(new(OrgUser))
}
// GetOrganizationCount returns count of membership of organization of user.
@@ -400,21 +405,26 @@ func (u *User) GetOrganizationCount() (int64, error) {
return u.getOrganizationCount(x)
}
// GetRepositories returns all repositories that user owns, including private repositories.
func (u *User) GetRepositories() (err error) {
u.Repos, err = GetRepositories(u.Id, true)
// GetRepositories returns repositories that user owns, including private repositories.
func (u *User) GetRepositories(page, pageSize int) (err error) {
u.Repos, err = GetUserRepositories(u.ID, true, page, pageSize)
return err
}
// GetRepositories returns mirror repositories that user owns, including private repositories.
func (u *User) GetMirrorRepositories() ([]*Repository, error) {
return GetUserMirrorRepositories(u.ID)
}
// GetOwnedOrganizations returns all organizations that user owns.
func (u *User) GetOwnedOrganizations() (err error) {
u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.Id)
u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.ID)
return err
}
// GetOrganizations returns all organizations that user belongs to.
func (u *User) GetOrganizations(all bool) error {
ous, err := GetOrgUsersByUserID(u.Id, all)
ous, err := GetOrgUsersByUserID(u.ID, all)
if err != nil {
return err
}
@@ -453,19 +463,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)
@@ -474,15 +471,49 @@ func GetUserSalt() string {
// NewFakeUser creates and returns a fake user for someone has deleted his/her account.
func NewFakeUser() *User {
return &User{
Id: -1,
ID: -1,
Name: "Someone",
LowerName: "someone",
}
}
var (
reversedUsernames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
reversedUserPatterns = []string{"*.keys"}
)
// isUsableName checks if name is reserved or pattern of name is not allowed
// based on given reversed names and patterns.
// Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
func isUsableName(names, patterns []string, name string) error {
name = strings.TrimSpace(strings.ToLower(name))
if utf8.RuneCountInString(name) == 0 {
return ErrNameEmpty
}
for i := range names {
if name == names[i] {
return ErrNameReserved{name}
}
}
for _, pat := range patterns {
if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
(pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
return ErrNamePatternNotAllowed{pat}
}
}
return nil
}
func IsUsableUsername(name string) error {
return isUsableName(reversedUsernames, reversedUserPatterns, name)
}
// CreateUser creates record of a new user.
func CreateUser(u *User) (err error) {
if err = IsUsableName(u.Name); err != nil {
if err = IsUsableUsername(u.Name); err != nil {
return err
}
@@ -510,16 +541,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
}
@@ -567,7 +596,7 @@ func VerifyUserActiveCode(code string) (user *User) {
if user = getVerifyUser(code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
data := com.ToStr(user.ID) + user.Email + user.LowerName + user.Passwd + user.Rands
if base.VerifyTimeLimitCode(data, minutes, prefix) {
return user
@@ -583,7 +612,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
if user := getVerifyUser(code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := com.ToStr(user.Id) + email + user.LowerName + user.Passwd + user.Rands
data := com.ToStr(user.ID) + email + user.LowerName + user.Passwd + user.Rands
if base.VerifyTimeLimitCode(data, minutes, prefix) {
emailAddress := &EmailAddress{Email: email}
@@ -597,7 +626,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
// ChangeUserName changes all corresponding setting from old user name to new one.
func ChangeUserName(u *User, newUserName string) (err error) {
if err = IsUsableName(newUserName); err != nil {
if err = IsUsableUsername(newUserName); err != nil {
return err
}
@@ -613,7 +642,7 @@ func ChangeUserName(u *User, newUserName string) (err error) {
}
// Delete all local copies of repository wiki that user owns.
if err = x.Where("owner_id=?", u.Id).Iterate(new(Repository), func(idx int, bean interface{}) error {
if err = x.Where("owner_id=?", u.ID).Iterate(new(Repository), func(idx int, bean interface{}) error {
repo := bean.(*Repository)
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
return nil
@@ -628,7 +657,7 @@ func updateUser(e Engine, u *User) error {
// Organization does not need email
if !u.IsOrganization() {
u.Email = strings.ToLower(u.Email)
has, err := e.Where("id!=?", u.Id).And("type=?", u.Type).And("email=?", u.Email).Get(new(User))
has, err := e.Where("id!=?", u.ID).And("type=?", u.Type).And("email=?", u.Email).Get(new(User))
if err != nil {
return err
} else if has {
@@ -647,7 +676,7 @@ func updateUser(e Engine, u *User) error {
u.Description = base.TruncateString(u.Description, 255)
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
_, err := e.Id(u.Id).AllCols().Update(u)
_, err := e.Id(u.ID).AllCols().Update(u)
return err
}
@@ -676,7 +705,7 @@ func deleteUser(e *xorm.Session, u *User) error {
if err != nil {
return fmt.Errorf("GetRepositoryCount: %v", err)
} else if count > 0 {
return ErrUserOwnRepos{UID: u.Id}
return ErrUserOwnRepos{UID: u.ID}
}
// Check membership of organization.
@@ -684,12 +713,12 @@ func deleteUser(e *xorm.Session, u *User) error {
if err != nil {
return fmt.Errorf("GetOrganizationCount: %v", err)
} else if count > 0 {
return ErrUserHasOrgs{UID: u.Id}
return ErrUserHasOrgs{UID: u.ID}
}
// ***** START: Watch *****
watches := make([]*Watch, 0, 10)
if err = e.Find(&watches, &Watch{UserID: u.Id}); err != nil {
if err = e.Find(&watches, &Watch{UserID: u.ID}); err != nil {
return fmt.Errorf("get all watches: %v", err)
}
for i := range watches {
@@ -701,7 +730,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** START: Star *****
stars := make([]*Star, 0, 10)
if err = e.Find(&stars, &Star{UID: u.Id}); err != nil {
if err = e.Find(&stars, &Star{UID: u.ID}); err != nil {
return fmt.Errorf("get all stars: %v", err)
}
for i := range stars {
@@ -713,7 +742,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** START: Follow *****
followers := make([]*Follow, 0, 10)
if err = e.Find(&followers, &Follow{UserID: u.Id}); err != nil {
if err = e.Find(&followers, &Follow{UserID: u.ID}); err != nil {
return fmt.Errorf("get all followers: %v", err)
}
for i := range followers {
@@ -724,37 +753,40 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** END: Follow *****
if err = deleteBeans(e,
&AccessToken{UID: u.Id},
&Collaboration{UserID: u.Id},
&Access{UserID: u.Id},
&Watch{UserID: u.Id},
&Star{UID: u.Id},
&Follow{FollowID: u.Id},
&Action{UserID: u.Id},
&IssueUser{UID: u.Id},
&EmailAddress{UID: u.Id},
&AccessToken{UID: u.ID},
&Collaboration{UserID: u.ID},
&Access{UserID: u.ID},
&Watch{UserID: u.ID},
&Star{UID: u.ID},
&Follow{FollowID: u.ID},
&Action{UserID: u.ID},
&IssueUser{UID: u.ID},
&EmailAddress{UID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
// ***** START: PublicKey *****
keys := make([]*PublicKey, 0, 10)
if err = e.Find(&keys, &PublicKey{OwnerID: u.Id}); err != nil {
if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("get all public keys: %v", err)
}
for _, key := range keys {
if err = deletePublicKey(e, key.ID); err != nil {
return fmt.Errorf("deletePublicKey: %v", err)
}
keyIDs := make([]int64, len(keys))
for i := range keys {
keyIDs[i] = keys[i].ID
}
if err = deletePublicKeys(e, keyIDs...); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)
}
// ***** END: PublicKey *****
// Clear assignee.
if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.Id); err != nil {
if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.ID); err != nil {
return fmt.Errorf("clear assignee: %v", err)
}
if _, err = e.Id(u.Id).Delete(new(User)); err != nil {
if _, err = e.Id(u.ID).Delete(new(User)); err != nil {
return fmt.Errorf("Delete: %v", err)
}
@@ -762,7 +794,6 @@ func deleteUser(e *xorm.Session, u *User) error {
// Note: There are something just cannot be roll back,
// so just keep error logs of those operations.
RewriteAllPublicKeys()
os.RemoveAll(UserPath(u.Name))
os.Remove(u.CustomAvatarPath())
@@ -783,15 +814,20 @@ func DeleteUser(u *User) (err error) {
return err
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
}
// DeleteInactivateUsers deletes all inactivate users and email addresses.
func DeleteInactivateUsers() (err error) {
users := make([]*User, 0, 10)
if err = x.Where("is_active=?", false).Find(&users); err != nil {
if err = x.Where("is_active = ?", false).Find(&users); err != nil {
return fmt.Errorf("get all inactive users: %v", err)
}
// FIXME: should only update authorized_keys file once after all deletions.
for _, u := range users {
if err = DeleteUser(u); err != nil {
// Ignore users that were set inactive by admin.
@@ -802,7 +838,7 @@ func DeleteInactivateUsers() (err error) {
}
}
_, err = x.Where("is_activated=?", false).Delete(new(EmailAddress))
_, err = x.Where("is_activated = ?", false).Delete(new(EmailAddress))
return err
}
@@ -840,7 +876,7 @@ func GetUserByID(id int64) (*User, error) {
// GetAssigneeByID returns the user with write access of repository by given ID.
func GetAssigneeByID(repo *Repository, userID int64) (*User, error) {
has, err := HasAccess(&User{Id: userID}, repo, ACCESS_MODE_WRITE)
has, err := HasAccess(&User{ID: userID}, repo, ACCESS_MODE_WRITE)
if err != nil {
return nil, err
} else if !has {
@@ -877,160 +913,19 @@ 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)
if err != nil {
continue
}
ids = append(ids, u.Id)
ids = append(ids, u.ID)
}
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 +998,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.UI.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.UI.ExplorePagingNum {
opts.PageSize = setting.UI.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().Unix()
w.UpdatedUnix = w.CreatedUnix
}
func (w *Webhook) BeforeUpdate() {
w.UpdatedUnix = time.Now().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
}
@@ -526,7 +573,7 @@ func (t *HookTask) deliver() {
}
defer func() {
t.Delivered = time.Now().UTC().UnixNano()
t.Delivered = time.Now().UnixNano()
if t.IsSucceed {
log.Trace("Hook delivered: %s", t.UUID)
} else {
@@ -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

@@ -36,11 +36,12 @@ type InstallForm struct {
RegisterConfirm bool
MailNotify bool
OfflineMode bool
DisableGravatar bool
DisableRegistration bool
EnableCaptcha bool
RequireSignInView bool
OfflineMode bool
DisableGravatar bool
EnableFederatedAvatar bool
DisableRegistration bool
EnableCaptcha bool
RequireSignInView bool
AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"`
AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
@@ -93,19 +94,25 @@ type UpdateProfileForm struct {
Email string `binding:"Required;Email;MaxSize(254)"`
Website string `binding:"Url;MaxSize(100)"`
Location string `binding:"MaxSize(50)"`
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
}
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
type UploadAvatarForm struct {
Enable bool
Avatar *multipart.FileHeader
const (
AVATAR_LOCAL string = "local"
AVATAR_BYMAIL string = "bymail"
)
type AvatarForm struct {
Source string
Avatar *multipart.FileHeader
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
Federavatar bool
}
func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
func (f *AvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/issue9/identicon"
)
const _RANDOM_AVATAR_SIZE = 200
const AVATAR_SIZE = 290
// RandomImage generates and returns a random avatar image unique to input data
// in custom size (height and width).
@@ -39,5 +39,5 @@ func RandomImageSize(size int, data []byte) (image.Image, error) {
// RandomImage generates and returns a random avatar image unique to input data
// in default size (height and width).
func RandomImage(data []byte) (image.Image, error) {
return RandomImageSize(_RANDOM_AVATAR_SIZE, data)
return RandomImageSize(AVATAR_SIZE, data)
}

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()
@@ -203,13 +204,24 @@ func HashEmail(email string) string {
return hex.EncodeToString(h.Sum(nil))
}
// AvatarLink returns avatar link by given email.
func AvatarLink(email string) string {
if setting.DisableGravatar || setting.OfflineMode {
return setting.AppSubUrl + "/img/avatar_default.jpg"
// AvatarLink returns relative avatar link to the site domain by given email,
// which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service.
func AvatarLink(email string) (url string) {
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
var err error
url, err = setting.LibravatarService.FromEmail(email)
if err != nil {
log.Error(1, "LibravatarService.FromEmail: %v", err)
}
}
return setting.GravatarSource + HashEmail(email)
if len(url) == 0 && !setting.DisableGravatar {
url = setting.GravatarSource + HashEmail(email)
}
if len(url) == 0 {
url = setting.AppSubUrl + "/img/avatar_default.png"
}
return url
}
// Seconds-based time units
@@ -521,3 +533,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.
@@ -158,6 +105,19 @@ func (ctx *Context) Handle(status int, title string, err error) {
ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
}
// HandleError use error check function to determine if server should
// response as client input error or server internal error.
// It responses with given status code for client error,
// or error context description for logging purpose of server error.
func (ctx *Context) HandleError(title string, errck func(error) bool, err error, status int) {
if errck(err) {
ctx.Error(status, err.Error())
return
}
ctx.Handle(500, title, err)
}
func (ctx *Context) HandleText(status int, title string) {
if (status/100 == 4) || (status/100 == 5) {
log.Error(4, "%s", title)
@@ -165,25 +125,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 +152,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, "/")
@@ -225,7 +169,7 @@ func Contexter() macaron.Handler {
ctx.IsSigned = true
ctx.Data["IsSigned"] = ctx.IsSigned
ctx.Data["SignedUser"] = ctx.User
ctx.Data["SignedUserID"] = ctx.User.Id
ctx.Data["SignedUserID"] = ctx.User.ID
ctx.Data["SignedUserName"] = ctx.User.Name
ctx.Data["IsAdmin"] = ctx.User.IsAdmin
} 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 (
"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
@@ -61,13 +72,13 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
ctx.Org.IsTeamMember = true
ctx.Org.IsTeamAdmin = true
} else if ctx.IsSigned {
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id)
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.ID)
if ctx.Org.IsOwner {
ctx.Org.IsMember = true
ctx.Org.IsTeamMember = true
ctx.Org.IsTeamAdmin = true
} else {
if org.IsOrgMember(ctx.User.Id) {
if org.IsOrgMember(ctx.User.ID) {
ctx.Org.IsMember = true
}
}
@@ -90,11 +101,12 @@ 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 {
if err := org.GetUserTeams(ctx.User.Id); err != nil {
org.Teams, err = org.GetUserTeams(ctx.User.ID)
if err != nil {
ctx.Handle(500, "GetUserTeams", err)
return
}

View File

@@ -2,13 +2,14 @@
// 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"
"path"
"strings"
"github.com/Unknwon/com"
"gopkg.in/macaron.v1"
"github.com/gogits/git-module"
@@ -18,6 +19,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 {
@@ -34,6 +85,24 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
}
}
// composeGoGetImport returns go-get-import meta content.
func composeGoGetImport(owner, repo string) string {
return path.Join(setting.Domain, setting.AppSubUrl, owner, repo)
}
// earlyResponseForGoGetMeta responses appropriate go-get meta with status 200
// if user does not have actual access to the requested repository,
// or the owner or repository does not exist at all.
// This is particular a workaround for "go get" command which does not respect
// .netrc file.
func earlyResponseForGoGetMeta(ctx *Context) {
ctx.PlainText(200, []byte(com.Expand(`<meta name="go-import" content="{GoGetImport} git {CloneLink}">`,
map[string]string{
"GoGetImport": composeGoGetImport(ctx.Params(":username"), ctx.Params(":reponame")),
"CloneLink": models.ComposeHTTPSCloneURL(ctx.Params(":username"), ctx.Params(":reponame")),
})))
}
func RepoAssignment(args ...bool) macaron.Handler {
return func(ctx *Context) {
var (
@@ -62,6 +131,10 @@ func RepoAssignment(args ...bool) macaron.Handler {
owner, err = models.GetUserByName(userName)
if err != nil {
if models.IsErrUserNotExist(err) {
if ctx.Query("go-get") == "1" {
earlyResponseForGoGetMeta(ctx)
return
}
ctx.Handle(404, "GetUserByName", err)
} else {
ctx.Handle(500, "GetUserByName", err)
@@ -72,9 +145,13 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Repo.Owner = owner
// Get repository.
repo, err := models.GetRepositoryByName(owner.Id, repoName)
repo, err := models.GetRepositoryByName(owner.ID, repoName)
if err != nil {
if models.IsErrRepoNotExist(err) {
if ctx.Query("go-get") == "1" {
earlyResponseForGoGetMeta(ctx)
return
}
ctx.Handle(404, "GetRepositoryByName", err)
} else {
ctx.Handle(500, "GetRepositoryByName", err)
@@ -99,6 +176,10 @@ func RepoAssignment(args ...bool) macaron.Handler {
// Check access.
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
if ctx.Query("go-get") == "1" {
earlyResponseForGoGetMeta(ctx)
return
}
ctx.Handle(404, "no access right", err)
return
}
@@ -110,6 +191,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 +205,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,39 +224,13 @@ 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()
if ctx.IsSigned {
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID)
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID)
}
// repo is bare and display enable
@@ -209,12 +265,42 @@ 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 or have fored repository can propose a new pull request.
if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) {
// 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)
ctx.Data["GoGetImport"] = composeGoGetImport(owner.Name, repo.Name)
prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)
ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"

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.
@@ -70,7 +75,7 @@ func IsReadmeFile(name string) bool {
var (
// MentionPattern matches string that mentions someone, e.g. @Unknwon
MentionPattern = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_\.]+`)
MentionPattern = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z-_\.]+`)
// CommitPattern matches link to certain commit with or without trailing hash,
// e.g. https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2
@@ -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,34 +230,39 @@ 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
}
// RenderSha1CurrentPattern renders SHA1 strings to corresponding links that assumes in the same repository.
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
ms := Sha1CurrentPattern.FindAll(rawBytes, -1)
for _, m := range ms {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, base.ShortSha(string(m)))), -1)
}
return rawBytes
return []byte(Sha1CurrentPattern.ReplaceAllStringFunc(string(rawBytes[:]), func(m string) string {
return fmt.Sprintf(`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, base.ShortSha(string(m)))
}))
}
// RenderSpecialLink renders mentions, indexes and SHA1 strings to corresponding links.
@@ -357,6 +386,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

@@ -20,6 +20,7 @@ import (
_ "github.com/go-macaron/cache/redis"
"github.com/go-macaron/session"
_ "github.com/go-macaron/session/redis"
"github.com/strk/go-libravatar"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/bindata"
@@ -54,7 +55,7 @@ var (
AppSubUrl string
AppSubUrlDepth int // Number of slashes
AppPath string
AppDataPath = "data"
AppDataPath string
// Server settings
Protocol Scheme
@@ -115,14 +116,23 @@ var (
ScriptType string
// UI settings
ExplorePagingNum int
IssuePagingNum int
FeedMaxCommitNum int
AdminUserPagingNum int
AdminRepoPagingNum int
AdminNoticePagingNum int
AdminOrgPagingNum int
ThemeColorMetaTag string
UI struct {
ExplorePagingNum int
IssuePagingNum int
FeedMaxCommitNum int
ThemeColorMetaTag string
MaxDisplayFileSize int64
Admin struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
} `ini:"ui.admin"`
User struct {
RepoPagingNum int
} `ini:"ui.user"`
}
// Markdown sttings
Markdown struct {
@@ -131,9 +141,11 @@ var (
}
// Picture settings
AvatarUploadPath string
GravatarSource string
DisableGravatar bool
AvatarUploadPath string
GravatarSource string
DisableGravatar bool
EnableFederatedAvatar bool
LibravatarService *libravatar.Libravatar
// Log settings
LogRootPath string
@@ -156,19 +168,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 +192,32 @@ var (
} `ini:"cron.check_repo_stats"`
}
// Git settings
Git struct {
DisableDiffHighlight bool
MaxGitDiffLines int
MaxGitDiffLineCharacters int
MaxGitDiffFiles int
GCArgs []string `delim:" "`
Timeout struct {
Migrate int
Mirror int
Clone int
Pull int
GC int `ini:"GC"`
} `ini:"git.timeout"`
}
// Mirror settings
Mirror struct {
DefaultInterval int
}
// API settings
API struct {
MaxResponseItems int
}
// I18n settings
Langs, Names []string
dateLangs map[string]string
@@ -263,6 +290,19 @@ func forcePathSeparator(path string) {
}
}
// IsRunUserMatchCurrentUser returns false if configured run user does not match
// actual user that runs the app. The first return value is the actual user name.
// This check is ignored under Windows since SSH remote login is not the main
// method to login on Windows.
func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
if IsWindows {
return "", true
}
currentUser := user.CurrentUsername()
return currentUser, runUser == currentUser
}
// NewContext initializes configuration context.
// NOTE: do not print any log except error.
func NewContext() {
@@ -316,6 +356,7 @@ func NewContext() {
log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppUrl, err)
}
// Suburl should start with '/' and end without '/', such as '/{subpath}'.
// This value is empty if site does not have sub-url.
AppSubUrl = strings.TrimSuffix(url.Path, "/")
AppSubUrlDepth = strings.Count(AppSubUrl, "/")
@@ -330,10 +371,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 +401,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()
@@ -413,10 +449,12 @@ func NewContext() {
}[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
RunUser = Cfg.Section("").Key("RUN_USER").String()
curUser := user.CurrentUsername()
// Does not check run user when the install lock is off.
if InstallLock && RunUser != curUser {
log.Fatal(4, "Expect user(%s) but current user is: %s", RunUser, curUser)
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
if !match {
log.Fatal(4, "Expect user '%s' but current user is: %s", RunUser, currentUser)
}
}
// Determine and create root git repository path.
@@ -433,19 +471,6 @@ func NewContext() {
log.Fatal(4, "Fail to map Repository settings: %v", err)
}
// UI settings.
sec = Cfg.Section("ui")
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)
sec = Cfg.Section("ui.admin")
AdminUserPagingNum = sec.Key("USER_PAGING_NUM").MustInt(50)
AdminRepoPagingNum = sec.Key("REPO_PAGING_NUM").MustInt(50)
AdminNoticePagingNum = sec.Key("NOTICE_PAGING_NUM").MustInt(50)
AdminOrgPagingNum = sec.Key("ORG_PAGING_NUM").MustInt(50)
ThemeColorMetaTag = sec.Key("THEME_COLOR_META_TAG").MustString("#ff5343")
sec = Cfg.Section("picture")
AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
forcePathSeparator(AvatarUploadPath)
@@ -461,16 +486,45 @@ func NewContext() {
GravatarSource = source
}
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool()
if OfflineMode {
DisableGravatar = true
EnableFederatedAvatar = false
}
if DisableGravatar {
EnableFederatedAvatar = false
}
if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
if EnableFederatedAvatar {
LibravatarService = libravatar.New()
parts := strings.Split(GravatarSource, "/")
if len(parts) >= 3 {
if parts[0] == "https:" {
LibravatarService.SetUseHTTPS(true)
LibravatarService.SetSecureFallbackHost(parts[2])
} else {
LibravatarService.SetUseHTTPS(false)
LibravatarService.SetFallbackHost(parts[2])
}
}
}
if err = Cfg.Section("ui").MapTo(&UI); err != nil {
log.Fatal(4, "Fail to map UI settings: %v", err)
} else 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("mirror").MapTo(&Mirror); err != nil {
log.Fatal(4, "Fail to map API settings: %v", err)
} else if err = Cfg.Section("api").MapTo(&API); err != nil {
log.Fatal(4, "Fail to map API settings: %v", err)
}
if Mirror.DefaultInterval <= 0 {
Mirror.DefaultInterval = 24
}
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
@@ -616,16 +670,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 +695,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"
)
@@ -95,13 +96,12 @@ func NewFuncMap() []template.FuncMap {
"ShortSha": base.ShortSha,
"MD5": base.EncodeMD5,
"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 {
return setting.ThemeColorMetaTag
return setting.UI.ThemeColorMetaTag
},
}}
}
@@ -114,10 +114,6 @@ func Str2html(raw string) template.HTML {
return template.HTML(markdown.Sanitizer.Sanitize(raw))
}
func Range(l int) []int {
return make([]int, l)
}
func List(l *list.List) chan interface{} {
e := l.Front()
c := make(chan interface{})
@@ -135,7 +131,7 @@ func Sha1(str string) string {
return base.EncodeSha1(str)
}
func ToUtf8WithErr(content []byte) (error, string) {
func ToUTF8WithErr(content []byte) (error, string) {
charsetLabel, err := base.DetectEncoding(content)
if err != nil {
return err, ""
@@ -158,8 +154,8 @@ func ToUtf8WithErr(content []byte) (error, string) {
return err, result
}
func ToUtf8(content string) string {
_, res := ToUtf8WithErr([]byte(content))
func ToUTF8(content string) string {
_, res := ToUTF8WithErr([]byte(content))
return res
}
@@ -240,7 +236,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 +251,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 {

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