mirror of
https://github.com/gogs/gogs.git
synced 2026-03-01 09:40:55 +01:00
Compare commits
409 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee14db51e | ||
|
|
5d35578811 | ||
|
|
d09fca3ca9 | ||
|
|
dadd35b636 | ||
|
|
c2afdf2192 | ||
|
|
152e715999 | ||
|
|
99c2ae7b35 | ||
|
|
cd9b926af7 | ||
|
|
9ac46fb983 | ||
|
|
8516dfcb6c | ||
|
|
c1ecb6c60a | ||
|
|
43297148b2 | ||
|
|
c0c1a4b01b | ||
|
|
47a3243ff1 | ||
|
|
22e14a0a67 | ||
|
|
48a0b5b026 | ||
|
|
16eb2eb6a3 | ||
|
|
e6ec1ca1f8 | ||
|
|
6f90835f95 | ||
|
|
643142acab | ||
|
|
7c31f235da | ||
|
|
4f40019130 | ||
|
|
780cc2d110 | ||
|
|
2a13f682e0 | ||
|
|
28cf0e6aaa | ||
|
|
92fb30c526 | ||
|
|
9f44c26789 | ||
|
|
3738b6399e | ||
|
|
62b0dc4853 | ||
|
|
429c92c0ce | ||
|
|
579e5e4fee | ||
|
|
ba27d71abe | ||
|
|
7115e3a4d5 | ||
|
|
0114fdcba4 | ||
|
|
dad5c15520 | ||
|
|
6e171c5225 | ||
|
|
f0b5c3b90a | ||
|
|
c30b856d14 | ||
|
|
13c106af77 | ||
|
|
ce1e4348da | ||
|
|
13a8823bd3 | ||
|
|
bbca2916f7 | ||
|
|
37305a59ca | ||
|
|
bb359a74f1 | ||
|
|
6b98d58906 | ||
|
|
8dca9f95fa | ||
|
|
f50e568fd1 | ||
|
|
f8a48ffaad | ||
|
|
67fb0fe6a5 | ||
|
|
0b273ac4d5 | ||
|
|
84b56c3c53 | ||
|
|
06602a84ff | ||
|
|
b710f6bd65 | ||
|
|
95bd19c509 | ||
|
|
7c5710d31f | ||
|
|
7f7216be6e | ||
|
|
ec332cf903 | ||
|
|
2c5411b00c | ||
|
|
a00c932bbc | ||
|
|
6f9a95f830 | ||
|
|
8bf57be9ba | ||
|
|
b1504ed99a | ||
|
|
9349def72e | ||
|
|
6cda35a75f | ||
|
|
2625193a48 | ||
|
|
f3c3258921 | ||
|
|
4042d1f0c3 | ||
|
|
4a46613916 | ||
|
|
6c8fcb3af2 | ||
|
|
61e27dedf7 | ||
|
|
94392a7af3 | ||
|
|
cc647ba9d5 | ||
|
|
5e89485cec | ||
|
|
8637e67e6f | ||
|
|
4a19fd6441 | ||
|
|
54e0ada9d5 | ||
|
|
cd89f6c502 | ||
|
|
660e7a178a | ||
|
|
15845cb287 | ||
|
|
d0a0239bac | ||
|
|
7e7613cdec | ||
|
|
a5b88c4d0c | ||
|
|
dccb0c15b9 | ||
|
|
3f7f4852ef | ||
|
|
0f33b04c87 | ||
|
|
fd3b9ca3aa | ||
|
|
f1a5a4277d | ||
|
|
f59d2dd034 | ||
|
|
5be881756b | ||
|
|
4296427214 | ||
|
|
7551141dbe | ||
|
|
5544a7037b | ||
|
|
dbed39ba05 | ||
|
|
aa1fc30b89 | ||
|
|
fa12c282f6 | ||
|
|
25b23c4bc9 | ||
|
|
7eafe3213f | ||
|
|
2cb04db526 | ||
|
|
96f92e6105 | ||
|
|
a47aef5460 | ||
|
|
1dd003bd4c | ||
|
|
70fbcd2f27 | ||
|
|
5850308a37 | ||
|
|
53c573ed02 | ||
|
|
10b47eddd2 | ||
|
|
5a9709fa9d | ||
|
|
7e9b42c87d | ||
|
|
b6c14f8b21 | ||
|
|
5077408d78 | ||
|
|
0885784f13 | ||
|
|
3380c946e1 | ||
|
|
d625e41c6c | ||
|
|
eb1bfe0e59 | ||
|
|
042d350762 | ||
|
|
0f26f3678a | ||
|
|
6a81632e36 | ||
|
|
b756806ee9 | ||
|
|
81e6f82caf | ||
|
|
29f76f3936 | ||
|
|
ea192147ea | ||
|
|
99812a80fd | ||
|
|
8ad92bb8a4 | ||
|
|
b85927e488 | ||
|
|
87b408a2e5 | ||
|
|
fc68fb951c | ||
|
|
5448d29b2e | ||
|
|
bb51eb5188 | ||
|
|
89f71b44f7 | ||
|
|
c5d4a9e046 | ||
|
|
edd786446c | ||
|
|
b0b88d9bc5 | ||
|
|
15b0cbe318 | ||
|
|
9f0c571238 | ||
|
|
f70343660d | ||
|
|
c8b45ecc27 | ||
|
|
9e8a8867ea | ||
|
|
2c82fc3edb | ||
|
|
bbe866122d | ||
|
|
87954dbfeb | ||
|
|
699c71d319 | ||
|
|
21f25799b4 | ||
|
|
90af997fec | ||
|
|
b73318bc62 | ||
|
|
e5bf4281b5 | ||
|
|
0c2b9bbb2b | ||
|
|
99385db0c4 | ||
|
|
90dd0657b5 | ||
|
|
ec92565f23 | ||
|
|
2772791fda | ||
|
|
08c976f811 | ||
|
|
72dd299ca0 | ||
|
|
30fda0f1ae | ||
|
|
ab9c5fb5e7 | ||
|
|
28dc5bb566 | ||
|
|
cf6d321991 | ||
|
|
50422f1fc2 | ||
|
|
db3d393576 | ||
|
|
2f105f3979 | ||
|
|
ee28fd9255 | ||
|
|
13d492e92a | ||
|
|
e7fd65f0cf | ||
|
|
2eeb0ec9b0 | ||
|
|
b1133c9934 | ||
|
|
991ce42c48 | ||
|
|
10dc330640 | ||
|
|
dfab54d5a2 | ||
|
|
3e22ae3412 | ||
|
|
55b4e77a5e | ||
|
|
ad7ea88923 | ||
|
|
f2884d8e31 | ||
|
|
36a63dd059 | ||
|
|
03ba257ad2 | ||
|
|
fe60ca408b | ||
|
|
0402c803c6 | ||
|
|
29ccf047d8 | ||
|
|
8aa0a76702 | ||
|
|
2d76de2574 | ||
|
|
4d8b905541 | ||
|
|
452aefd025 | ||
|
|
899e799459 | ||
|
|
2295fafb34 | ||
|
|
a562228c5e | ||
|
|
e74630ae3b | ||
|
|
1f2e173a74 | ||
|
|
46e96c008c | ||
|
|
256cd6374a | ||
|
|
57a47bbc05 | ||
|
|
024fcc836b | ||
|
|
250be011c7 | ||
|
|
4e822c1911 | ||
|
|
26d52ceb48 | ||
|
|
d90acacd86 | ||
|
|
69f5308761 | ||
|
|
4b5e09e4d6 | ||
|
|
4f78abe7dc | ||
|
|
e63b2881b1 | ||
|
|
745167d57a | ||
|
|
d7bdc1de8d | ||
|
|
c912494609 | ||
|
|
69dae1ec1c | ||
|
|
cf85e9eb7b | ||
|
|
599716bb1b | ||
|
|
ae88d76032 | ||
|
|
9266f28822 | ||
|
|
6488ee12be | ||
|
|
c2fb01a257 | ||
|
|
5761342f32 | ||
|
|
57af7432fc | ||
|
|
1c7dcdd6b9 | ||
|
|
25b3836418 | ||
|
|
5aa2bf86f4 | ||
|
|
b0eb47cb1c | ||
|
|
e7a4f96fb6 | ||
|
|
60110adc06 | ||
|
|
5ff2dfb23e | ||
|
|
eac32419fc | ||
|
|
e3d3d424b2 | ||
|
|
971e2c3bd6 | ||
|
|
c083d76567 | ||
|
|
52322ef624 | ||
|
|
a4ea3bd015 | ||
|
|
3d93532c87 | ||
|
|
fff615d5fc | ||
|
|
f1b8d52eb3 | ||
|
|
7ca5f8f119 | ||
|
|
194a742fb9 | ||
|
|
160956dd31 | ||
|
|
089bacd54e | ||
|
|
d950bf68e3 | ||
|
|
7796c9e122 | ||
|
|
528ec9bffd | ||
|
|
32ec4734f9 | ||
|
|
6a98e7d914 | ||
|
|
a752f09055 | ||
|
|
846bf2ca9f | ||
|
|
f4ab50501e | ||
|
|
de10387f41 | ||
|
|
1faaaeb3d9 | ||
|
|
12cb84b97f | ||
|
|
fdcca9292e | ||
|
|
a1f717f65a | ||
|
|
70a281a39b | ||
|
|
9fcf66f0e0 | ||
|
|
98b152030d | ||
|
|
467d7dacb6 | ||
|
|
d62ab49978 | ||
|
|
e30c701386 | ||
|
|
401bf944ef | ||
|
|
326c982660 | ||
|
|
4b25bdfbc4 | ||
|
|
528682a294 | ||
|
|
6aa00f7bcf | ||
|
|
f485fcde96 | ||
|
|
6f6b37f148 | ||
|
|
99c3a9390f | ||
|
|
f0df46c88a | ||
|
|
e84ac64964 | ||
|
|
3a30c06345 | ||
|
|
a10ca2c5f6 | ||
|
|
927d9f092b | ||
|
|
7938506e07 | ||
|
|
6f7276278d | ||
|
|
743d22669a | ||
|
|
84841c8c4b | ||
|
|
274a2ca528 | ||
|
|
d4aaef90e6 | ||
|
|
6efb1e5626 | ||
|
|
73b4acbb63 | ||
|
|
8a248696e9 | ||
|
|
8b35c194ec | ||
|
|
ac05f88641 | ||
|
|
4bbb878d20 | ||
|
|
2ce60ff314 | ||
|
|
17a4d8a5e5 | ||
|
|
04592c385b | ||
|
|
bc00da1721 | ||
|
|
76a0e43e88 | ||
|
|
24caccccdd | ||
|
|
26342b0c24 | ||
|
|
a4eaddff81 | ||
|
|
c041273dd3 | ||
|
|
fb970b9d87 | ||
|
|
0240f520ab | ||
|
|
3d105733a9 | ||
|
|
8df3ba96f3 | ||
|
|
d35a1c30f4 | ||
|
|
e9ae926e04 | ||
|
|
28c03f1147 | ||
|
|
84d9aff8a2 | ||
|
|
12d30255a7 | ||
|
|
7826eae452 | ||
|
|
8a2347592d | ||
|
|
bcd4adb3a0 | ||
|
|
bf5faf76eb | ||
|
|
f473895c41 | ||
|
|
fbf43c31e5 | ||
|
|
3c0c7a9f83 | ||
|
|
13216c5c20 | ||
|
|
6be9a2c1db | ||
|
|
d8612f7704 | ||
|
|
0a78d99a4d | ||
|
|
3df8eb60e3 | ||
|
|
0325bec283 | ||
|
|
dfad51fe9e | ||
|
|
7049cb9d97 | ||
|
|
78b8b63774 | ||
|
|
ba314a7a36 | ||
|
|
39356f4238 | ||
|
|
b3c05026df | ||
|
|
ce36fd7a49 | ||
|
|
69e00f9948 | ||
|
|
3257df0da3 | ||
|
|
0f2869069b | ||
|
|
a27c6f4b75 | ||
|
|
d27ca649c7 | ||
|
|
d9900e4dbc | ||
|
|
e75a1444af | ||
|
|
b35157f4ff | ||
|
|
762ab056a2 | ||
|
|
78481f0e42 | ||
|
|
746c7fd4e7 | ||
|
|
7f26ae0b45 | ||
|
|
b5948f2e71 | ||
|
|
79a1bfd963 | ||
|
|
ac53bb593d | ||
|
|
dd36c431ec | ||
|
|
b1d41cfa60 | ||
|
|
9dda9ef07c | ||
|
|
9a43fcb61c | ||
|
|
5ec8ef0230 | ||
|
|
d3db1b2591 | ||
|
|
3decc0b3d6 | ||
|
|
98b58fa050 | ||
|
|
5e11341232 | ||
|
|
90e93b1f3a | ||
|
|
e6f927f61a | ||
|
|
60ae8ac3d2 | ||
|
|
004fb30ebe | ||
|
|
3fb4f7f498 | ||
|
|
9e09e48502 | ||
|
|
c79774e8d4 | ||
|
|
d6b09c35f7 | ||
|
|
0048980da5 | ||
|
|
d169d00be6 | ||
|
|
ff731ea07d | ||
|
|
9a5a27ea8d | ||
|
|
94d7b62922 | ||
|
|
2df42e369e | ||
|
|
1f5bb08c25 | ||
|
|
01ff65a93e | ||
|
|
8540043c45 | ||
|
|
f57adf3637 | ||
|
|
a75fa58e1c | ||
|
|
6ccb2d36cf | ||
|
|
414e5f09c7 | ||
|
|
a04596659b | ||
|
|
149d62a648 | ||
|
|
db3905c0a3 | ||
|
|
3253e3c5aa | ||
|
|
c9321550e0 | ||
|
|
ac390d28b8 | ||
|
|
561e5f9ccb | ||
|
|
9df5c39bca | ||
|
|
9976fc6782 | ||
|
|
8966f5635d | ||
|
|
85d7afeba0 | ||
|
|
63e21c146a | ||
|
|
9bd9ad4205 | ||
|
|
dd6faf7f9b | ||
|
|
db4da7beec | ||
|
|
b4f47a7623 | ||
|
|
af8eccc02e | ||
|
|
820be19cf5 | ||
|
|
d733efc1cc | ||
|
|
985a0f3450 | ||
|
|
322515a50b | ||
|
|
13e1fa6789 | ||
|
|
c6277cce51 | ||
|
|
6530375dbf | ||
|
|
449a6e490b | ||
|
|
ebea20b4e7 | ||
|
|
f76d821bda | ||
|
|
263304b6b7 | ||
|
|
73e98c91c3 | ||
|
|
2bf8494332 | ||
|
|
df2bdf7ea3 | ||
|
|
514382e2eb | ||
|
|
cb1eadc276 | ||
|
|
1314ba219e | ||
|
|
5267dce210 | ||
|
|
97c48da49f | ||
|
|
1e74ee51ff | ||
|
|
067edcdb90 | ||
|
|
792c13cf0a | ||
|
|
3bd7d3b1c5 | ||
|
|
af847ef94e | ||
|
|
bfed3ea7d3 | ||
|
|
b44e4d7cb0 | ||
|
|
eed9966ad6 | ||
|
|
affa3c2dbf | ||
|
|
6775ac7334 | ||
|
|
2c626371b0 | ||
|
|
3cacec9163 | ||
|
|
ad513a20e9 | ||
|
|
72a8fa3bc8 | ||
|
|
0c9a616326 | ||
|
|
0e9bc2d410 | ||
|
|
1d3ec27cb7 | ||
|
|
a0cd59bd0e |
@@ -1,6 +1,6 @@
|
||||
[run]
|
||||
init_cmds = [
|
||||
["make", "build-dev", "TAGS=sqlite"],
|
||||
["make", "build-dev"],
|
||||
["./gogs", "web"]
|
||||
]
|
||||
watch_all = true
|
||||
@@ -14,6 +14,6 @@ watch_exts = [".go"]
|
||||
ignore_files = [".+_test.go"]
|
||||
build_delay = 1500
|
||||
cmds = [
|
||||
["make", "build-dev", "TAGS=sqlite"], # cert pam tidb
|
||||
["make", "build-dev"], # TAGS=sqlite cert pam tidb
|
||||
["./gogs", "web"]
|
||||
]
|
||||
7
.codebeatignore
Normal file
7
.codebeatignore
Normal file
@@ -0,0 +1,7 @@
|
||||
conf/**
|
||||
docker/**
|
||||
modules/bindata/**
|
||||
packager/**
|
||||
public/**
|
||||
scripts/**
|
||||
templates/**
|
||||
7
.codebeatsettings
Normal file
7
.codebeatsettings
Normal 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]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -5,8 +5,21 @@ root = true
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.yml]
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.tmpl]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.{less,yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal 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
|
||||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -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
|
||||
|
||||
|
||||
21
.github/ISSUE_TEMPLATE.md
vendored
21
.github/ISSUE_TEMPLATE.md
vendored
@@ -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:
|
||||
|
||||
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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
1
.gitignore
vendored
@@ -17,3 +17,4 @@ output*
|
||||
gogs.sublime-project
|
||||
gogs.sublime-workspace
|
||||
/release
|
||||
vendor
|
||||
|
||||
63
.gopmfile
63
.gopmfile
@@ -3,52 +3,57 @@ 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/urfave/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:5e0c133
|
||||
github.com/gogits/go-gogs-client = commit:c52f7ee
|
||||
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/editorconfig/editorconfig-core-go.v1 = commit:a872f05
|
||||
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
|
||||
|
||||
|
||||
2
.mailmap
Normal file
2
.mailmap
Normal file
@@ -0,0 +1,2 @@
|
||||
Unknwon <u@gogs.io> <joe2010xtmf@163.com>
|
||||
Unknwon <u@gogs.io> 无闻 <u@gogs.io>
|
||||
@@ -4,6 +4,7 @@ go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -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
|
||||
|
||||
23
Makefile
23
Makefile
@@ -6,24 +6,37 @@ 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
|
||||
|
||||
build: $(GENERATED)
|
||||
go install -v -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
all: build
|
||||
|
||||
check: test
|
||||
|
||||
dist: release
|
||||
|
||||
govet:
|
||||
go tool vet -composites=false -methods=false -structtags=false .
|
||||
$(GOVET) gogs.go
|
||||
$(GOVET) models modules routers
|
||||
|
||||
build: $(GENERATED)
|
||||
go install $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
|
||||
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:
|
||||
|
||||
35
README.md
35
README.md
@@ -3,7 +3,7 @@ Gogs - Go Git Service [
|
||||
|
||||
##### Current version: 0.9.0
|
||||
##### Current tip version: 0.9.97 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
|
||||
|
||||
| Web | UI | Preview |
|
||||
|:-------------:|:-------:|:-------:|
|
||||
@@ -18,7 +18,7 @@ Gogs - Go Git Service [ 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
|
||||
|
||||
@@ -41,15 +41,17 @@ The goal of this project is to make the easiest, fastest, and most painless way
|
||||
- SMTP/LDAP/Reverse proxy authentication
|
||||
- Reverse proxy with sub-path
|
||||
- Account/Organization/Repository management
|
||||
- Add/Remove repository collaborators
|
||||
- Repository/Organization webhooks (including Slack)
|
||||
- Repository Git hooks/deploy keys
|
||||
- Repository issues, pull requests and wiki
|
||||
- Add/Remove repository collaborators
|
||||
- Gravatar and custom source
|
||||
- Migrate and mirror repository and its wiki
|
||||
- Web editor for repository files and wiki
|
||||
- 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 +65,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 +79,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 +89,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 +101,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 +111,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
|
||||
|
||||
@@ -115,10 +122,10 @@ There are 5 ways to install Gogs:
|
||||
|
||||
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
|
||||
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
|
||||
- Thanks [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
|
||||
- Thanks [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
|
||||
|
||||
|
||||
28
README_ZH.md
28
README_ZH.md
@@ -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)!
|
||||
|
||||
## 功能特性
|
||||
|
||||
@@ -22,15 +22,17 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
- 支持 SMTP、LDAP 和反向代理的用户认证
|
||||
- 支持反向代理子路径
|
||||
- 支持用户、组织和仓库管理系统
|
||||
- 支持添加和删除仓库协作者
|
||||
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
|
||||
- 支持仓库 Git 钩子和部署密钥
|
||||
- 支持仓库工单(Issue)、合并请求(Pull Request)以及 Wiki
|
||||
- 支持添加和删除仓库协作者
|
||||
- 支持 Gravatar 以及自定义源
|
||||
- 支持迁移和镜像仓库以及它的 Wiki
|
||||
- 支持在线编辑仓库文件和 Wiki
|
||||
- 支持自定义源的 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 +46,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 +70,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 +80,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/)(团队交流)
|
||||
|
||||
### 产品支持
|
||||
|
||||
@@ -87,10 +91,10 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
|
||||
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
||||
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
|
||||
- 感谢 [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 服务赞助。
|
||||
|
||||
## 贡献成员
|
||||
|
||||
|
||||
70
cmd/admin.go
Normal file
70
cmd/admin.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var (
|
||||
CmdAdmin = cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "Preform admin operations on command line",
|
||||
Description: `Allow using internal logic of Gogs without hacking into the source code
|
||||
to make automatic initialization process more smoothly`,
|
||||
Subcommands: []cli.Command{
|
||||
subcmdCreateUser,
|
||||
},
|
||||
}
|
||||
|
||||
subcmdCreateUser = cli.Command{
|
||||
Name: "create-user",
|
||||
Usage: "Create a new user in database",
|
||||
Action: runCreateUser,
|
||||
Flags: []cli.Flag{
|
||||
stringFlag("name", "", "Username"),
|
||||
stringFlag("password", "", "User password"),
|
||||
stringFlag("email", "", "User email address"),
|
||||
boolFlag("admin", "User is an admin"),
|
||||
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func runCreateUser(c *cli.Context) error {
|
||||
if !c.IsSet("name") {
|
||||
return fmt.Errorf("Username is not specified")
|
||||
} else if !c.IsSet("password") {
|
||||
return fmt.Errorf("Password is not specified")
|
||||
} else if !c.IsSet("email") {
|
||||
return fmt.Errorf("Email is not specified")
|
||||
}
|
||||
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
setting.NewContext()
|
||||
models.LoadConfigs()
|
||||
models.SetEngine()
|
||||
|
||||
if err := models.CreateUser(&models.User{
|
||||
Name: c.String("name"),
|
||||
Email: c.String("email"),
|
||||
Passwd: c.String("password"),
|
||||
IsActive: true,
|
||||
IsAdmin: c.Bool("admin"),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CreateUser: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("New user '%s' has been successfully created!\n", c.String("name"))
|
||||
return nil
|
||||
}
|
||||
10
cmd/cert.go
10
cmd/cert.go
@@ -22,7 +22,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package cmd
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func stringFlag(name, value, usage string) cli.StringFlag {
|
||||
|
||||
29
cmd/dump.go
29
cmd/dump.go
@@ -14,7 +14,7 @@ import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/Unknwon/cae/zip"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
@@ -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.
|
||||
@@ -91,7 +96,13 @@ func runDump(ctx *cli.Context) {
|
||||
log.Fatalf("Fail to save %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
if err := os.Chmod(fileName, 0600); err != nil {
|
||||
log.Printf("Can't change file access permissions mask to 0600: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
|
||||
os.RemoveAll(TmpWorkDir)
|
||||
log.Printf("Finish dumping in file %s", fileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
19
cmd/serve.go
19
cmd/serve.go
@@ -14,8 +14,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/codegangsta/cli"
|
||||
git "github.com/gogits/git-module"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
@@ -100,10 +101,10 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
|
||||
}
|
||||
|
||||
if err = models.PushUpdate(models.PushUpdateOptions{
|
||||
RefName: task.RefName,
|
||||
RefFullName: task.RefName,
|
||||
OldCommitID: task.OldCommitID,
|
||||
NewCommitID: task.NewCommitID,
|
||||
PusherID: user.Id,
|
||||
PusherID: user.ID,
|
||||
PusherName: user.Name,
|
||||
RepoUserName: repoUser.Name,
|
||||
RepoName: reponame,
|
||||
@@ -113,7 +114,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
|
||||
|
||||
// Ask for running deliver hook and test pull request tasks.
|
||||
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
|
||||
strings.TrimPrefix(task.RefName, "refs/heads/") + "&secret=" + base.EncodeMD5(repoUser.Salt)
|
||||
strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
|
||||
log.GitLogger.Trace("Trigger task: %s", reqURL)
|
||||
|
||||
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
||||
@@ -129,7 +130,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 +139,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 +150,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 +176,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 +291,6 @@ func runServ(c *cli.Context) {
|
||||
fail("Internal error", "UpdatePublicKey: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package cmd
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
212
cmd/web.go
212
cmd/web.go
@@ -8,13 +8,13 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/fcgi"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/cache"
|
||||
"github.com/go-macaron/captcha"
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/go-macaron/toolbox"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/mcuadros/go-version"
|
||||
"github.com/urfave/cli"
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
@@ -34,8 +35,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"
|
||||
@@ -72,27 +73,35 @@ func checkVersion() {
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
|
||||
}
|
||||
if string(data) != setting.AppVer {
|
||||
log.Fatal(4, "Binary and template file version does not match, did you forget to recompile?")
|
||||
tplVer := string(data)
|
||||
if tplVer != setting.AppVer {
|
||||
if version.Compare(tplVer, setting.AppVer, ">") {
|
||||
log.Fatal(4, "Binary version is lower than template file version, did you forget to recompile Gogs?")
|
||||
} else {
|
||||
log.Fatal(4, "Binary version is higher than template file version, did you forget to update template files?")
|
||||
}
|
||||
}
|
||||
|
||||
// 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.4.1"},
|
||||
{"github.com/gogits/go-gogs-client", gogs.Version, "0.12.1"},
|
||||
}
|
||||
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 +132,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 {
|
||||
@@ -149,7 +163,7 @@ func newMacaron() *macaron.Macaron {
|
||||
m.Use(cache.Cacher(cache.Options{
|
||||
Adapter: setting.CacheAdapter,
|
||||
AdapterConfig: setting.CacheConn,
|
||||
Interval: setting.CacheInternal,
|
||||
Interval: setting.CacheInterval,
|
||||
}))
|
||||
m.Use(captcha.Captchaer(captcha.Options{
|
||||
SubURL: setting.AppSubUrl,
|
||||
@@ -157,6 +171,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 +184,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 +197,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 +208,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 +232,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 +247,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 +262,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 +311,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) {
|
||||
@@ -314,6 +330,7 @@ func runWeb(ctx *cli.Context) {
|
||||
defer fr.Close()
|
||||
|
||||
ctx.Header().Set("Cache-Control", "public,max-age=86400")
|
||||
ctx.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name))
|
||||
// Fix #312. Attachments with , in their name are not handled correctly by Google Chrome.
|
||||
// We must put the name in " manually.
|
||||
if err = repo.ServeData(ctx, "\""+attach.Name+"\"", fr); err != nil {
|
||||
@@ -332,8 +349,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 +364,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 +383,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 +401,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 +440,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,18 +449,19 @@ 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)
|
||||
@@ -453,14 +471,19 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Group("/:index", func() {
|
||||
m.Post("/title", repo.UpdateIssueTitle)
|
||||
m.Post("/content", repo.UpdateIssueContent)
|
||||
m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
|
||||
})
|
||||
})
|
||||
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())
|
||||
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
m.Group("/milestones", func() {
|
||||
m.Combo("/new").Get(repo.NewMilestone).
|
||||
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||
@@ -468,19 +491,46 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
|
||||
m.Get("/:id/:action", repo.ChangeMilestonStatus)
|
||||
m.Post("/delete", repo.DeleteMilestone)
|
||||
}, reqRepoWriter, middleware.RepoRef())
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
|
||||
m.Get("/edit/:tagname", repo.EditRelease)
|
||||
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", 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)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_edit/*").Get(repo.EditFile).
|
||||
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
|
||||
m.Combo("/_new/*").Get(repo.NewFile).
|
||||
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost)
|
||||
m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
|
||||
m.Combo("/_delete/*").Get(repo.DeleteFile).
|
||||
Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_upload/*").Get(repo.UploadFile).
|
||||
Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
|
||||
m.Post("/upload-file", repo.UploadFileToServer)
|
||||
m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
||||
}, func(ctx *context.Context) {
|
||||
if !setting.Repository.Upload.Enabled {
|
||||
ctx.Handle(404, "", nil)
|
||||
return
|
||||
}
|
||||
})
|
||||
}, reqRepoWriter, context.RepoRef(), func(ctx *context.Context) {
|
||||
if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
|
||||
ctx.Handle(404, "", nil)
|
||||
return
|
||||
}
|
||||
})
|
||||
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("", func() {
|
||||
@@ -489,7 +539,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 +554,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 +568,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]{7,40})$", repo.Diff)
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, middleware.RepoRef())
|
||||
}, context.RepoRef())
|
||||
m.Get("/commit/:sha([a-z0-9]{7,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)
|
||||
m.Get("/compare/:before([a-z0-9]{7,40})\\.\\.\\.:after([a-z0-9]{7,40})", repo.CompareDiff)
|
||||
}, 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 +593,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 {
|
||||
@@ -556,13 +611,19 @@ func runWeb(ctx *cli.Context) {
|
||||
|
||||
// Flag for port number in case first time run conflict.
|
||||
if ctx.IsSet("port") {
|
||||
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HttpPort, ctx.String("port"), 1)
|
||||
setting.HttpPort = ctx.String("port")
|
||||
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HTTPPort, ctx.String("port"), 1)
|
||||
setting.HTTPPort = ctx.String("port")
|
||||
}
|
||||
|
||||
var err error
|
||||
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
||||
var listenAddr string
|
||||
if setting.Protocol == setting.UNIX_SOCKET {
|
||||
listenAddr = fmt.Sprintf("%s", setting.HTTPAddr)
|
||||
} else {
|
||||
listenAddr = fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.HTTPPort)
|
||||
}
|
||||
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl)
|
||||
|
||||
var err error
|
||||
switch setting.Protocol {
|
||||
case setting.HTTP:
|
||||
err = http.ListenAndServe(listenAddr, m)
|
||||
@@ -571,6 +632,21 @@ func runWeb(ctx *cli.Context) {
|
||||
err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
|
||||
case setting.FCGI:
|
||||
err = fcgi.Serve(nil, m)
|
||||
case setting.UNIX_SOCKET:
|
||||
os.Remove(listenAddr)
|
||||
|
||||
var listener *net.UnixListener
|
||||
listener, err = net.ListenUnix("unix", &net.UnixAddr{listenAddr, "unix"})
|
||||
if err != nil {
|
||||
break // Handle error after switch
|
||||
}
|
||||
|
||||
// FIXME: add proper implementation of signal capture on all protocols
|
||||
// execute this on SIGTERM or SIGINT: listener.Close()
|
||||
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
|
||||
log.Fatal(4, "Failed to set permission of unix socket: %v", err)
|
||||
}
|
||||
err = http.Serve(listener, m)
|
||||
default:
|
||||
log.Fatal(4, "Invalid protocol: %s", setting.Protocol)
|
||||
}
|
||||
@@ -578,4 +654,6 @@ func runWeb(ctx *cli.Context) {
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to start server: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
104
conf/app.ini
104
conf/app.ini
@@ -12,13 +12,38 @@ 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
|
||||
MAX_CREATION_LIMIT = -1
|
||||
; Patch test queue length, make it as large as possible
|
||||
PULL_REQUEST_QUEUE_LENGTH = 10000
|
||||
; Mirror sync queue length, increase if mirror syncing starts hanging
|
||||
MIRROR_QUEUE_LENGTH = 1000
|
||||
; Patch test queue length, increase if pull request patch testing starts hanging
|
||||
PULL_REQUEST_QUEUE_LENGTH = 1000
|
||||
; Preferred Licenses to place at the top of the List
|
||||
; Name must match file name in conf/license or custom/conf/license
|
||||
PREFERRED_LICENSES = Apache License 2.0,MIT License
|
||||
|
||||
[repository.editor]
|
||||
; List of file extensions that should have line wraps in the CodeMirror editor
|
||||
; Separate extensions with a comma. To line wrap files w/o extension, just put a comma
|
||||
LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,
|
||||
; Valid file modes that have a preview API associated with them, such as api/v1/markdown
|
||||
; Separate values by commas. Preview tab in edit mode won't show if the file extension doesn't match
|
||||
PREVIEWABLE_FILE_MODES = markdown
|
||||
|
||||
[repository.upload]
|
||||
; Whether repository file uploads are enabled. Defaults to `true`
|
||||
ENABLED = true
|
||||
; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gogs restart)
|
||||
TEMP_PATH = data/tmp/uploads
|
||||
; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type
|
||||
ALLOWED_TYPES =
|
||||
; Max size of each file in MB. Defaults to 3MB
|
||||
FILE_MAX_SIZE = 3
|
||||
; Max number of files per upload. Defaults to 5
|
||||
MAX_FILES = 5
|
||||
|
||||
[ui]
|
||||
; Number of repositories that are showed in one explore page
|
||||
@@ -31,6 +56,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,23 +69,32 @@ 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
|
||||
; List of custom URL-Schemes that are allowed as links when rendering Markdown
|
||||
; for example git,magnet
|
||||
CUSTOM_URL_SCHEMES =
|
||||
; List of file extensions that should be rendered/edited as Markdown
|
||||
; Separate extensions with a comma. To render files w/o extension as markdown, just put a comma
|
||||
FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
|
||||
|
||||
[server]
|
||||
PROTOCOL = http
|
||||
DOMAIN = localhost
|
||||
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
|
||||
HTTP_ADDR =
|
||||
HTTP_ADDR = 0.0.0.0
|
||||
HTTP_PORT = 3000
|
||||
; Permission for unix socket
|
||||
UNIX_SOCKET_PERMISSION = 666
|
||||
; 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 +106,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 +129,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"
|
||||
@@ -148,7 +186,7 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = true
|
||||
|
||||
[webhook]
|
||||
; Hook task queue length
|
||||
; Hook task queue length, increase if webhook shooting starts hanging
|
||||
QUEUE_LENGTH = 1000
|
||||
; Deliver timeout in seconds
|
||||
DELIVER_TIMEOUT = 5
|
||||
@@ -165,24 +203,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 +235,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 +259,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 https://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 +353,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 +361,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 +369,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 +387,26 @@ MIGRATE = 600
|
||||
MIRROR = 300
|
||||
CLONE = 300
|
||||
PULL = 300
|
||||
GC = 60
|
||||
|
||||
[mirror]
|
||||
; Default interval in hours between each check
|
||||
DEFAULT_INTERVAL = 8
|
||||
|
||||
[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 +419,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
|
||||
|
||||
7
conf/label/Default
Normal file
7
conf/label/Default
Normal file
@@ -0,0 +1,7 @@
|
||||
#ee0701 bug
|
||||
#cccccc duplicate
|
||||
#84b6eb enhancement
|
||||
#128a0c help wanted
|
||||
#e6e6e6 invalid
|
||||
#cc317c question
|
||||
#ffffff wontfix
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
133
conf/locale/locale_bg-BG.ini
Executable file → Normal file
133
conf/locale/locale_bg-BG.ini
Executable file → Normal 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=Моля активирайте Вашия профил
|
||||
@@ -188,6 +189,13 @@ TeamName=Име на екипа
|
||||
AuthName=Име на удостоверението
|
||||
AdminEmail=Ел. поща на администратора
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` не може да бъде празен.`
|
||||
alpha_dash_error=` трябва да e валидна буква, число или тире(-_).`
|
||||
alpha_dash_dot_error=` трябва да e валидна буква, число, тире(-_) или точка.`
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=Потребителското име '%s' не е
|
||||
[settings]
|
||||
profile=Профил
|
||||
password=Парола
|
||||
avatar=Avatar
|
||||
ssh_keys=SSH ключове
|
||||
social=Социални профили
|
||||
applications=Приложения
|
||||
@@ -261,6 +269,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 +357,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,9 +365,12 @@ readme_helper=Изберете шаблон на readme
|
||||
auto_init=Инициализиране на това хранилище с избраните файлове и шаблон
|
||||
create_repo=Създай хранилище
|
||||
default_branch=Клон по подразбиране
|
||||
mirror_prune=Окастряне
|
||||
mirror_prune_desc=Премахва всички препратки за отдалечено проследяване, които не съществуват отдалечено
|
||||
mirror_interval=Интервал на отразяване (часове)
|
||||
mirror_address=Адрес на огледало
|
||||
mirror_address_desc=Моля включете потребител и парола в адреса ако са нужни.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Наблюдаващи
|
||||
stargazers=Харесващи
|
||||
forks=Разклонения
|
||||
@@ -412,6 +425,45 @@ file_raw=Директен файл
|
||||
file_history=История
|
||||
file_view_raw=Виж директен файл
|
||||
file_permalink=Постоянна връзка
|
||||
file_too_large=Този файл е твърде голям за да се визуализира
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Ревизии
|
||||
commits.search=Търсене в ревизии
|
||||
@@ -438,6 +490,11 @@ issues.create=Създай задача
|
||||
issues.new_label=Нов етикет
|
||||
issues.new_label_placeholder=Име на етикета...
|
||||
issues.create_label=Създай етикет
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d отворени
|
||||
issues.close_tab=%d затворени
|
||||
issues.filter_label=Етикет
|
||||
@@ -465,7 +522,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оментирай и затвори
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at=`посочи тази задача от ревизия <a
|
||||
issues.poster=Участник
|
||||
issues.collaborator=Сътрудник
|
||||
issues.owner=Притежател
|
||||
issues.sign_up_for_free=Регистрирай се безплатно
|
||||
issues.sign_in_require_desc=за да се включите в този разговор. Вече имате профил? <a href="%s">Влезте, за да коментирате</a>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Редакция
|
||||
issues.cancel=Отказ
|
||||
issues.save=Запис
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Изтрий етикет
|
||||
issues.label_deletion_desc=При изтриване на този етикет ще се премахне информацията за него във всички свързани задачи. Желаете ли да продължите?
|
||||
issues.label_deletion_success=Етикетът е изтрит успешно!
|
||||
issues.num_participants=%d участника
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Нова заявка за сливане
|
||||
pulls.compare_changes=Сравни промените
|
||||
@@ -566,20 +625,32 @@ 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=Основни настройки
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +673,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=Нов притежател
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=При <strong>всички</strong> събити
|
||||
settings.event_choose=Нека избера от какво имам нужда.
|
||||
settings.event_create=Създаване
|
||||
settings.event_create_desc=Създаване на клон или маркер
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Предаване
|
||||
settings.event_push_desc=Git предаване към хранилището
|
||||
settings.active=Активна
|
||||
@@ -688,6 +759,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 +791,7 @@ release.deletion=Изтрий версията
|
||||
release.deletion_desc=При изтриване на тази версия ще се премахне и съответния Git маркер. Желаете ли да продължите?
|
||||
release.deletion_success=Версията беше изтрита успешно!
|
||||
release.tag_name_already_exist=Версия с това име на маркер вече съществува.
|
||||
release.tag_name_invalid=Името на етикета е невалидно.
|
||||
release.downloads=Изтегляния
|
||||
|
||||
[org]
|
||||
@@ -885,6 +959,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 +990,7 @@ auths.enabled=Активно
|
||||
auths.updated=Последна модификация
|
||||
auths.auth_type=Тип на удостоверяване
|
||||
auths.auth_name=Име на удостоверяване
|
||||
auths.security_protocol=Протокол за защита
|
||||
auths.domain=Домейн
|
||||
auths.host=Сървър
|
||||
auths.port=Порт
|
||||
@@ -989,6 +1065,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 +1076,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 +1091,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 +1109,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=Режим на журнал
|
||||
|
||||
|
||||
1200
conf/locale/locale_cs-CZ.ini
Normal file
1200
conf/locale/locale_cs-CZ.ini
Normal file
File diff suppressed because it is too large
Load Diff
333
conf/locale/locale_de-DE.ini
Executable file → Normal file
333
conf/locale/locale_de-DE.ini
Executable file → Normal 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,17 +44,10 @@ 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
|
||||
docker_helper=Wenn Gogs innerhalb Docker läuft, lesen Sie sich bitte den <a target="_blank" href="%s">Leitfaden</a> genau durch, bevor Sie irgendwas auf dieser Seite ändern!
|
||||
docker_helper=Wenn Gogs innerhalb von Docker läuft, lesen Sie sich bitte den <a target="_blank" href="%s">Leitfaden</a> genau durch, bevor Sie irgendwas auf dieser Seite ändern!
|
||||
requite_db_desc=Gogs benötigt MySQL, PostgreSQL, SQLite3 oder TiDB.
|
||||
db_title=Datenbankeinstellungen
|
||||
db_type=Datenbanktyp
|
||||
@@ -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=Suche nach föderierten Profilbildern einschalten
|
||||
federated_avatar_lookup_popup=Der Suche nach föderierten Profilbildern die Verwendung von föderierten open source Services basierend auf libravatar erlauben.
|
||||
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,9 +186,16 @@ SSHTitle=SSH-Schlüsselname
|
||||
HttpsUrl=HTTPS URL
|
||||
PayloadUrl=Payload URL
|
||||
TeamName=Teamname
|
||||
AuthName=Authentifizierungsname
|
||||
AuthName=Name der Autorisierung
|
||||
AdminEmail=Administrator E-Mail
|
||||
|
||||
NewBranchName=Neuer Branch Name
|
||||
CommitSummary=Commit Zusammenfassung
|
||||
CommitMessage=Commit Nachricht
|
||||
CommitChoice=Commit Auswahl
|
||||
TreeName=Dateipfad
|
||||
Content=Inhalt
|
||||
|
||||
require_error=` darf nicht leer sein.`
|
||||
alpha_dash_error=` kann ausschließlich alphanumerische Zeichen und "-_" enthalten.`
|
||||
alpha_dash_dot_error=` kann ausschließlich alphanumerische Zeichen und ".-_" enthalten.`
|
||||
@@ -213,7 +221,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 +232,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 +248,7 @@ form.name_pattern_not_allowed=Benutzernamen der Form '%s' sind nicht erlaubt.
|
||||
[settings]
|
||||
profile=Profil
|
||||
password=Passwort
|
||||
avatar=Profilbild
|
||||
ssh_keys=SSH-Schlüssel
|
||||
social=Soziale Konten
|
||||
applications=Anwendungen
|
||||
@@ -250,23 +258,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=Suche nach Profilbildern via E-Mail
|
||||
federated_avatar_lookup=Suche nach föderierten Profilbildern
|
||||
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 +288,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 +303,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 +325,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 +333,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 +341,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 +357,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=Wählen Sie eine .gitignore Vorlage aus
|
||||
license=Lizenz
|
||||
license_helper=Wählen Sie eine Lizenz aus
|
||||
readme=Readme
|
||||
@@ -355,16 +365,19 @@ 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.
|
||||
mirror_last_synced=Zuletzt synchronisiert
|
||||
watchers=Beobachter
|
||||
stargazers=In Favoriten von
|
||||
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 +390,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 +407,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 +421,49 @@ 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
|
||||
|
||||
editor.new_file=Neue Datei
|
||||
editor.upload_file=Datei hochladen
|
||||
editor.edit_file=Datei bearbeiten
|
||||
editor.preview_changes=Vorschau der Änderungen
|
||||
editor.cannot_edit_non_text_files=Nicht-Text Dateien können nicht bearbeitet werden
|
||||
editor.edit_this_file=Diese Datei bearbeiten
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=Um die Datei zu bearbeiten müssen Sie das Repository forken
|
||||
editor.delete_this_file=Diese Datei löschen
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=Die Datei '%s' wurde erfolgreich gelöscht!
|
||||
editor.name_your_file=Dateinamen eingeben...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=oder
|
||||
editor.cancel_lower=abbrechen
|
||||
editor.commit_changes=Änderungen im Commit
|
||||
editor.add_tmpl=Hinzufügen von '%s/<filename>'
|
||||
editor.add='%s' hinzufügen
|
||||
editor.update='%s' ändern
|
||||
editor.delete='%s' löschen
|
||||
editor.commit_message_desc=Eine optionale, erweiterte Commit Beschreibung...
|
||||
editor.commit_directly_to_this_branch=Änderungen direkt dem Branch <strong class="branch-name">%s</strong> hinzufügen.
|
||||
editor.create_new_branch=Erstellen Sie einen <strong>neuen Branch</strong> für diesen Commit und starten Sie einen Pull Request.
|
||||
editor.new_branch_name_desc=Neuer Branch Name...
|
||||
editor.cancel=Abbrechen
|
||||
editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein.
|
||||
editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository.
|
||||
editor.directory_is_a_file='%s' im übergeordneten Verzeichnis ist eine Datei und kein Verzeichnis.
|
||||
editor.filename_is_a_directory=Die Datei '%s' existiert bereits als Verzeichnis in diesem Repository.
|
||||
editor.file_editing_no_longer_exists=Die Datei '%s' welche Sie bearbeiten existiert in diesem Repository nicht mehr.
|
||||
editor.file_changed_while_editing=Seit dem Start der Bearbeitung hat sich die Datei geändert. <a target="_blank" href="%s">Hier klicken</a> um die Änderungen zu sehen, oder nochmals <strong>Commit drücken</strong> um die Änderungen zu überschreiben.
|
||||
editor.file_already_exists=Eine Datei mit dem Namen '%s' existiert bereits in diesem Repository.
|
||||
editor.no_changes_to_show=Keine Änderungen vorhanden.
|
||||
editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v
|
||||
editor.add_subdir=Unterverzeichnis erstellen...
|
||||
editor.unable_to_upload_files=Fehler beim Hochladen der Dateien zu '%s'. Fehler: %v
|
||||
editor.upload_files_to_dir=Dateien hochladen nach '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Commits durchsuchen
|
||||
@@ -438,6 +490,11 @@ issues.create=Issue erstellen
|
||||
issues.new_label=Neues Label
|
||||
issues.new_label_placeholder=Label-Name...
|
||||
issues.create_label=Label erstellen
|
||||
issues.label_templates.title=Lade vordefinierte Label
|
||||
issues.label_templates.info=Es sind noch keine Label vorhanden. Sie können vordefinierte Label benutzen, oder auf "Neues Label" klicken um eines zu erstellen.
|
||||
issues.label_templates.helper=Wählen Sie ein Label
|
||||
issues.label_templates.use=Dieses Label Set benutzen
|
||||
issues.label_templates.fail_to_load_file=Fehler beim Laden der Label Template Datei '%s': %v
|
||||
issues.open_tab=%d offen
|
||||
issues.close_tab=%d geschlossen
|
||||
issues.filter_label=Label
|
||||
@@ -448,9 +505,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 +522,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,12 +532,11 @@ 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
|
||||
issues.sign_up_for_free=Kostenlos anmelden
|
||||
issues.sign_in_require_desc=um dieser Diskussion beizutreten. Haben Sie bereits ein Konto? <a href="%s">Anmelden um zu kommentieren</a>
|
||||
issues.sign_in_require_desc=<a href="%s">Anmelden</a> um an der Diskussion teilzunehmen.
|
||||
issues.edit=Bearbeiten
|
||||
issues.cancel=Abbrechen
|
||||
issues.save=Speichern
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Label löschen
|
||||
issues.label_deletion_desc=Das Label wird von allen verknüpften Issues entfernt. Möchten Sie fortfahren?
|
||||
issues.label_deletion_success=Label wurde erfolgreich gelöscht!
|
||||
issues.num_participants=%d Beteiligte
|
||||
issues.attachment.open_tab=`Klicken um "%s" in einem neuen Tab zu öffnen`
|
||||
issues.attachment.download=`Klicken um "%s" herunterzuladen`
|
||||
|
||||
pulls.new=Neuer Pull-Request
|
||||
pulls.compare_changes=Änderungen vergleichen
|
||||
@@ -510,14 +569,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 +587,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 +606,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 +617,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,20 +625,32 @@ 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
|
||||
settings.mirror_settings=Mirror Einstellungen
|
||||
settings.sync_mirror=Jetzt synchronisieren
|
||||
settings.mirror_sync_in_progress=Mirror Synchronisierung läuft, bitte die Seite in ca. einer Minute neu laden.
|
||||
settings.site=Offizielle Webseite
|
||||
settings.update_settings=Einstellungen speichern
|
||||
settings.change_reponame_prompt=Diese Änderung wirkt sich darauf aus, wie sich Links auf Repositories beziehen.
|
||||
settings.advanced_settings=Erweiterte Einstellungen
|
||||
settings.wiki_desc=Wiki aktivieren damit Benutzer Seiten anlegen können
|
||||
settings.wiki_desc=Wiki einschalten
|
||||
settings.use_internal_wiki=Eingebautes Wiki verwenden
|
||||
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=Issue-Tracker einschalten
|
||||
settings.use_internal_issue_tracker=Eingebauten Issue-Tracker verwenden
|
||||
settings.use_external_issue_tracker=Externes Issue-System verwenden
|
||||
settings.tracker_url_format=URL-Format des externen Issue-Systems
|
||||
settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers:
|
||||
settings.tracker_issue_style.numeric=Numerisch
|
||||
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 +661,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 +681,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 +690,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 +708,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Ich brauche <strong>alles</strong>.
|
||||
settings.event_choose=Lass mich auswählen, was ich brauche.
|
||||
settings.event_create=Erstellen
|
||||
settings.event_create_desc=Branch/Tag erstellt
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push auf ein Repository
|
||||
settings.active=Aktiv
|
||||
@@ -667,7 +738,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 +746,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 +756,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 +770,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 +791,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 +865,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 +880,7 @@ organizations=Organisationen
|
||||
repositories=Repositories
|
||||
authentication=Authentifizierung
|
||||
config=Konfiguration
|
||||
notices=System-Mitteilungen
|
||||
notices=Systemmitteilungen
|
||||
monitor=Monitoring
|
||||
first_page=Erste
|
||||
last_page=Letzte
|
||||
@@ -829,8 +903,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 +935,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 +946,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 +990,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 +999,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,18 +1019,18 @@ 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.app_name=Anwendungsname
|
||||
config.server_config=Serverkonfiguration
|
||||
config.app_name=Name der Anwendung
|
||||
config.app_ver=Anwendungsversion
|
||||
config.app_url=Anwendungs-URL
|
||||
config.domain=Domain
|
||||
@@ -970,14 +1046,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 +1063,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 +1076,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 +1091,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=Föderierte Profilbilder einschalten
|
||||
|
||||
config.git_config=Git Konfiguration
|
||||
config.git_disable_diff_highlight=Diff Syntaxhervorhebung ausschalten
|
||||
config.git_max_diff_lines=Max Diff Zeilen (in einer Datei)
|
||||
config.git_max_diff_line_characters=Max Diff Zeichen (in einer Zeile)
|
||||
config.git_max_diff_files=Max Diff Dateien (Anzeige)
|
||||
config.git_gc_args=GC-Argumente
|
||||
config.git_migrate_timeout=Zeitlimit für Migration
|
||||
config.git_mirror_timeout=Zeitlimit für Mirror-Aktualisierung
|
||||
config.git_clone_timeout=Zeitlimit für Clone
|
||||
config.git_pull_timeout=Zeitlimit für Pull
|
||||
config.git_gc_timeout=Zeitlimit für GC
|
||||
|
||||
config.log_config=Konfiguration des Loggings
|
||||
config.log_mode=Log-Modus
|
||||
|
||||
monitor.cron=Cron-Tasks
|
||||
@@ -1044,7 +1141,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 +1156,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 +1193,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
|
||||
|
||||
@@ -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
|
||||
@@ -188,6 +189,13 @@ TeamName = Team name
|
||||
AuthName = Authorization name
|
||||
AdminEmail = Admin email
|
||||
|
||||
NewBranchName = New branch name
|
||||
CommitSummary = Commit summary
|
||||
CommitMessage = Commit message
|
||||
CommitChoice = Commit choice
|
||||
TreeName = File path
|
||||
Content = Content
|
||||
|
||||
require_error = ` cannot be empty.`
|
||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
||||
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.`
|
||||
@@ -224,8 +232,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 +248,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 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced = Last Synced
|
||||
watchers = Watchers
|
||||
stargazers = Stargazers
|
||||
forks = Forks
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file = New file
|
||||
editor.upload_file = Upload file
|
||||
editor.edit_file = Edit file
|
||||
editor.preview_changes = Preview Changes
|
||||
editor.cannot_edit_non_text_files = Cannot edit non-text files
|
||||
editor.edit_this_file = Edit this file
|
||||
editor.must_be_on_a_branch = You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit = You must fork this repository before editing the file
|
||||
editor.delete_this_file = Delete this file
|
||||
editor.must_have_write_access = You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success = File '%s' has been deleted successfully!
|
||||
editor.name_your_file = Name your file...
|
||||
editor.filename_help = To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or = or
|
||||
editor.cancel_lower = cancel
|
||||
editor.commit_changes = Commit Changes
|
||||
editor.add_tmpl = Add '%s/<filename>'
|
||||
editor.add = Add '%s'
|
||||
editor.update = Update '%s'
|
||||
editor.delete = Delete '%s'
|
||||
editor.commit_message_desc = Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc = New branch name...
|
||||
editor.cancel = Cancel
|
||||
editor.filename_cannot_be_empty = Filename cannot be empty.
|
||||
editor.branch_already_exists = Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file = Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory = The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists = The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing = File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists = A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show = There are no changes to show.
|
||||
editor.fail_to_update_file = Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir = Add subdirectory...
|
||||
editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir = Upload files to '%s'
|
||||
|
||||
commits.commits = Commits
|
||||
commits.search = Search commits
|
||||
@@ -438,6 +490,11 @@ issues.create = Create Issue
|
||||
issues.new_label = New Label
|
||||
issues.new_label_placeholder = Label name...
|
||||
issues.create_label = Create Label
|
||||
issues.label_templates.title = Load a predefined set of labels
|
||||
issues.label_templates.info = There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper = Select a label set
|
||||
issues.label_templates.use = Use this label set
|
||||
issues.label_templates.fail_to_load_file = Failed to load label template file '%s': %v
|
||||
issues.open_tab = %d Open
|
||||
issues.close_tab = %d Closed
|
||||
issues.filter_label = Label
|
||||
@@ -465,7 +522,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
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at = `referenced this issue from a commit <a id="%[1]s" href="
|
||||
issues.poster = Poster
|
||||
issues.collaborator = Collaborator
|
||||
issues.owner = Owner
|
||||
issues.sign_up_for_free = 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>
|
||||
issues.sign_in_require_desc = <a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit = Edit
|
||||
issues.cancel = Cancel
|
||||
issues.save = Save
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion = Label Deletion
|
||||
issues.label_deletion_desc = Deleting this label will remove its information in all related issues. Do you want to continue?
|
||||
issues.label_deletion_success = Label has been deleted successfully!
|
||||
issues.num_participants = %d Participants
|
||||
issues.attachment.open_tab = `Click to see "%s" in a new tab`
|
||||
issues.attachment.download = `Click to download "%s"`
|
||||
|
||||
pulls.new = New Pull Request
|
||||
pulls.compare_changes = Compare Changes
|
||||
@@ -566,20 +625,32 @@ 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
|
||||
settings.mirror_settings = Mirror Settings
|
||||
settings.sync_mirror = Sync Now
|
||||
settings.mirror_sync_in_progress = Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +673,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything = I need <strong>everything</strong>.
|
||||
settings.event_choose = Let me choose what I need.
|
||||
settings.event_create = Create
|
||||
settings.event_create_desc = Branch, or tag created
|
||||
settings.event_pull_request = Pull Request
|
||||
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push = Push
|
||||
settings.event_push_desc = Git push to a repository
|
||||
settings.active = Active
|
||||
@@ -688,6 +759,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 +791,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 +959,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 +990,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 +1019,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
|
||||
@@ -952,6 +1028,7 @@ 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.
|
||||
auths.deletion_success = Authentication has been deleted successfully!
|
||||
auths.login_source_exist = Login source '%s' already exists.
|
||||
|
||||
config.server_config = Server Configuration
|
||||
config.app_name = Application Name
|
||||
@@ -989,6 +1066,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 +1077,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 +1092,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 +1110,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
|
||||
|
||||
|
||||
159
conf/locale/locale_es-ES.ini
Executable file → Normal file
159
conf/locale/locale_es-ES.ini
Executable file → Normal 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=Habilitar búsqueda de Avatares Federados
|
||||
federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Nombre del equipo
|
||||
AuthName=Nombre de autorización
|
||||
AdminEmail=Correo electrónico del administrador
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` no puede estar vacío.`
|
||||
alpha_dash_error=` los caracteres deben ser Alfanumericos o dash(-_).`
|
||||
alpha_dash_dot_error=` debe ser un caracter alfanumérivo válido, un guión alto o bajo (-_) o un signo de puntuación.`
|
||||
@@ -224,9 +232,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 +248,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 +269,8 @@ change_username_prompt=Este cambio afectará a los enlaces que hacen referencia
|
||||
continue=Continuar
|
||||
cancel=Cancelar
|
||||
|
||||
lookup_avatar_by_mail=Buscar avatar por correo
|
||||
federated_avatar_lookup=Búsqueda de Avatar Federado
|
||||
enable_custom_avatar=Activar avatar personalizado
|
||||
choose_new_avatar=Selecciona nuevo avatar
|
||||
update_avatar=Actualizar configuración del avatar
|
||||
@@ -346,8 +356,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=Seleccionar plantillas de .gitignore
|
||||
license=Licencia
|
||||
license_helper=Selecciona un fichero de licencia
|
||||
readme=Readme
|
||||
@@ -355,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Seguidores
|
||||
stargazers=Fans
|
||||
forks=Forks
|
||||
@@ -378,18 +391,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 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Buscar Commits
|
||||
@@ -438,6 +490,11 @@ issues.create=Crear incidencia
|
||||
issues.new_label=Nueva Etiqueta
|
||||
issues.new_label_placeholder=Nombre etiqueta...
|
||||
issues.create_label=Crear etiqueta
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d abiertas
|
||||
issues.close_tab=%d cerradas
|
||||
issues.filter_label=Etiqueta
|
||||
@@ -465,7 +522,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
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at=`mencionada esta incidencia en un commit <a id="%[1]s" href
|
||||
issues.poster=Autor
|
||||
issues.collaborator=Colaborador
|
||||
issues.owner=Propietario
|
||||
issues.sign_up_for_free=Registro gratuito
|
||||
issues.sign_in_require_desc=para unirse a esta conversación. ¿Ya dispone de una cuenta? <a href="%s">Inicie sesión para comentar</a>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Editar
|
||||
issues.cancel=Cancelar
|
||||
issues.save=Guardar
|
||||
@@ -494,9 +551,11 @@ issues.label_deletion=Borrado de Etiqueta
|
||||
issues.label_deletion_desc=Al borrar la etiqueta su información será eliminada de todas las incidencias relacionadas. Desea continuar?
|
||||
issues.label_deletion_success=Etiqueta borrada con éxito!
|
||||
issues.num_participants=%d participantes
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
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,20 +625,32 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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=Activar sistema de wiki
|
||||
settings.use_internal_wiki=Usar wiki integrada
|
||||
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=Habilitar rastreo de incidencias
|
||||
settings.use_internal_issue_tracker=Usar rastreo de incidencias ligero incluido
|
||||
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 +673,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Necesito <strong>todo</strong>.
|
||||
settings.event_choose=Déjeme elegir lo que necesito.
|
||||
settings.event_create=Crear
|
||||
settings.event_create_desc=Rama o etiqueta creada
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push a un repositorio
|
||||
settings.active=Activo
|
||||
@@ -682,12 +753,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 +778,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 +791,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 +959,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 +990,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 +1065,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 +1076,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 +1091,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 +1109,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=Habilitar Avatares Federados
|
||||
|
||||
config.git_config=Configuración de Git
|
||||
config.git_disable_diff_highlight=Desactivar resaltado de sintaxis del Diff
|
||||
config.git_max_diff_lines=Líneas de Diff máximas (por un solo archivo)
|
||||
config.git_max_diff_line_characters=Carácteres de Diff máximos (para una sola línea)
|
||||
config.git_max_diff_files=Máximo de archivos de Diff (que se mostrarán)
|
||||
config.git_gc_args=Argumentos de GC
|
||||
config.git_migrate_timeout=Tiempo de espera de migración
|
||||
config.git_mirror_timeout=Tiempo de espera de actualización de espejos
|
||||
config.git_clone_timeout=Tiempo de espera de operación de clones
|
||||
config.git_pull_timeout=Tiempo de espera de operación de pull
|
||||
config.git_gc_timeout=Tiempo de espera de operación de GC
|
||||
|
||||
config.log_config=Configuración del Log
|
||||
config.log_mode=Modo del Log
|
||||
|
||||
|
||||
133
conf/locale/locale_fi-FI.ini
Executable file → Normal file
133
conf/locale/locale_fi-FI.ini
Executable file → Normal 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Tiimin nimi
|
||||
AuthName=Luvan nimi
|
||||
AdminEmail=Ylläpito sähköposti
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` ei voi olla tyhjä.`
|
||||
alpha_dash_error=` täytyy olla kirjaimia tai numeroita tai väliviiva(-_) merkkejä.`
|
||||
alpha_dash_dot_error=` täytyy olla kirjaimia tai numeroita tai väliviiva(-_) tai piste merkkejä.`
|
||||
@@ -224,8 +232,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 +248,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 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Tarkkailijat
|
||||
stargazers=Tähtiharrastajat
|
||||
forks=Haarat
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commitit
|
||||
commits.search=Etsi commiteista
|
||||
@@ -438,6 +490,11 @@ issues.create=Ilmoita ongelma
|
||||
issues.new_label=Uusi tunniste
|
||||
issues.new_label_placeholder=Tunnisteen nimi...
|
||||
issues.create_label=Luo tunniste
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d avoinna
|
||||
issues.close_tab=%d suljettu
|
||||
issues.filter_label=Tunniste
|
||||
@@ -465,7 +522,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
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at=`viittasi tähän ongelmaan commitissa <a id="%[1]s" href="
|
||||
issues.poster=Tekijä
|
||||
issues.collaborator=Yhteistyökumppani
|
||||
issues.owner=Omistaja
|
||||
issues.sign_up_for_free=Rekisteröidy ilmaiseksi
|
||||
issues.sign_in_require_desc=liittyäksesi tähän keskusteluu. Onko sinulla jo tili? <a href="%s">Kirjaudu sisään kommentoidaksesi</a>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Muokkaa
|
||||
issues.cancel=Peruuta
|
||||
issues.save=Tallenna
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Tunnisteen poistaminen
|
||||
issues.label_deletion_desc=Tämän tunnisteen poistaminen poistaa sen tiedot kaikista siihen liittyvistä ongelmista. Haluatko jatkaa?
|
||||
issues.label_deletion_success=Tunniste on poistettu onnistuneesti!
|
||||
issues.num_participants=%d osallistujaa
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Uusi pull pyyntö
|
||||
pulls.compare_changes=Vertaa muutoksia
|
||||
@@ -566,20 +625,32 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +673,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Tarvitsen <strong>kaiken</strong>.
|
||||
settings.event_choose=Haluan valita, mitä tarvitsen.
|
||||
settings.event_create=Luo
|
||||
settings.event_create_desc=Branch, tai tagi luotu
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push repoon
|
||||
settings.active=Aktiivinen
|
||||
@@ -688,6 +759,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 +791,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 +959,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 +990,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 +1065,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 +1076,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 +1091,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 +1109,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
|
||||
|
||||
|
||||
265
conf/locale/locale_fr-FR.ini
Executable file → Normal file
265
conf/locale/locale_fr-FR.ini
Executable file → Normal 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=Activer les recherches d'avatars unifiés
|
||||
federated_avatar_lookup_popup=Activer la recherche unifiée d'avatars en utilisant le service open source unifié basé sur 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 l’administrateur 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Nom d'équipe
|
||||
AuthName=Nom d'autorisation
|
||||
AdminEmail=E-mail de l'administrateur
|
||||
|
||||
NewBranchName=Nouveau nom de la branche
|
||||
CommitSummary=Résumé du commit
|
||||
CommitMessage=Message de commit
|
||||
CommitChoice=Choix de commit
|
||||
TreeName=Chemin du fichier
|
||||
Content=Contenu
|
||||
|
||||
require_error=` Ne peut être vide `
|
||||
alpha_dash_error=` doivent être des caractères alpha, numeriques ou console (-_) valides `
|
||||
alpha_dash_dot_error=` doivent être des caractères alpha, numeriques, console (-_) valides ou des points `
|
||||
@@ -217,15 +225,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 +248,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 +269,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=Recherche d'avatar par email
|
||||
federated_avatar_lookup=Recherche d'avatars unifiés
|
||||
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 mé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 mé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 +345,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 +357,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=Choisissez un modèle de fichier .gitignore
|
||||
license=Licence
|
||||
license_helper=Sélectionner un fichier de licence
|
||||
readme=Fichier Readme
|
||||
@@ -355,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Dernière synchronisation
|
||||
watchers=Observateurs
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
@@ -377,7 +390,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 +418,52 @@ 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
|
||||
|
||||
editor.new_file=Nouveau fichier
|
||||
editor.upload_file=Téléverser un fichier
|
||||
editor.edit_file=Modifier fichier
|
||||
editor.preview_changes=Aperçu des modifications
|
||||
editor.cannot_edit_non_text_files=Impossible de modifier les fichiers non-texte
|
||||
editor.edit_this_file=Modifier ce fichier
|
||||
editor.must_be_on_a_branch=Vous devez être sur une branche pour appliquer ou proposer des modifications à ce fichier
|
||||
editor.fork_before_edit=Vous devez fourcher ce dépôt avant de modifier le fichier
|
||||
editor.delete_this_file=Supprimer ce fichier
|
||||
editor.must_have_write_access=Vous devez avoir un accès en écriture pour appliquer ou proposer des modifications à ce fichier
|
||||
editor.file_delete_success=Fichier '%s' a été supprimé avec succès!
|
||||
editor.name_your_file=Nommez votre fichier...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=ou
|
||||
editor.cancel_lower=annuler
|
||||
editor.commit_changes=Commit les modifications
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Mettre à jour '%s'
|
||||
editor.delete=Supprimer '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=Nouveau nom de la branche...
|
||||
editor.cancel=Annuler
|
||||
editor.filename_cannot_be_empty=Nom de fichier ne peut pas être vide.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=Il n’y a aucun changement à afficher.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Rechercher des commits
|
||||
@@ -426,23 +478,28 @@ issues.new=Nouveau ticket
|
||||
issues.new.labels=Etiquettes
|
||||
issues.new.no_label=Pas d'étiquette
|
||||
issues.new.clear_labels=Effacer les étiquettes
|
||||
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.milestone=Jalon
|
||||
issues.new.no_milestone=Aucun jalon
|
||||
issues.new.clear_milestone=Effacer le jalon
|
||||
issues.new.open_milestone=Ouvrir un jalon
|
||||
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
|
||||
issues.create=Créer un rapport de problème
|
||||
issues.create=Créer un ticket
|
||||
issues.new_label=Nouvelle étiquette
|
||||
issues.new_label_placeholder=Nom de l'étiquette...
|
||||
issues.create_label=Créer une étiquette
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
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 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Modifier
|
||||
issues.cancel=Annuler
|
||||
issues.save=Enregistrer
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Suppression du Label
|
||||
issues.label_deletion_desc=Cette opération supprimera également toutes les informations relatives aux tickets. Voulez-vous continuer ?
|
||||
issues.label_deletion_success=Label supprimé avec succès !
|
||||
issues.num_participants=%d Participants
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Nouvelle Pull Request
|
||||
pulls.compare_changes=Comparer les changements
|
||||
@@ -557,8 +616,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,20 +625,32 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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=Activer le wiki
|
||||
settings.use_internal_wiki=Utiliser le wiki interne
|
||||
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=Activer le système de tickets
|
||||
settings.use_internal_issue_tracker=Utiliser le système simplifié de tickets interne
|
||||
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 +662,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 l’effacement.
|
||||
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 +682,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.
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=J'ai besoin de <strong>tout</strong>.
|
||||
settings.event_choose=Permettez-moi de choisir ce dont j'ai besoin.
|
||||
settings.event_create=Créer
|
||||
settings.event_create_desc=Branche, ou Tag créé
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push vers un dépôt
|
||||
settings.active=Actif
|
||||
@@ -688,6 +759,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 +786,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 +805,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 +910,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 +959,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 +990,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 +1026,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 +1051,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 +1065,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 +1076,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 +1091,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 +1109,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=Activer les avatars unifiés
|
||||
|
||||
config.git_config=Configuration de Git
|
||||
config.git_disable_diff_highlight=Désactiver la surbrillance syntaxique de Diff
|
||||
config.git_max_diff_lines=Lignes de Diff Max (pour un seul fichier)
|
||||
config.git_max_diff_line_characters=Nombre max de caractères de Diff (pour une seule ligne)
|
||||
config.git_max_diff_files=Nombre max de fichiers de Diff (à afficher)
|
||||
config.git_gc_args=Arguments de GC
|
||||
config.git_migrate_timeout=Délai imparti pour une migration
|
||||
config.git_mirror_timeout=Délai imparti pour mettre à jour le miroir
|
||||
config.git_clone_timeout=Délai imparti pour l'opération "Clone"
|
||||
config.git_pull_timeout=Délai imparti pour l'opération "Pull"
|
||||
config.git_gc_timeout=Délai imparti pour l'opération "GC"
|
||||
|
||||
config.log_config=Configuration du Journal
|
||||
config.log_mode=Mode du journal
|
||||
|
||||
@@ -1060,14 +1157,14 @@ notices.delete_success=Notifications système supprimées avec succès.
|
||||
|
||||
[action]
|
||||
create_repo=a créé le dépôt <a href="%s">%s</a>
|
||||
rename_repo=rebaptisé le dépôt de <code>%[1]s</code> à <a href="%[2]s">%[3]s</a>
|
||||
rename_repo=a rebaptisé le dépôt de <code>%[1]s</code> vers <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=a soumis à <a href="%[1]s/src/%[2]s">%[3]s</a> sur <a href="%[1]s">%[4]s</a>
|
||||
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>
|
||||
@@ -1075,23 +1172,23 @@ push_tag=a soumis le tag <a href="%s/src/%s">%[2]s</a> sur <a href="%[1]s">%[3]s
|
||||
compare_commits=Comparer ces %d commits
|
||||
|
||||
[tool]
|
||||
ago=auparavant
|
||||
from_now=à partir de maintenant
|
||||
ago=il y a
|
||||
from_now=dans
|
||||
now=maintenant
|
||||
1s=1 seconde %s
|
||||
1m=1 minute %s
|
||||
1h=1 heure %s
|
||||
1d=1 jour %s
|
||||
1w=1 semaine %s
|
||||
1mon=1 mois %s
|
||||
1y=1 an %s
|
||||
seconds=%d secondes %s
|
||||
minutes=%d minutes %s
|
||||
hours=%d heures %s
|
||||
days=%d jours %s
|
||||
weeks=%d semaines %s
|
||||
months=%d mois %s
|
||||
years=%d ans %s
|
||||
1s=%s 1 seconde
|
||||
1m=%s 1 minute
|
||||
1h=%s 1 heure
|
||||
1d=%s 1 jour
|
||||
1w=%s 1 semaine
|
||||
1mon=%s 1 mois
|
||||
1y=%s 1 an
|
||||
seconds=%[2]s %[1]d secondes
|
||||
minutes=%[2]s %[1]d minutes
|
||||
hours=%[2]s %[1]d heures
|
||||
days=%[2]s %[1]d jours
|
||||
weeks=%[2]s %[1]d semaines
|
||||
months=%[2]s %[1]d mois
|
||||
years=%[2]s %[1]d ans
|
||||
raw_seconds=secondes
|
||||
raw_minutes=minutes
|
||||
|
||||
|
||||
351
conf/locale/locale_it-IT.ini
Executable file → Normal file
351
conf/locale/locale_it-IT.ini
Executable file → Normal 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Nome Team
|
||||
AuthName=Nome autorizzazione
|
||||
AdminEmail=Email dell'Admin
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` non può essere vuoto.`
|
||||
alpha_dash_error=` ammessi solo caratteri alfanumerici o trattini(-_).`
|
||||
alpha_dash_dot_error=` ammessi solo caratteri alfanumerici o trattini(-_) o punti.`
|
||||
@@ -224,8 +232,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 +248,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 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Osservatori
|
||||
stargazers=Fan
|
||||
forks=Fork
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Ricerca una versione
|
||||
@@ -438,6 +490,11 @@ issues.create=Crea Problema
|
||||
issues.new_label=Nuova etichetta
|
||||
issues.new_label_placeholder=Nome dell'etichetta...
|
||||
issues.create_label=Crea Etichetta
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d Aperti
|
||||
issues.close_tab=%d Chiusi
|
||||
issues.filter_label=Etichetta
|
||||
@@ -465,23 +522,23 @@ 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=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Modifica
|
||||
issues.cancel=Cancel
|
||||
issues.cancel=Annulla
|
||||
issues.save=Salva
|
||||
issues.label_title=Nome etichetta
|
||||
issues.label_color=Colore etichetta
|
||||
@@ -494,46 +551,48 @@ issues.label_deletion=Elimina Etichetta
|
||||
issues.label_deletion_desc=Eliminare l'etichetta rimuovera le sue informazioni in tutti i problemi correlati. Vuoi continuare?
|
||||
issues.label_deletion_success=Etichetta eliminata con successo!
|
||||
issues.num_participants=%d Partecipanti
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Nuova Pull Request
|
||||
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 +616,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,45 +625,55 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +682,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 +693,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 +711,19 @@ 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_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
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 +737,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 +775,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 +823,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 +838,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 +868,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 +956,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 +983,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 +1018,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 +1045,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 +1065,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 +1089,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 +1109,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 +1142,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 +1169,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 +1193,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
|
||||
|
||||
|
||||
245
conf/locale/locale_ja-JP.ini
Executable file → Normal file
245
conf/locale/locale_ja-JP.ini
Executable file → Normal 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=はい
|
||||
@@ -188,6 +189,13 @@ TeamName=チーム名
|
||||
AuthName=承認名
|
||||
AdminEmail=管理者の電子メール
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=空にできません
|
||||
alpha_dash_error=アルファベット、数字、ハイフン"-"、アンダースコア"_"のいずれかの必要があります
|
||||
alpha_dash_dot_error=' アルファベット、数値、ダッシュ(-)、アンダースコア(_) 、ドット(.)のいずれかを入力する必要があります。 '
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=ユーザ名のパターン '%s' は許可され
|
||||
[settings]
|
||||
profile=プロフィール
|
||||
password=パスワード
|
||||
avatar=Avatar
|
||||
ssh_keys=SSH キー
|
||||
social=SNSアカウント
|
||||
applications=アプリケーション
|
||||
@@ -261,10 +269,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 +325,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 +338,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 +346,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,16 +365,19 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=ウォッチャー
|
||||
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 +389,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 +421,49 @@ labels=ラベル
|
||||
milestones=マイルストーン
|
||||
commits=コミット
|
||||
releases=リリース
|
||||
file_raw=生データ
|
||||
file_raw=Raw
|
||||
file_history=履歴
|
||||
file_view_raw=生データを見る
|
||||
file_view_raw=Rawデータを見る
|
||||
file_permalink=パーマリンク
|
||||
file_too_large=このファイルは大きすぎるため、表示できません。
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=コミット
|
||||
commits.search=コミットの検索
|
||||
@@ -438,6 +490,11 @@ issues.create=問題を作成
|
||||
issues.new_label=新しいラベル
|
||||
issues.new_label_placeholder=ラベル名...
|
||||
issues.create_label=ラベルを作成
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d オープン
|
||||
issues.close_tab=%d クローズ
|
||||
issues.filter_label=ラベル
|
||||
@@ -448,8 +505,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 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=編集
|
||||
issues.cancel=キャンセル
|
||||
issues.save=保存
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=ラベルの削除
|
||||
issues.label_deletion_desc=ラベルを削除すると、関連するすべての問題の情報が削除されます。続行しますか。
|
||||
issues.label_deletion_success=ラベルは正常に削除されました。
|
||||
issues.num_participants=%d Participants
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=新しいプルリクエスト
|
||||
pulls.compare_changes=変更を比較
|
||||
@@ -503,7 +562,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,20 +625,32 @@ 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=基本設定
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +673,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=<strong>すべて</strong> が必要です。
|
||||
settings.event_choose=必要なものを選択しましょう。
|
||||
settings.event_create=Create
|
||||
settings.event_create_desc=ブランチ、またはタグを作成
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=プッシュ
|
||||
settings.event_push_desc=Git リポジトリにプッシュ
|
||||
settings.active=アクティブ
|
||||
@@ -688,6 +759,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 +791,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 +799,7 @@ org_name_holder=組織名
|
||||
org_full_name_holder=組織のフルネーム
|
||||
org_name_helper=偉大な組織の名は短く覚えやすいです。
|
||||
create_org=組織を作成
|
||||
repo_updated=更新した
|
||||
repo_updated=最終更新
|
||||
people=人々
|
||||
invite_someone=誰かを招待
|
||||
teams=チーム
|
||||
@@ -753,8 +827,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 +959,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 +987,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 +1065,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 +1076,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 +1091,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 +1156,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 +1183,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
|
||||
|
||||
161
conf/locale/locale_lv-LV.ini
Executable file → Normal file
161
conf/locale/locale_lv-LV.ini
Executable file → Normal 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Komandas nosaukums
|
||||
AuthName=Autorizācijas nosaukums
|
||||
AdminEmail=Admin e-pasta adrese
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` nedrīkst būt tukšs.`
|
||||
alpha_dash_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus vai domuzīmes (-_).`
|
||||
alpha_dash_dot_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus, domuzīmes (-_) vai punktu.`
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
|
||||
[settings]
|
||||
profile=Profils
|
||||
password=Parole
|
||||
avatar=Profila attēls
|
||||
ssh_keys=SSH atslēgas
|
||||
social=Sociālie konti
|
||||
applications=Lietotnes
|
||||
@@ -261,10 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Novērotāji
|
||||
stargazers=Zvaigžņdevēji
|
||||
forks=Atdalītie repozitoriji
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Revīzijas
|
||||
commits.search=Meklēt revīzijas
|
||||
@@ -438,6 +490,11 @@ issues.create=Pieteikt problēmu
|
||||
issues.new_label=Jauna etiķete
|
||||
issues.new_label_placeholder=Etiķetes nosaukums...
|
||||
issues.create_label=Izveidot etiķeti
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d atvērti
|
||||
issues.close_tab=%d aizvērti
|
||||
issues.filter_label=Etiķete
|
||||
@@ -465,7 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Labot
|
||||
issues.cancel=Atcelt
|
||||
issues.save=Saglabāt
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Etiķetes dzēšana
|
||||
issues.label_deletion_desc=Dzēšot šo etiķeti, tā tiks noņemta no visām saistītajām problēmām. Vai vēlaties turpināt?
|
||||
issues.label_deletion_success=Etiķete tika veiksmīgi izdzēsta!
|
||||
issues.num_participants=%d dalībnieki
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Jauns izmaiņu pieprasījums
|
||||
pulls.compare_changes=Salīdzināt izmaiņas
|
||||
@@ -557,8 +616,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,20 +625,32 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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=Iespējot vikivietnes
|
||||
settings.use_internal_wiki=Izmantot iebūvēto vikivietni
|
||||
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 +665,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 +682,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.
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Vēlos saņemt <strong>visu</strong>.
|
||||
settings.event_choose=Atzīmēt, ko vēlos saņemt.
|
||||
settings.event_create=Izveidot
|
||||
settings.event_create_desc=Atzara vai taga izveidošana
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Izmaiņu nosūtīšana
|
||||
settings.event_push_desc=Git izmaiņu nosūtīšana uz repozitoriju
|
||||
settings.active=Aktīvs
|
||||
@@ -688,6 +759,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 +791,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 +959,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 +990,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 +1026,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 +1065,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 +1076,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 +1091,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 +1109,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 konfigurācija
|
||||
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 argumenti
|
||||
config.git_migrate_timeout=Migrācijas noilgums
|
||||
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 darbības noilgums
|
||||
|
||||
config.log_config=Žurnalizēšanas konfigurācija
|
||||
config.log_mode=Žurnalizēšanas veids
|
||||
|
||||
@@ -1066,8 +1163,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>
|
||||
|
||||
249
conf/locale/locale_nl-NL.ini
Executable file → Normal file
249
conf/locale/locale_nl-NL.ini
Executable file → Normal 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Team naam
|
||||
AuthName=Autorisatienaam
|
||||
AdminEmail=E-mail beheerder
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=kan niet leeg zijn.
|
||||
alpha_dash_error=moet een valide alfanumeriek of dash(-_) karakter zijn.
|
||||
alpha_dash_dot_error=moet een valide alfanumeriek, dash(-_) of (.) punt karakter zijn.
|
||||
@@ -224,8 +232,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 +248,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 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Volgers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Zoeken
|
||||
@@ -438,6 +490,11 @@ issues.create=Maak probleem
|
||||
issues.new_label=Nieuw Label
|
||||
issues.new_label_placeholder=Tekst label...
|
||||
issues.create_label=Maak label
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d Open
|
||||
issues.close_tab=%d gesloten
|
||||
issues.filter_label=Label
|
||||
@@ -465,7 +522,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,12 +532,11 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Bewerken
|
||||
issues.cancel=Annuleren
|
||||
issues.save=Opslaan
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Verwijder label
|
||||
issues.label_deletion_desc=Het verwijderen van dit label zal alle informatie in de gerelateerde problemen verwijderen. Wilt u doorgaan?
|
||||
issues.label_deletion_success=Label werd met succes verwijderd!
|
||||
issues.num_participants=%d deelnemers
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Nieuwe Pull aanvraag
|
||||
pulls.compare_changes=Vergelijk veranderingen
|
||||
@@ -506,7 +565,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 +576,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 +616,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=Pagina’s
|
||||
wiki.last_updated=Laatst bijgewerkt: %s
|
||||
@@ -566,45 +625,55 @@ 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.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +682,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
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Ik moet <strong>alles</strong> hebben.
|
||||
settings.event_choose=Laat me kiezen wat ik nodig heb.
|
||||
settings.event_create=Creëer
|
||||
settings.event_create_desc=Branch, of tag aangemaakt
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push naar een repository
|
||||
settings.active=Actief
|
||||
@@ -667,7 +738,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 +754,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 +770,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 +788,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 +823,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 +833,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 +843,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 +899,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 +953,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 +982,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 +990,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 +1012,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 +1065,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 +1076,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 +1091,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 +1109,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 +1142,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
|
||||
|
||||
215
conf/locale/locale_pl-PL.ini
Executable file → Normal file
215
conf/locale/locale_pl-PL.ini
Executable file → Normal 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Nazwa zespołu
|
||||
AuthName=Nazwa autoryzacji
|
||||
AdminEmail=E-mail administratora
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` nie może być puste.`
|
||||
alpha_dash_error=` musi się składać z prawidłowych znaków alfanumerycznych, myślników oraz podkreśleń.`
|
||||
alpha_dash_dot_error=` musi się składać z prawidłowych znaków alfanumerycznych, myślników, podkreśleń oraz kropek.`
|
||||
@@ -224,8 +232,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 +248,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 +269,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 +357,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,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Obserwujący
|
||||
stargazers=Polubienia
|
||||
forks=Forki
|
||||
@@ -412,6 +425,45 @@ 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ć
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commity
|
||||
commits.search=Przeszukaj commity
|
||||
@@ -438,6 +490,11 @@ issues.create=Utwórz problem
|
||||
issues.new_label=Nowa etykieta
|
||||
issues.new_label_placeholder=Etykieta...
|
||||
issues.create_label=Utwórz etykietę
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=Otwarte %d
|
||||
issues.close_tab=Zamknięte %d
|
||||
issues.filter_label=Etykieta
|
||||
@@ -465,7 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Edytuj
|
||||
issues.cancel=Anuluj
|
||||
issues.save=Zapisz
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Usunięcie etykiety
|
||||
issues.label_deletion_desc=Usunięcie tej etykiety spowoduje usuniecie jej ze wszystkich powiązanych problemów. Czy na pewno chcesz kontynuować?
|
||||
issues.label_deletion_success=Etykieta została usunięta pomyślnie!
|
||||
issues.num_participants=%d uczestników
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Nowy pull request
|
||||
pulls.compare_changes=Porównaj zmiany
|
||||
@@ -557,8 +616,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,45 +625,55 @@ 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
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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ź konwersję
|
||||
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 +682,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>.
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Potrzebuję <strong>wszystkiego</strong>.
|
||||
settings.event_choose=Pozwól mi wybrać, czego potrzebuję.
|
||||
settings.event_create=Utwórz
|
||||
settings.event_create_desc=Utworzono gałąź lub tag
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Wypchnięcie
|
||||
settings.event_push_desc=Wypchnięcie (push) do repozytorium Git
|
||||
settings.active=Aktywny
|
||||
@@ -688,6 +759,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 +781,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 +791,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 +959,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 +990,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 +1004,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 +1026,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 +1044,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 +1065,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 +1076,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 +1109,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 +1160,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>
|
||||
|
||||
169
conf/locale/locale_pt-BR.ini
Executable file → Normal file
169
conf/locale/locale_pt-BR.ini
Executable file → Normal 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
|
||||
@@ -85,7 +78,7 @@ ssh_port_helper=Número da porta que seu servidor SSH está usando, deixe vazio
|
||||
http_port=Porta HTTP
|
||||
http_port_helper=Número da porta em que a aplicação irá executar.
|
||||
app_url=URL do aplicativo
|
||||
app_url_helper=Isto afeta a URL de clonagem via HTTP/HTTPs e também o email.
|
||||
app_url_helper=Isto afeta a URL de clonagem via HTTP/HTTPs e também o e-mail.
|
||||
log_root_path=Caminho do log
|
||||
log_root_path_helper=Pasta dos arquivos de log.
|
||||
|
||||
@@ -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=Habilitar a busca federativa de avatares
|
||||
federated_avatar_lookup_popup=Habilitar a busca federativa de avatares a usar o serviço federativo de código aberto baseado no 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
|
||||
@@ -188,6 +189,13 @@ TeamName=Nome da equipe
|
||||
AuthName=Nome de autorização
|
||||
AdminEmail=E-mail do Administrador
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` não pode estar vazio.`
|
||||
alpha_dash_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
alpha_dash_dot_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
@@ -224,8 +232,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 +248,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 +269,12 @@ change_username_prompt=Essa alteração afetará os links para a sua conta.
|
||||
continue=Continuar
|
||||
cancel=Cancelar
|
||||
|
||||
lookup_avatar_by_mail=Busca de avatar por e-mail
|
||||
federated_avatar_lookup=Busca de avatar federativo
|
||||
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 +357,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=Selecionar templates de .gitignore
|
||||
license=Licença
|
||||
license_helper=Selecione um arquivo de licença
|
||||
readme=Leia-me
|
||||
@@ -355,9 +365,12 @@ 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.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Observadores
|
||||
stargazers=Usuários que estrelaram
|
||||
forks=Forks
|
||||
@@ -412,6 +425,45 @@ 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
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Pesquisar commits
|
||||
@@ -438,6 +490,11 @@ issues.create=Salvar
|
||||
issues.new_label=Nova etiqueta
|
||||
issues.new_label_placeholder=Nome da etiqueta...
|
||||
issues.create_label=Salvar
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d aberto
|
||||
issues.close_tab=%d fechados
|
||||
issues.filter_label=Etiqueta
|
||||
@@ -465,7 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Editar
|
||||
issues.cancel=Cancelar
|
||||
issues.save=Salvar
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Exclusão de etiqueta
|
||||
issues.label_deletion_desc=Excluir uma etiqueta a retirará de todos os problemas que ela estiver marcando. Quer mesmo continuar?
|
||||
issues.label_deletion_success=A etiqueta foi excluída com sucesso!
|
||||
issues.num_participants=%d participantes
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Novo Pull Request
|
||||
pulls.compare_changes=Comparar mudanças
|
||||
@@ -557,8 +616,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 +625,32 @@ 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.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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=Habilitar sistema de wiki
|
||||
settings.use_internal_wiki=Usar wiki nativa
|
||||
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=Habilitar issue tracker
|
||||
settings.use_internal_issue_tracker=Usar o issue tracker nativo
|
||||
settings.use_external_issue_tracker=Usar issue tracker externo
|
||||
settings.tracker_url_format=Formato de URL do issue tracker externo
|
||||
settings.tracker_issue_style=Estilo de nome de issue tracker externo:
|
||||
settings.tracker_issue_style.numeric=Numérico
|
||||
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 +665,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 +682,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.
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Preciso de <strong>tudo</strong>.
|
||||
settings.event_choose=Deixe-me escolher o que eu preciso.
|
||||
settings.event_create=Criar
|
||||
settings.event_create_desc=Branch ou Tag criado
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push para o repositório
|
||||
settings.active=Ativar
|
||||
@@ -688,6 +759,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 +791,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 +837,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 +959,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 +990,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 +1026,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 +1065,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 +1076,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 +1091,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 +1109,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=Habilitar avatares federativos
|
||||
|
||||
config.git_config=Configuração do Git
|
||||
config.git_disable_diff_highlight=Habilitar realce de mudanças no diff
|
||||
config.git_max_diff_lines=Máximo de linhas mostradas no diff (para um único arquivo)
|
||||
config.git_max_diff_line_characters=Máximo de caracteres mostrados no diff (para uma única linha)
|
||||
config.git_max_diff_files=Máximo de arquivos a serem mostrados no diff
|
||||
config.git_gc_args=Argumentos do coletor de lixo
|
||||
config.git_migrate_timeout=Timeout de migração
|
||||
config.git_mirror_timeout=Timeout para sincronização de espelho
|
||||
config.git_clone_timeout=Timeout para operação de clone
|
||||
config.git_pull_timeout=Timeout para operação de pull
|
||||
config.git_gc_timeout=Timeout para execução do coletor de lixo
|
||||
|
||||
config.log_config=Configuração de Log
|
||||
config.log_mode=Modo do Log
|
||||
|
||||
@@ -1066,8 +1163,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>
|
||||
|
||||
141
conf/locale/locale_ru-RU.ini
Executable file → Normal file
141
conf/locale/locale_ru-RU.ini
Executable file → Normal 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=Показать больше репозиториев...
|
||||
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=Пожалуйста активируйте свой аккаунт
|
||||
@@ -188,6 +189,13 @@ TeamName=Название команды
|
||||
AuthName=Имя авторизации
|
||||
AdminEmail=Электронная почта администратора
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=` не может быть пустым.`
|
||||
alpha_dash_error=«должен быть допустимым символьным, числовым или dash(-_) значением.»
|
||||
alpha_dash_dot_error=«должен быть допустимым символьным, числовым или dash(-_) символами, включая точку.»
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=Имя пользователя «%s» не доп
|
||||
[settings]
|
||||
profile=Профиль
|
||||
password=Пароль
|
||||
avatar=Аватар
|
||||
ssh_keys=SSH ключи
|
||||
social=Учетные записи в соцсетях
|
||||
applications=Приложения
|
||||
@@ -261,6 +269,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 +357,7 @@ fork_from=Ответвление от
|
||||
fork_visiblity_helper=Ответвленному репозиторию нельзя поменять уровень видимости
|
||||
repo_desc=Описание
|
||||
repo_lang=Язык
|
||||
repo_lang_helper=Выберите файлы .gitignore
|
||||
repo_gitignore_helper=Выберите шаблоны .gitignore
|
||||
license=Лицензия
|
||||
license_helper=Выберите файл лицензии
|
||||
readme=Readme
|
||||
@@ -355,9 +365,12 @@ 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=Укажите необходимые учетные данные в адрес.
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=Наблюдатели
|
||||
stargazers=Звездочеты
|
||||
forks=Ответвления
|
||||
@@ -412,6 +425,45 @@ file_raw=Исходник
|
||||
file_history=История
|
||||
file_view_raw=Посмотреть исходник
|
||||
file_permalink=Постоянная ссылка
|
||||
file_too_large=Этот файл слишком большой, поэтому он не может быть отображен
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=Коммиты
|
||||
commits.search=Поиск коммитов
|
||||
@@ -438,6 +490,11 @@ issues.create=Добавить задачу
|
||||
issues.new_label=Новая метка
|
||||
issues.new_label_placeholder=Имя метки...
|
||||
issues.create_label=Добавить метку
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d открыто(ы)
|
||||
issues.close_tab=%d закрыто(ы)
|
||||
issues.filter_label=Метка
|
||||
@@ -465,7 +522,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=Вы уверены, что хотите удалить этот комментарий?
|
||||
issues.no_content=Пока нет содержимого.
|
||||
issues.close_issue=Закрыть
|
||||
issues.close_comment_issue=Прокомментировать и закрыть
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at=`упомянул эту задачу в коммите <a
|
||||
issues.poster=Автор
|
||||
issues.collaborator=Соавтор
|
||||
issues.owner=Владелец
|
||||
issues.sign_up_for_free=Зарегистрируйтесь бесплатно
|
||||
issues.sign_in_require_desc=чтобы присоединиться к обсуждению. Уже есть аккаунт? <a href="%s">Войдите чтобы прокомментировать</a>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=Изменить
|
||||
issues.cancel=Отмена
|
||||
issues.save=Сохранить
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=Удаление метки
|
||||
issues.label_deletion_desc=Удаление ярлыка затронет все связанные задачи. Продолжить?
|
||||
issues.label_deletion_success=Метка была удалена успешно!
|
||||
issues.num_participants=%d участников
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=Новый запрос на слияние
|
||||
pulls.compare_changes=Сравнить изменения
|
||||
@@ -566,20 +625,32 @@ 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=Основные параметры
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
settings.site=Официальный сайт
|
||||
settings.update_settings=Обновить настройки
|
||||
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
|
||||
settings.advanced_settings=Расширенные настройки
|
||||
settings.wiki_desc=Включить Вики, чтобы позволить людям писать документы
|
||||
settings.wiki_desc=Включить систему Wiki
|
||||
settings.use_internal_wiki=Использовать встроенную wiki
|
||||
settings.use_external_wiki=Использовать внешнюю Wiki
|
||||
settings.external_wiki_url=URL-адрес внешней Вики
|
||||
settings.external_wiki_url_desc=Посетители будут перенаправлены на URL-адрес, когда они кликнут по вкладке.
|
||||
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
|
||||
settings.issues_desc=Включить систему отслеживания ошибок
|
||||
settings.use_internal_issue_tracker=Использовать встроенную легковесную систему отслеживания ошибок
|
||||
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
|
||||
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
|
||||
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 +673,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=Новый владелец
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=Мне нужно <strong>все</strong>.
|
||||
settings.event_choose=Позвольте мне выбрать то, что нужно.
|
||||
settings.event_create=Создать
|
||||
settings.event_create_desc=Ветка или тэг созданы
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Push в репозиторий
|
||||
settings.active=Активен
|
||||
@@ -681,13 +752,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=Разница между файлами не показана из-за своего большого размера
|
||||
diff.too_many_files=Некоторые файлы не были показаны из-за большого количества измененных файлов
|
||||
|
||||
release.releases=Релизы
|
||||
release.new_release=Новый релиз
|
||||
@@ -718,6 +791,7 @@ release.deletion=Удаление релиза
|
||||
release.deletion_desc=Удаление этого релиза удалит соответствующую Git метку. Вы хотите продолжить?
|
||||
release.deletion_success=Релиз был успешно удален!
|
||||
release.tag_name_already_exist=Релиз с этим именем метки уже существует.
|
||||
release.tag_name_invalid=Имя тега является не допустимым.
|
||||
release.downloads=Загрузки
|
||||
|
||||
[org]
|
||||
@@ -885,6 +959,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 +990,7 @@ auths.enabled=Включено
|
||||
auths.updated=Обновлено
|
||||
auths.auth_type=Тип аутентификации
|
||||
auths.auth_name=Имя аутентификации
|
||||
auths.security_protocol=Протокол безопасности
|
||||
auths.domain=Домен
|
||||
auths.host=Хост
|
||||
auths.port=Порт
|
||||
@@ -989,6 +1065,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 +1076,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 +1091,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 +1109,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
|
||||
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
|
||||
config.git_migrate_timeout=Тайм-аут миграции
|
||||
config.git_mirror_timeout=Время Ожидания Обновления Зеркала
|
||||
config.git_clone_timeout=Время Ожидания Операции Клонирования
|
||||
config.git_pull_timeout=Время Ожидания Операции Извлечения
|
||||
config.git_gc_timeout=Время Ожидания Операции Сборки Мусора
|
||||
|
||||
config.log_config=Конфигурация журнала
|
||||
config.log_mode=Режим журналирования
|
||||
|
||||
@@ -1060,7 +1157,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>`
|
||||
|
||||
1200
conf/locale/locale_tr-TR.ini
Normal file
1200
conf/locale/locale_tr-TR.ini
Normal file
File diff suppressed because it is too large
Load Diff
135
conf/locale/locale_zh-CN.ini
Executable file → Normal file
135
conf/locale/locale_zh-CN.ini
Executable file → Normal 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=请激活您的帐户
|
||||
@@ -188,6 +189,13 @@ TeamName=团队名称
|
||||
AuthName=认证名称
|
||||
AdminEmail=管理员邮箱
|
||||
|
||||
NewBranchName=新的分支名称
|
||||
CommitSummary=提交小结
|
||||
CommitMessage=提交消息
|
||||
CommitChoice=提交选择
|
||||
TreeName=文件路径
|
||||
Content=内容
|
||||
|
||||
require_error=不能为空。
|
||||
alpha_dash_error=必须为英文字母、阿拉伯数字或横线(-_)。
|
||||
alpha_dash_dot_error=必须为英文字母、阿拉伯数字、横线(-_)或点。
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
|
||||
[settings]
|
||||
profile=个人信息
|
||||
password=修改密码
|
||||
avatar=头像设置
|
||||
ssh_keys=管理 SSH 密钥
|
||||
social=社交帐号绑定
|
||||
applications=管理授权应用
|
||||
@@ -261,6 +269,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 +357,7 @@ fork_from=派生自
|
||||
fork_visiblity_helper=派生仓库无法修改可见性
|
||||
repo_desc=仓库描述
|
||||
repo_lang=仓库语言
|
||||
repo_lang_helper=请选择 .gitignore 文件
|
||||
repo_gitignore_helper=选择 .gitignore 模板
|
||||
license=授权许可
|
||||
license_helper=请选择授权许可文件
|
||||
readme=自述文档
|
||||
@@ -355,9 +365,12 @@ readme_helper=请选择自述文档模板
|
||||
auto_init=使用选定的文件和模板初始化仓库
|
||||
create_repo=创建仓库
|
||||
default_branch=默认分支
|
||||
mirror_prune=修剪
|
||||
mirror_prune_desc=当远程追踪的引用被删除时本地也同步删除
|
||||
mirror_interval=镜像同步周期(小时)
|
||||
mirror_address=镜像地址
|
||||
mirror_address_desc=请在镜像地址中写入必要的用户凭据信息。
|
||||
mirror_last_synced=上次同步时间:
|
||||
watchers=关注者
|
||||
stargazers=称赞者
|
||||
forks=派生仓库
|
||||
@@ -412,6 +425,45 @@ file_raw=原始文件
|
||||
file_history=文件历史
|
||||
file_view_raw=查看原始文件
|
||||
file_permalink=永久链接
|
||||
file_too_large=文件过大导致无法显示
|
||||
|
||||
editor.new_file=新的文件
|
||||
editor.upload_file=上传文件
|
||||
editor.edit_file=编辑文件
|
||||
editor.preview_changes=预览变更
|
||||
editor.cannot_edit_non_text_files=无法编辑非文本文件
|
||||
editor.edit_this_file=编辑此文件
|
||||
editor.must_be_on_a_branch=您必须在某个分支上才能对此文件进行修改操作
|
||||
editor.fork_before_edit=您必须派生此仓库才能对此文件进行修改操作
|
||||
editor.delete_this_file=删除此文件
|
||||
editor.must_have_write_access=您必须具有可写权限才能对此文件进行修改操作
|
||||
editor.file_delete_success=文件 '%s' 删除成功!
|
||||
editor.name_your_file=命名文件...
|
||||
editor.filename_help=输入名称后按下 / 键即可添加目录,或将光标移至输入框最左侧按下退格键移除目录。
|
||||
editor.or=或
|
||||
editor.cancel_lower=取消
|
||||
editor.commit_changes=提交变更
|
||||
editor.add_tmpl=添加 '%s/<文件名>'
|
||||
editor.add=添加 '%s'
|
||||
editor.update=更新 '%s'
|
||||
editor.delete=删除 '%s'
|
||||
editor.commit_message_desc=添加一个可选的扩展描述...
|
||||
editor.commit_directly_to_this_branch=直接提交至 <strong class="branch-name">%s</strong> 分支。
|
||||
editor.create_new_branch=为此提交创建一个 <strong>新的分支</strong> 并发起合并请求。
|
||||
editor.new_branch_name_desc=新的分支名称...
|
||||
editor.cancel=取消
|
||||
editor.filename_cannot_be_empty=文件名不能为空。
|
||||
editor.branch_already_exists=此仓库已存在名为 '%s' 的分支。
|
||||
editor.directory_is_a_file=路径 '%s' 的父路径中包含此仓库已存在的文件名。
|
||||
editor.filename_is_a_directory=文件名 '%s' 是此仓库中已存在的目录名。
|
||||
editor.file_editing_no_longer_exists=您编辑的文件 '%s' 已经不存在于此仓库中。
|
||||
editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。<a target="_blank" href="%s">单击此处</a> 查看变动的具体内容,或者 <strong>再次提交</strong> 覆盖已发生的变动。
|
||||
editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。
|
||||
editor.no_changes_to_show=没有可以显示的变更。
|
||||
editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v
|
||||
editor.add_subdir=添加子目录...
|
||||
editor.unable_to_upload_files=上传文件至 '%s' 时发生错误:%v
|
||||
editor.upload_files_to_dir=上传文件至 '%s'
|
||||
|
||||
commits.commits=次代码提交
|
||||
commits.search=搜索提交历史
|
||||
@@ -438,6 +490,11 @@ issues.create=创建工单
|
||||
issues.new_label=创建标签
|
||||
issues.new_label_placeholder=标签名称...
|
||||
issues.create_label=创建标签
|
||||
issues.label_templates.title=加载预定义的标签模板
|
||||
issues.label_templates.info=此仓库还未创建任何标签,您可以通过上方的 "创建标签" 创建一个新的标签或加载一组预定义的标签。
|
||||
issues.label_templates.helper=选择标签模板
|
||||
issues.label_templates.use=加载标签模板
|
||||
issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v
|
||||
issues.open_tab=%d 个开启中
|
||||
issues.close_tab=%d 个已关闭
|
||||
issues.filter_label=标签筛选
|
||||
@@ -465,7 +522,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=评论并关闭
|
||||
@@ -478,8 +536,7 @@ issues.commit_ref_at=`在代码提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中
|
||||
issues.poster=发布者
|
||||
issues.collaborator=协作者
|
||||
issues.owner=所有者
|
||||
issues.sign_up_for_free=免费注册
|
||||
issues.sign_in_require_desc=并加入到对话中来。如果您已经注册,可以直接 <a href="%s">登录并评论</a>
|
||||
issues.sign_in_require_desc=<a href="%s">登陆</a> 并参与到对话中。
|
||||
issues.edit=编辑
|
||||
issues.cancel=取消
|
||||
issues.save=保存
|
||||
@@ -494,6 +551,8 @@ issues.label_deletion=删除标签操作
|
||||
issues.label_deletion_desc=删除该标签将会移除所有工单中相关的信息。是否继续?
|
||||
issues.label_deletion_success=标签删除成功!
|
||||
issues.num_participants=%d 名参与者
|
||||
issues.attachment.open_tab=`在新的标签页中查看 '%s'`
|
||||
issues.attachment.download=`点击下载 '%s'`
|
||||
|
||||
pulls.new=创建合并请求
|
||||
pulls.compare_changes=对比文件变化
|
||||
@@ -566,20 +625,32 @@ 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=基本设置
|
||||
settings.mirror_settings=镜像设置
|
||||
settings.sync_mirror=立即同步
|
||||
settings.mirror_sync_in_progress=镜像同步请求已经生效,请稍后刷新页面。
|
||||
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 +673,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=新拥有者
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=请把 <strong>一切</strong> 都给我
|
||||
settings.event_choose=我的命运自己主宰
|
||||
settings.event_create=创建
|
||||
settings.event_create_desc=创建分支或标签
|
||||
settings.event_pull_request=合并请求
|
||||
settings.event_pull_request_desc=开启、关闭、重新开启、编辑、指派、取消指派、更新标签、清除标签或同步合并请求
|
||||
settings.event_push=推送
|
||||
settings.event_push_desc=Git 仓库推送
|
||||
settings.active=是否激活
|
||||
@@ -688,6 +759,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 +791,7 @@ release.deletion=删除版本发布操作
|
||||
release.deletion_desc=删除该版本发布将会移除相应的 Git 标签。是否继续?
|
||||
release.deletion_success=版本发布删除成功!
|
||||
release.tag_name_already_exist=已经存在使用相同标签进行发布的版本。
|
||||
release.tag_name_invalid=标签名称不是有效的名称。
|
||||
release.downloads=下载附件
|
||||
|
||||
[org]
|
||||
@@ -885,6 +959,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 +990,7 @@ auths.enabled=已启用
|
||||
auths.updated=最后更新时间
|
||||
auths.auth_type=认证类型
|
||||
auths.auth_name=认证名称
|
||||
auths.security_protocol=安全协议
|
||||
auths.domain=域名
|
||||
auths.host=主机地址
|
||||
auths.port=主机端口
|
||||
@@ -989,6 +1065,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 +1076,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 +1091,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 +1109,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=日志模式
|
||||
|
||||
|
||||
191
conf/locale/locale_zh-HK.ini
Executable file → Normal file
191
conf/locale/locale_zh-HK.ini
Executable file → Normal 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=請激活您的帳戶
|
||||
@@ -188,6 +189,13 @@ TeamName=團隊名稱
|
||||
AuthName=認證名稱
|
||||
AdminEmail=管理員郵箱
|
||||
|
||||
NewBranchName=New branch name
|
||||
CommitSummary=Commit summary
|
||||
CommitMessage=Commit message
|
||||
CommitChoice=Commit choice
|
||||
TreeName=File path
|
||||
Content=Content
|
||||
|
||||
require_error=不能為空。
|
||||
alpha_dash_error=必須為英文字母、阿拉伯數字或橫線(-_)。
|
||||
alpha_dash_dot_error=必須為英文字母、阿拉伯數字、橫線(-_)或點。
|
||||
@@ -224,8 +232,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 +248,7 @@ form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
|
||||
[settings]
|
||||
profile=個人信息
|
||||
password=修改密碼
|
||||
avatar=Avatar
|
||||
ssh_keys=管理 SSH 密鑰
|
||||
social=社交帳號綁定
|
||||
applications=管理授權應用
|
||||
@@ -261,10 +269,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 +357,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,9 +365,12 @@ 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=請在位址中包括必要的使用者憑據。
|
||||
mirror_last_synced=Last Synced
|
||||
watchers=關注者
|
||||
stargazers=稱讚者
|
||||
forks=派生倉庫
|
||||
@@ -387,7 +400,7 @@ unwatch=取消關注
|
||||
watch=關註
|
||||
unstar=取消讚好
|
||||
star=讚好
|
||||
fork=派生
|
||||
fork=複刻
|
||||
|
||||
no_desc=暫無描述
|
||||
quick_guide=快速幫助
|
||||
@@ -412,6 +425,45 @@ file_raw=原始文件
|
||||
file_history=文件歷史
|
||||
file_view_raw=查看原始文件
|
||||
file_permalink=永久連結
|
||||
file_too_large=This file is too large to be shown
|
||||
|
||||
editor.new_file=New file
|
||||
editor.upload_file=Upload file
|
||||
editor.edit_file=Edit file
|
||||
editor.preview_changes=Preview Changes
|
||||
editor.cannot_edit_non_text_files=Cannot edit non-text files
|
||||
editor.edit_this_file=Edit this file
|
||||
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
|
||||
editor.fork_before_edit=You must fork this repository before editing the file
|
||||
editor.delete_this_file=Delete this file
|
||||
editor.must_have_write_access=You must have write access to make or propose changes to this file
|
||||
editor.file_delete_success=File '%s' has been deleted successfully!
|
||||
editor.name_your_file=Name your file...
|
||||
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
|
||||
editor.or=or
|
||||
editor.cancel_lower=cancel
|
||||
editor.commit_changes=Commit Changes
|
||||
editor.add_tmpl=Add '%s/<filename>'
|
||||
editor.add=Add '%s'
|
||||
editor.update=Update '%s'
|
||||
editor.delete=Delete '%s'
|
||||
editor.commit_message_desc=Add an optional extended description...
|
||||
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
|
||||
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
|
||||
editor.new_branch_name_desc=New branch name...
|
||||
editor.cancel=Cancel
|
||||
editor.filename_cannot_be_empty=Filename cannot be empty.
|
||||
editor.branch_already_exists=Branch '%s' already exists in this repository.
|
||||
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
|
||||
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
|
||||
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
|
||||
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
|
||||
editor.file_already_exists=A file with name '%s' already exists in this repository.
|
||||
editor.no_changes_to_show=There are no changes to show.
|
||||
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
|
||||
editor.add_subdir=Add subdirectory...
|
||||
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
|
||||
editor.upload_files_to_dir=Upload files to '%s'
|
||||
|
||||
commits.commits=次代碼提交
|
||||
commits.search=搜索提交歷史
|
||||
@@ -438,6 +490,11 @@ issues.create=創建問題
|
||||
issues.new_label=創建標籤
|
||||
issues.new_label_placeholder=標籤名稱...
|
||||
issues.create_label=創建標籤
|
||||
issues.label_templates.title=Load a predefined set of labels
|
||||
issues.label_templates.info=There aren’t any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||
issues.label_templates.helper=Select a label set
|
||||
issues.label_templates.use=Use this label set
|
||||
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
|
||||
issues.open_tab=%d 個開啓中
|
||||
issues.close_tab=%d 個已關閉
|
||||
issues.filter_label=標籤篩選
|
||||
@@ -465,7 +522,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,10 +534,9 @@ 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>
|
||||
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
|
||||
issues.edit=編輯
|
||||
issues.cancel=取消
|
||||
issues.save=保存
|
||||
@@ -493,7 +550,9 @@ issues.label_modify=修改標籤
|
||||
issues.label_deletion=刪除標籤
|
||||
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
|
||||
issues.label_deletion_success=標籤刪除成功!
|
||||
issues.num_participants=%d Participants
|
||||
issues.num_participants=%d 參與者
|
||||
issues.attachment.open_tab=`Click to see "%s" in a new tab`
|
||||
issues.attachment.download=`Click to download "%s"`
|
||||
|
||||
pulls.new=創建合併請求
|
||||
pulls.compare_changes=對比文件變化
|
||||
@@ -557,8 +616,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,26 +625,38 @@ 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=基本設置
|
||||
settings.mirror_settings=Mirror Settings
|
||||
settings.sync_mirror=Sync Now
|
||||
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
|
||||
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 +665,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 +682,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=被操作的協作者已經被收回權限!
|
||||
@@ -651,6 +720,8 @@ settings.event_send_everything=推送 <strong>所有</strong> 事件
|
||||
settings.event_choose=讓我選擇我的需要
|
||||
settings.event_create=創建
|
||||
settings.event_create_desc=創建分支或標籤
|
||||
settings.event_pull_request=Pull Request
|
||||
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push=推送
|
||||
settings.event_push_desc=Git 倉庫推送
|
||||
settings.active=是否激活
|
||||
@@ -688,6 +759,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 +791,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 +959,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 +990,7 @@ auths.enabled=已啟用
|
||||
auths.updated=最後更新時間
|
||||
auths.auth_type=認證類型
|
||||
auths.auth_name=認證名稱
|
||||
auths.security_protocol=Security Protocol
|
||||
auths.domain=域名
|
||||
auths.host=主機地址
|
||||
auths.port=主機端口
|
||||
@@ -968,17 +1044,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 +1065,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 +1076,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 +1109,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=日誌模式
|
||||
|
||||
|
||||
1200
conf/locale/locale_zh-TW.ini
Normal file
1200
conf/locale/locale_zh-TW.ini
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
152
glide.lock
generated
Normal file
152
glide.lock
generated
Normal file
@@ -0,0 +1,152 @@
|
||||
hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
|
||||
updated: 2016-06-12T17:35:14.27036884+08:00
|
||||
imports:
|
||||
- name: github.com/bradfitz/gomemcache
|
||||
version: fb1f79c6b65acda83063cbc69f6bba1522558bfc
|
||||
subpackages:
|
||||
- memcache
|
||||
- name: github.com/urfave/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: 5e0c1330d7853d1affbc193885d517db0f8d1ca5
|
||||
- name: github.com/gogits/go-gogs-client
|
||||
version: c52f7ee0cc58d3cd6e379025552873a8df6de322
|
||||
- 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/editorconfig/editorconfig-core-go.v1
|
||||
version: a872f05c2e34b37b567401384d202aff11ba06d4
|
||||
- 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: []
|
||||
59
glide.yaml
Normal file
59
glide.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
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/urfave/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/editorconfig/editorconfig-core-go.v1
|
||||
- package: gopkg.in/gomail.v2
|
||||
- package: gopkg.in/ini.v1
|
||||
- package: gopkg.in/ldap.v2
|
||||
- package: gopkg.in/macaron.v1
|
||||
7
gogs.go
7
gogs.go
@@ -11,13 +11,13 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/cmd"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.9.0.0306"
|
||||
const APP_VER = "0.9.97.0901"
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "Gogs"
|
||||
app.Usage = "Go Git Service"
|
||||
app.Usage = "Go Git Service: a painless self-hosted Git service"
|
||||
app.Version = APP_VER
|
||||
app.Commands = []cli.Command{
|
||||
cmd.CmdWeb,
|
||||
@@ -35,6 +35,7 @@ func main() {
|
||||
cmd.CmdUpdate,
|
||||
cmd.CmdDump,
|
||||
cmd.CmdCert,
|
||||
cmd.CmdAdmin,
|
||||
}
|
||||
app.Flags = append(app.Flags, []cli.Flag{}...)
|
||||
app.Run(os.Args)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
271
models/action.go
271
models/action.go
@@ -6,7 +6,6 @@ package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
@@ -45,10 +44,6 @@ const (
|
||||
ACTION_REOPEN_PULL_REQUEST // 15
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("Not implemented yet")
|
||||
)
|
||||
|
||||
var (
|
||||
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
|
||||
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
|
||||
@@ -76,7 +71,6 @@ type Action struct {
|
||||
OpType ActionType
|
||||
ActUserID int64 // Action user id.
|
||||
ActUserName string // Action user name.
|
||||
ActEmail string
|
||||
ActAvatar string `xorm:"-"`
|
||||
RepoID int64
|
||||
RepoUserName string
|
||||
@@ -84,13 +78,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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,10 +105,6 @@ func (a *Action) ShortActUserName() string {
|
||||
return base.EllipsisString(a.ActUserName, 20)
|
||||
}
|
||||
|
||||
func (a *Action) GetActEmail() string {
|
||||
return a.ActEmail
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoUserName() string {
|
||||
return a.RepoUserName
|
||||
}
|
||||
@@ -164,7 +159,7 @@ func (a *Action) GetIssueTitle() string {
|
||||
log.Error(4, "GetIssueByIndex: %v", err)
|
||||
return "500 when get issue"
|
||||
}
|
||||
return issue.Name
|
||||
return issue.Title
|
||||
}
|
||||
|
||||
func (a *Action) GetIssueContent() string {
|
||||
@@ -179,16 +174,15 @@ 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,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
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,9 +196,8 @@ 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,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
@@ -229,16 +222,19 @@ 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 {
|
||||
Len int
|
||||
Commits []*PushCommit
|
||||
CompareUrl string
|
||||
CompareURL string
|
||||
|
||||
avatars map[string]string
|
||||
}
|
||||
@@ -251,21 +247,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),
|
||||
Author: &api.PayloadAuthor{
|
||||
Name: cmt.AuthorName,
|
||||
Email: cmt.AuthorEmail,
|
||||
UserName: author_username,
|
||||
ID: commit.Sha1,
|
||||
Message: commit.Message,
|
||||
URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1),
|
||||
Author: &api.PayloadUser{
|
||||
Name: commit.AuthorName,
|
||||
Email: commit.AuthorEmail,
|
||||
UserName: authorUsername,
|
||||
},
|
||||
Committer: &api.PayloadUser{
|
||||
Name: commit.CommitterName,
|
||||
Email: commit.CommitterEmail,
|
||||
UserName: committerUsername,
|
||||
},
|
||||
Timestamp: commit.Timestamp,
|
||||
}
|
||||
}
|
||||
return commits
|
||||
@@ -283,15 +291,15 @@ func (push *PushCommits) AvatarLink(email string) string {
|
||||
log.Error(4, "GetUserByEmail: %v", err)
|
||||
}
|
||||
} else {
|
||||
push.avatars[email] = u.AvatarLink()
|
||||
push.avatars[email] = u.RelAvatarLink()
|
||||
}
|
||||
}
|
||||
|
||||
return push.avatars[email]
|
||||
}
|
||||
|
||||
// updateIssuesCommit checks if issues are manipulated by commit message.
|
||||
func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*PushCommit) error {
|
||||
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
||||
func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) error {
|
||||
// Commits are appended in the reverse order.
|
||||
for i := len(commits) - 1; i >= 0; i-- {
|
||||
c := commits[i]
|
||||
@@ -307,7 +315,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
|
||||
// Add repo name if missing
|
||||
if ref[0] == '#' {
|
||||
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
|
||||
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
|
||||
} else if !strings.Contains(ref, "/") {
|
||||
// FIXME: We don't support User#ID syntax yet
|
||||
// return ErrNotImplemented
|
||||
@@ -327,9 +335,8 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
}
|
||||
refMarked[issue.ID] = true
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1)
|
||||
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
|
||||
if err = CreateRefComment(u, repo, issue, message, c.Sha1); err != nil {
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, c.Message)
|
||||
if err = CreateRefComment(doer, repo, issue, message, c.Sha1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -346,7 +353,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
|
||||
// Add repo name if missing
|
||||
if ref[0] == '#' {
|
||||
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
|
||||
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
|
||||
} else if !strings.Contains(ref, "/") {
|
||||
// We don't support User#ID syntax yet
|
||||
// return ErrNotImplemented
|
||||
@@ -370,7 +377,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
continue
|
||||
}
|
||||
|
||||
if err = issue.ChangeStatus(u, repo, true); err != nil {
|
||||
if err = issue.ChangeStatus(doer, repo, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -386,7 +393,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
|
||||
// Add repo name if missing
|
||||
if ref[0] == '#' {
|
||||
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
|
||||
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
|
||||
} else if !strings.Contains(ref, "/") {
|
||||
// We don't support User#ID syntax yet
|
||||
// return ErrNotImplemented
|
||||
@@ -410,7 +417,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
continue
|
||||
}
|
||||
|
||||
if err = issue.ChangeStatus(u, repo, false); err != nil {
|
||||
if err = issue.ChangeStatus(doer, repo, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -418,26 +425,26 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommitRepoAction adds new action for committing repository.
|
||||
func CommitRepoAction(
|
||||
userID, repoUserID int64,
|
||||
userName, actEmail string,
|
||||
repoID int64,
|
||||
repoUserName, repoName string,
|
||||
refFullName string,
|
||||
commit *PushCommits,
|
||||
oldCommitID string, newCommitID string) error {
|
||||
type CommitRepoActionOptions struct {
|
||||
PusherName string
|
||||
RepoOwnerID int64
|
||||
RepoName string
|
||||
RefFullName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
Commits *PushCommits
|
||||
}
|
||||
|
||||
u, err := GetUserByID(userID)
|
||||
// CommitRepoAction adds new commit actio to the repository, and prepare corresponding webhooks.
|
||||
func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
pusher, err := GetUserByName(opts.PusherName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID: %v", err)
|
||||
return fmt.Errorf("GetUserByName [%s]: %v", opts.PusherName, err)
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(repoUserID, repoName)
|
||||
repo, err := GetRepositoryByName(opts.RepoOwnerID, opts.RepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByName: %v", err)
|
||||
} else if err = repo.GetOwner(); err != nil {
|
||||
return fmt.Errorf("GetOwner: %v", err)
|
||||
return fmt.Errorf("GetRepositoryByName [owner_id: %d, name: %s]: %v", opts.RepoOwnerID, opts.RepoName, err)
|
||||
}
|
||||
|
||||
// Change repository bare status and update last updated time.
|
||||
@@ -449,79 +456,64 @@ func CommitRepoAction(
|
||||
isNewBranch := false
|
||||
opType := ACTION_COMMIT_REPO
|
||||
// Check it's tag push or branch.
|
||||
if strings.HasPrefix(refFullName, "refs/tags/") {
|
||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
||||
opType = ACTION_PUSH_TAG
|
||||
commit = &PushCommits{}
|
||||
opts.Commits = &PushCommits{}
|
||||
} else {
|
||||
// if not the first commit, set the compareUrl
|
||||
if !strings.HasPrefix(oldCommitID, "0000000") {
|
||||
commit.CompareUrl = repo.ComposeCompareURL(oldCommitID, newCommitID)
|
||||
} else {
|
||||
// if not the first commit, set the compare URL.
|
||||
if opts.OldCommitID == git.EMPTY_SHA {
|
||||
isNewBranch = true
|
||||
} else {
|
||||
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||
}
|
||||
|
||||
if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil {
|
||||
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil {
|
||||
log.Error(4, "updateIssuesCommit: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(commit.Commits) > setting.FeedMaxCommitNum {
|
||||
commit.Commits = commit.Commits[:setting.FeedMaxCommitNum]
|
||||
if len(opts.Commits.Commits) > setting.UI.FeedMaxCommitNum {
|
||||
opts.Commits.Commits = opts.Commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(commit)
|
||||
data, err := json.Marshal(opts.Commits)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Marshal: %v", err)
|
||||
}
|
||||
|
||||
refName := git.RefEndName(refFullName)
|
||||
|
||||
refName := git.RefEndName(opts.RefFullName)
|
||||
if err = NotifyWatchers(&Action{
|
||||
ActUserID: u.Id,
|
||||
ActUserName: userName,
|
||||
ActEmail: actEmail,
|
||||
ActUserID: pusher.ID,
|
||||
ActUserName: pusher.Name,
|
||||
OpType: opType,
|
||||
Content: string(bs),
|
||||
Content: string(data),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repoUserName,
|
||||
RepoName: repoName,
|
||||
RepoUserName: repo.MustOwner().Name,
|
||||
RepoName: repo.Name,
|
||||
RefName: refName,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
payloadRepo := repo.ComposePayload()
|
||||
|
||||
pusher_email, pusher_name := "", ""
|
||||
pusher, err := GetUserByName(userName)
|
||||
if err == nil {
|
||||
pusher_email = pusher.Email
|
||||
pusher_name = pusher.DisplayName()
|
||||
}
|
||||
payloadSender := &api.PayloadUser{
|
||||
UserName: pusher.Name,
|
||||
ID: pusher.Id,
|
||||
AvatarUrl: pusher.AvatarLink(),
|
||||
}
|
||||
defer func() {
|
||||
go HookQueue.Add(repo.ID)
|
||||
}()
|
||||
|
||||
apiPusher := pusher.APIFormat()
|
||||
apiRepo := repo.APIFormat(nil)
|
||||
switch opType {
|
||||
case ACTION_COMMIT_REPO: // Push
|
||||
p := &api.PushPayload{
|
||||
Ref: refFullName,
|
||||
Before: oldCommitID,
|
||||
After: newCommitID,
|
||||
CompareUrl: setting.AppUrl + commit.CompareUrl,
|
||||
Commits: commit.ToApiPayloadCommits(repo.FullRepoLink()),
|
||||
Repo: payloadRepo,
|
||||
Pusher: &api.PayloadAuthor{
|
||||
Name: pusher_name,
|
||||
Email: pusher_email,
|
||||
UserName: userName,
|
||||
},
|
||||
Sender: payloadSender,
|
||||
}
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, p); err != nil {
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, &api.PushPayload{
|
||||
Ref: opts.RefFullName,
|
||||
Before: opts.OldCommitID,
|
||||
After: opts.NewCommitID,
|
||||
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
|
||||
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
|
||||
Repo: apiRepo,
|
||||
Pusher: apiPusher,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks: %v", err)
|
||||
}
|
||||
|
||||
@@ -529,8 +521,8 @@ func CommitRepoAction(
|
||||
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "branch",
|
||||
Repo: payloadRepo,
|
||||
Sender: payloadSender,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -538,52 +530,50 @@ func CommitRepoAction(
|
||||
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
Repo: payloadRepo,
|
||||
Sender: payloadSender,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repository) (err error) {
|
||||
func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err error) {
|
||||
if err = notifyWatchers(e, &Action{
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
ActUserID: doer.ID,
|
||||
ActUserName: doer.Name,
|
||||
OpType: ACTION_TRANSFER_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: newOwner.Name,
|
||||
RepoUserName: repo.Owner.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("notifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
// Remove watch for organization.
|
||||
if repo.Owner.IsOrganization() {
|
||||
if err = watchRepo(e, repo.Owner.Id, repo.ID, false); err != nil {
|
||||
return fmt.Errorf("watch repository: %v", err)
|
||||
if oldOwner.IsOrganization() {
|
||||
if err = watchRepo(e, oldOwner.ID, repo.ID, false); err != nil {
|
||||
return fmt.Errorf("watchRepo [false]: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("action.transferRepoAction: %s/%s", actUser.Name, repo.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransferRepoAction adds new action for transferring repository.
|
||||
func TransferRepoAction(actUser, oldOwner, newOwner *User, repo *Repository) error {
|
||||
return transferRepoAction(x, actUser, oldOwner, newOwner, repo)
|
||||
// TransferRepoAction adds new action for transferring repository,
|
||||
// the Owner field of repository is assumed to be new owner.
|
||||
func TransferRepoAction(doer, oldOwner *User, repo *Repository) error {
|
||||
return transferRepoAction(x, doer, oldOwner, repo)
|
||||
}
|
||||
|
||||
func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Issue) error {
|
||||
func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue) error {
|
||||
return notifyWatchers(e, &Action{
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
ActUserID: doer.ID,
|
||||
ActUserName: doer.Name,
|
||||
OpType: ACTION_MERGE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -597,21 +587,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
124
models/error.go
124
models/error.go
@@ -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,33 @@ 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)
|
||||
}
|
||||
|
||||
type ErrRepoFileAlreadyExist struct {
|
||||
FileName string
|
||||
}
|
||||
|
||||
func IsErrRepoFileAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrRepoFileAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrRepoFileAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("repository file already exists [file_name: %s]", err.FileName)
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
@@ -409,7 +447,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)
|
||||
}
|
||||
|
||||
// __ __ ___. .__ __
|
||||
@@ -488,7 +526,8 @@ func (err ErrPullRequestNotExist) Error() string {
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type ErrCommentNotExist struct {
|
||||
ID int64
|
||||
ID int64
|
||||
IssueID int64
|
||||
}
|
||||
|
||||
func IsErrCommentNotExist(err error) bool {
|
||||
@@ -497,7 +536,7 @@ func IsErrCommentNotExist(err error) bool {
|
||||
}
|
||||
|
||||
func (err ErrCommentNotExist) Error() string {
|
||||
return fmt.Sprintf("comment does not exist [id: %d]", err.ID)
|
||||
return fmt.Sprintf("comment does not exist [id: %d, issue_id: %d]", err.ID, err.IssueID)
|
||||
}
|
||||
|
||||
// .____ ___. .__
|
||||
@@ -508,7 +547,8 @@ func (err ErrCommentNotExist) Error() string {
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type ErrLabelNotExist struct {
|
||||
ID int64
|
||||
LabelID int64
|
||||
RepoID int64
|
||||
}
|
||||
|
||||
func IsErrLabelNotExist(err error) bool {
|
||||
@@ -517,7 +557,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)
|
||||
}
|
||||
|
||||
// _____ .__.__ __
|
||||
@@ -562,24 +602,50 @@ func (err ErrAttachmentNotExist) Error() string {
|
||||
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
||||
}
|
||||
|
||||
// _____ __ .__ __ .__ __ .__
|
||||
// / _ \ __ ___/ |_| |__ ____ _____/ |_|__| ____ _____ _/ |_|__| ____ ____
|
||||
// / /_\ \| | \ __\ | \_/ __ \ / \ __\ |/ ___\\__ \\ __\ |/ _ \ / \
|
||||
// / | \ | /| | | Y \ ___/| | \ | | \ \___ / __ \| | | ( <_> ) | \
|
||||
// \____|__ /____/ |__| |___| /\___ >___| /__| |__|\___ >____ /__| |__|\____/|___| /
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
// .____ .__ _________
|
||||
// | | ____ ____ |__| ____ / _____/ ____ __ _________ ____ ____
|
||||
// | | / _ \ / ___\| |/ \ \_____ \ / _ \| | \_ __ \_/ ___\/ __ \
|
||||
// | |__( <_> ) /_/ > | | \ / ( <_> ) | /| | \/\ \__\ ___/
|
||||
// |_______ \____/\___ /|__|___| / /_______ /\____/|____/ |__| \___ >___ >
|
||||
// \/ /_____/ \/ \/ \/ \/
|
||||
|
||||
type ErrAuthenticationNotExist struct {
|
||||
type ErrLoginSourceNotExist struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func IsErrAuthenticationNotExist(err error) bool {
|
||||
_, ok := err.(ErrAuthenticationNotExist)
|
||||
func IsErrLoginSourceNotExist(err error) bool {
|
||||
_, ok := err.(ErrLoginSourceNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrAuthenticationNotExist) Error() string {
|
||||
return fmt.Sprintf("authentication does not exist [id: %d]", err.ID)
|
||||
func (err ErrLoginSourceNotExist) Error() string {
|
||||
return fmt.Sprintf("login source does not exist [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
type ErrLoginSourceAlreadyExist struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrLoginSourceAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrLoginSourceAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrLoginSourceAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("login source already exists [name: %s]", err.Name)
|
||||
}
|
||||
|
||||
type ErrLoginSourceInUse struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func IsErrLoginSourceInUse(err error) bool {
|
||||
_, ok := err.(ErrLoginSourceInUse)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrLoginSourceInUse) Error() string {
|
||||
return fmt.Sprintf("login source is still used by some users [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
// ___________
|
||||
@@ -602,3 +668,25 @@ func IsErrTeamAlreadyExist(err error) bool {
|
||||
func (err ErrTeamAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
|
||||
}
|
||||
|
||||
// ____ ___ .__ .___
|
||||
// | | \______ | | _________ __| _/
|
||||
// | | /\____ \| | / _ \__ \ / __ |
|
||||
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
|
||||
// |______/ | __/|____/\____(____ /\____ |
|
||||
// |__| \/ \/
|
||||
//
|
||||
|
||||
type ErrUploadNotExist struct {
|
||||
ID int64
|
||||
UUID string
|
||||
}
|
||||
|
||||
func IsErrUploadNotExist(err error) bool {
|
||||
_, ok := err.(ErrAttachmentNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUploadNotExist) Error() string {
|
||||
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
||||
}
|
||||
|
||||
@@ -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,27 @@ var (
|
||||
)
|
||||
|
||||
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
|
||||
var buf bytes.Buffer
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Reproduce signs which are cutted for inline diff before.
|
||||
switch lineType {
|
||||
case DIFF_LINE_ADD:
|
||||
buf.WriteByte('+')
|
||||
case DIFF_LINE_DEL:
|
||||
buf.WriteByte('-')
|
||||
}
|
||||
|
||||
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 +101,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))
|
||||
}
|
||||
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))
|
||||
}
|
||||
diff1 = diffLine.Content
|
||||
diff2 = compareDiffLine.Content
|
||||
default:
|
||||
return template.HTML(html.EscapeString(diffLine.Content))
|
||||
}
|
||||
|
||||
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 +195,9 @@ type DiffFile struct {
|
||||
IsDeleted bool
|
||||
IsBin bool
|
||||
IsRenamed bool
|
||||
IsSubmodule bool
|
||||
Sections []*DiffSection
|
||||
IsIncomplete bool
|
||||
}
|
||||
|
||||
func (diffFile *DiffFile) GetType() int {
|
||||
@@ -174,6 +211,7 @@ func (diffFile *DiffFile) GetHighlightClass() string {
|
||||
type Diff struct {
|
||||
TotalAddition, TotalDeletion int
|
||||
Files []*DiffFile
|
||||
IsIncomplete bool
|
||||
}
|
||||
|
||||
func (diff *Diff) NumFiles() int {
|
||||
@@ -182,7 +220,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 +232,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 +252,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 +336,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 +370,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 +407,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
|
||||
}
|
||||
@@ -402,10 +443,10 @@ func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxline
|
||||
return nil, fmt.Errorf("Start: %v", err)
|
||||
}
|
||||
|
||||
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
|
||||
pid := process.Add(fmt.Sprintf("GetDiffRange [repo_path: %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 +458,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)
|
||||
}
|
||||
|
||||
@@ -19,52 +19,17 @@ func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) {
|
||||
}
|
||||
|
||||
func TestDiffToHTML(t *testing.T) {
|
||||
assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
||||
assertEqual(t, "+foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
||||
dmp.Diff{dmp.DiffEqual, "foo "},
|
||||
dmp.Diff{dmp.DiffInsert, "bar"},
|
||||
dmp.Diff{dmp.DiffDelete, " baz"},
|
||||
dmp.Diff{dmp.DiffEqual, " biz"},
|
||||
}, DIFF_LINE_ADD))
|
||||
|
||||
assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
||||
assertEqual(t, "-foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
||||
dmp.Diff{dmp.DiffEqual, "foo "},
|
||||
dmp.Diff{dmp.DiffDelete, "bar"},
|
||||
dmp.Diff{dmp.DiffInsert, " baz"},
|
||||
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])
|
||||
}
|
||||
|
||||
1216
models/issue.go
1216
models/issue.go
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,10 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"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 +55,13 @@ 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
|
||||
Updated time.Time `xorm:"-"`
|
||||
UpdatedUnix int64
|
||||
|
||||
// Reference issue in commit message
|
||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||
@@ -65,6 +72,15 @@ type Comment struct {
|
||||
ShowTag CommentTag `xorm:"-"`
|
||||
}
|
||||
|
||||
func (c *Comment) BeforeInsert() {
|
||||
c.CreatedUnix = time.Now().Unix()
|
||||
c.UpdatedUnix = c.CreatedUnix
|
||||
}
|
||||
|
||||
func (c *Comment) BeforeUpdate() {
|
||||
c.UpdatedUnix = time.Now().Unix()
|
||||
}
|
||||
|
||||
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
|
||||
var err error
|
||||
switch colName {
|
||||
@@ -79,13 +95,15 @@ func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
|
||||
if err != nil {
|
||||
if IsErrUserNotExist(err) {
|
||||
c.PosterID = -1
|
||||
c.Poster = NewFakeUser()
|
||||
c.Poster = NewGhostUser()
|
||||
} else {
|
||||
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()
|
||||
case "updated_unix":
|
||||
c.Updated = time.Unix(c.UpdatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +115,16 @@ func (c *Comment) AfterDelete() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Comment) APIFormat() *api.Comment {
|
||||
return &api.Comment{
|
||||
ID: c.ID,
|
||||
Poster: c.Poster.APIFormat(),
|
||||
Body: c.Content,
|
||||
Created: c.Created,
|
||||
Updated: c.Updated,
|
||||
}
|
||||
}
|
||||
|
||||
// HashTag returns unique hash tag for comment.
|
||||
func (c *Comment) HashTag() string {
|
||||
return "issuecomment-" + com.ToStr(c.ID)
|
||||
@@ -107,10 +135,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,9 +176,8 @@ 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]),
|
||||
RepoID: opts.Repo.ID,
|
||||
RepoUserName: opts.Repo.Owner.Name,
|
||||
@@ -151,7 +202,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 +212,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 +245,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
|
||||
@@ -294,15 +349,32 @@ func GetCommentByID(id int64) (*Comment, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrCommentNotExist{id}
|
||||
return nil, ErrCommentNotExist{id, 0}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetCommentsByIssueID returns all comments of issue by given ID.
|
||||
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
||||
func getCommentsByIssueIDSince(e Engine, issueID, since int64) ([]*Comment, error) {
|
||||
comments := make([]*Comment, 0, 10)
|
||||
return comments, x.Where("issue_id=?", issueID).Asc("created").Find(&comments)
|
||||
sess := e.Where("issue_id = ?", issueID).Asc("created_unix")
|
||||
if since > 0 {
|
||||
sess.And("updated_unix >= ?", since)
|
||||
}
|
||||
return comments, sess.Find(&comments)
|
||||
}
|
||||
|
||||
func getCommentsByIssueID(e Engine, issueID int64) ([]*Comment, error) {
|
||||
return getCommentsByIssueIDSince(e, issueID, -1)
|
||||
}
|
||||
|
||||
// GetCommentsByIssueID returns all comments of an issue.
|
||||
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
||||
return getCommentsByIssueID(x, issueID)
|
||||
}
|
||||
|
||||
// GetCommentsByIssueID returns a list of comments of an issue since a given time point.
|
||||
func GetCommentsByIssueIDSince(issueID, since int64) ([]*Comment, error) {
|
||||
return getCommentsByIssueIDSince(x, issueID, since)
|
||||
}
|
||||
|
||||
// UpdateComment updates information of comment.
|
||||
@@ -310,3 +382,32 @@ func UpdateComment(c *Comment) error {
|
||||
_, err := x.Id(c.ID).AllCols().Update(c)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCommentByID deletes the comment by given ID.
|
||||
func DeleteCommentByID(id int64) error {
|
||||
comment, err := GetCommentByID(id)
|
||||
if err != nil {
|
||||
if IsErrCommentNotExist(err) {
|
||||
return 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()
|
||||
}
|
||||
|
||||
@@ -7,12 +7,51 @@ package models
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
)
|
||||
|
||||
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
|
||||
|
||||
// GetLabelTemplateFile loads the label template file by given name,
|
||||
// then parses and returns a list of name-color pairs.
|
||||
func GetLabelTemplateFile(name string) ([][2]string, error) {
|
||||
data, err := getRepoInitFile("label", name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getRepoInitFile: %v", err)
|
||||
}
|
||||
|
||||
lines := strings.Split(string(data), "\n")
|
||||
list := make([][2]string, 0, len(lines))
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := strings.TrimSpace(lines[i])
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.SplitN(line, " ", 2)
|
||||
if len(fields) != 2 {
|
||||
return nil, fmt.Errorf("line is malformed: %s", line)
|
||||
}
|
||||
|
||||
if !labelColorPattern.MatchString(fields[0]) {
|
||||
return nil, fmt.Errorf("bad HTML color code in line: %s", line)
|
||||
}
|
||||
|
||||
fields[1] = strings.TrimSpace(fields[1])
|
||||
list = append(list, [2]string{fields[1], fields[0]})
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// Label represents a label of repository for issues.
|
||||
type Label struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
@@ -25,9 +64,17 @@ type Label struct {
|
||||
IsChecked bool `xorm:"-"`
|
||||
}
|
||||
|
||||
func (label *Label) APIFormat() *api.Label {
|
||||
return &api.Label{
|
||||
ID: label.ID,
|
||||
Name: label.Name,
|
||||
Color: label.Color,
|
||||
}
|
||||
}
|
||||
|
||||
// CalOpenIssues calculates the open issues of label.
|
||||
func (m *Label) CalOpenIssues() {
|
||||
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
||||
func (label *Label) CalOpenIssues() {
|
||||
label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
|
||||
}
|
||||
|
||||
// ForegroundColor calculates the text color for labels based
|
||||
@@ -40,7 +87,7 @@ func (l *Label) ForegroundColor() template.CSS {
|
||||
b := float32(0xFF & color)
|
||||
luminance := (0.2126*r + 0.7152*g + 0.0722*b) / 255
|
||||
|
||||
if luminance < 0.5 {
|
||||
if luminance < 0.66 {
|
||||
return template.CSS("#fff")
|
||||
}
|
||||
}
|
||||
@@ -50,54 +97,71 @@ func (l *Label) ForegroundColor() template.CSS {
|
||||
return template.CSS("#000")
|
||||
}
|
||||
|
||||
// NewLabel creates new label of repository.
|
||||
func NewLabel(l *Label) error {
|
||||
_, err := x.Insert(l)
|
||||
// NewLabels creates new label(s) for a repository.
|
||||
func NewLabels(labels ...*Label) error {
|
||||
_, err := x.Insert(labels)
|
||||
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)).Asc("name").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).Asc("name").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)).Asc("name").Find(&labels)
|
||||
}
|
||||
|
||||
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
|
||||
@@ -117,7 +181,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 +195,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 +219,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 +245,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 +262,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
81
models/issue_mail.go
Normal 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.Title, 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
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
|
||||
type LoginType int
|
||||
|
||||
// Note: new type must be added at the end of list to maintain compatibility.
|
||||
// Note: new type must append to the end of list to maintain compatibility.
|
||||
const (
|
||||
LOGIN_NOTYPE LoginType = iota
|
||||
LOGIN_PLAIN // 1
|
||||
@@ -35,11 +36,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 +43,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 +68,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
|
||||
@@ -95,14 +101,27 @@ func (cfg *PAMConfig) ToDB() ([]byte, error) {
|
||||
return json.Marshal(cfg)
|
||||
}
|
||||
|
||||
// LoginSource represents an external way for authorizing users.
|
||||
type LoginSource struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type LoginType
|
||||
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 +151,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 +180,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
|
||||
}
|
||||
@@ -185,15 +219,15 @@ func (source *LoginSource) SMTP() *SMTPConfig {
|
||||
func (source *LoginSource) PAM() *PAMConfig {
|
||||
return source.Cfg.(*PAMConfig)
|
||||
}
|
||||
func CreateLoginSource(source *LoginSource) error {
|
||||
has, err := x.Get(&LoginSource{Name: source.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
return ErrLoginSourceAlreadyExist{source.Name}
|
||||
}
|
||||
|
||||
// CountLoginSources returns number of login sources.
|
||||
func CountLoginSources() int64 {
|
||||
count, _ := x.Count(new(LoginSource))
|
||||
return count
|
||||
}
|
||||
|
||||
func CreateSource(source *LoginSource) error {
|
||||
_, err := x.Insert(source)
|
||||
_, err = x.Insert(source)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -209,7 +243,7 @@ func GetLoginSourceByID(id int64) (*LoginSource, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrAuthenticationNotExist{id}
|
||||
return nil, ErrLoginSourceNotExist{id}
|
||||
}
|
||||
return source, nil
|
||||
}
|
||||
@@ -224,12 +258,18 @@ func DeleteSource(source *LoginSource) error {
|
||||
if err != nil {
|
||||
return err
|
||||
} else if count > 0 {
|
||||
return ErrAuthenticationUserUsed
|
||||
return ErrLoginSourceInUse{source.ID}
|
||||
}
|
||||
_, err = x.Id(source.ID).Delete(new(LoginSource))
|
||||
return err
|
||||
}
|
||||
|
||||
// CountLoginSources returns number of login sources.
|
||||
func CountLoginSources() int64 {
|
||||
count, _ := x.Count(new(LoginSource))
|
||||
return count
|
||||
}
|
||||
|
||||
// .____ ________ _____ __________
|
||||
// | | \______ \ / _ \\______ \
|
||||
// | | | | \ / /_\ \| ___/
|
||||
@@ -237,55 +277,57 @@ func DeleteSource(source *LoginSource) error {
|
||||
// |_______ \/_______ /\____|__ /____|
|
||||
// \/ \/ \/
|
||||
|
||||
// LoginUserLDAPSource queries if loginName/passwd can login against the LDAP directory pool,
|
||||
func composeFullName(firstname, surname, username string) string {
|
||||
switch {
|
||||
case len(firstname) == 0 && len(surname) == 0:
|
||||
return username
|
||||
case len(firstname) == 0:
|
||||
return surname
|
||||
case len(surname) == 0:
|
||||
return firstname
|
||||
default:
|
||||
return firstname + " " + surname
|
||||
}
|
||||
}
|
||||
|
||||
// LoginViaLDAP queries if login/password is valid against the LDAP directory pool,
|
||||
// and create a local user if success when enabled.
|
||||
// It returns the same LoginUserPlain semantic.
|
||||
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)
|
||||
if !logged {
|
||||
func LoginViaLDAP(user *User, login, passowrd string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
username, fn, sn, mail, isAdmin, succeed := source.Cfg.(*LDAPConfig).SearchEntry(login, passowrd, source.Type == LOGIN_DLDAP)
|
||||
if !succeed {
|
||||
// User not in LDAP, do nothing
|
||||
return nil, ErrUserNotExist{0, loginName}
|
||||
return nil, ErrUserNotExist{0, login}
|
||||
}
|
||||
|
||||
if !autoRegister {
|
||||
return u, nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// Fallback.
|
||||
if len(name) == 0 {
|
||||
name = loginName
|
||||
if len(username) == 0 {
|
||||
username = login
|
||||
}
|
||||
if len(mail) == 0 {
|
||||
mail = fmt.Sprintf("%s@localhost", name)
|
||||
// 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)
|
||||
}
|
||||
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(name),
|
||||
Name: name,
|
||||
FullName: composeFullName(fn, sn, name),
|
||||
if len(mail) == 0 {
|
||||
mail = fmt.Sprintf("%s@localhost", username)
|
||||
}
|
||||
|
||||
user = &User{
|
||||
LowerName: strings.ToLower(username),
|
||||
Name: username,
|
||||
FullName: composeFullName(fn, sn, username),
|
||||
Email: mail,
|
||||
LoginType: source.Type,
|
||||
LoginSource: source.ID,
|
||||
LoginName: loginName,
|
||||
Email: mail,
|
||||
IsAdmin: admin,
|
||||
LoginName: login,
|
||||
IsActive: true,
|
||||
IsAdmin: isAdmin,
|
||||
}
|
||||
return u, CreateUser(u)
|
||||
}
|
||||
|
||||
func composeFullName(firstName, surename, userName string) string {
|
||||
switch {
|
||||
case len(firstName) == 0 && len(surename) == 0:
|
||||
return userName
|
||||
case len(firstName) == 0:
|
||||
return surename
|
||||
case len(surename) == 0:
|
||||
return firstName
|
||||
default:
|
||||
return firstName + " " + surename
|
||||
}
|
||||
return user, CreateUser(user)
|
||||
}
|
||||
|
||||
// _________ __________________________
|
||||
@@ -295,25 +337,21 @@ func composeFullName(firstName, surename, userName string) string {
|
||||
// /_______ /\____|__ /____| |____|
|
||||
// \/ \/
|
||||
|
||||
type loginAuth struct {
|
||||
type smtpLoginAuth struct {
|
||||
username, password string
|
||||
}
|
||||
|
||||
func LoginAuth(username, password string) smtp.Auth {
|
||||
return &loginAuth{username, password}
|
||||
func (auth *smtpLoginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||
return "LOGIN", []byte(auth.username), nil
|
||||
}
|
||||
|
||||
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||
return "LOGIN", []byte(a.username), nil
|
||||
}
|
||||
|
||||
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||
func (auth *smtpLoginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||
if more {
|
||||
switch string(fromServer) {
|
||||
case "Username:":
|
||||
return []byte(a.username), nil
|
||||
return []byte(auth.username), nil
|
||||
case "Password:":
|
||||
return []byte(a.password), nil
|
||||
return []byte(auth.password), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
@@ -359,25 +397,24 @@ func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
|
||||
return ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
// Query if name/passwd can login against the LDAP directory pool
|
||||
// Create a local user if success
|
||||
// Return the same LoginUserPlain semantic
|
||||
func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
|
||||
// LoginViaSMTP queries if login/password is valid against the SMTP,
|
||||
// and create a local user if success when enabled.
|
||||
func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
|
||||
// Verify allowed domains.
|
||||
if len(cfg.AllowedDomains) > 0 {
|
||||
idx := strings.Index(name, "@")
|
||||
idx := strings.Index(login, "@")
|
||||
if idx == -1 {
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), name[idx+1:]) {
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
return nil, ErrUserNotExist{0, login}
|
||||
} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), login[idx+1:]) {
|
||||
return nil, ErrUserNotExist{0, login}
|
||||
}
|
||||
}
|
||||
|
||||
var auth smtp.Auth
|
||||
if cfg.Auth == SMTP_PLAIN {
|
||||
auth = smtp.PlainAuth("", name, passwd, cfg.Host)
|
||||
auth = smtp.PlainAuth("", login, password, cfg.Host)
|
||||
} else if cfg.Auth == SMTP_LOGIN {
|
||||
auth = LoginAuth(name, passwd)
|
||||
auth = &smtpLoginAuth{login, password}
|
||||
} else {
|
||||
return nil, errors.New("Unsupported SMTP auth type")
|
||||
}
|
||||
@@ -388,33 +425,32 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTP
|
||||
tperr, ok := err.(*textproto.Error)
|
||||
if (ok && tperr.Code == 535) ||
|
||||
strings.Contains(err.Error(), "Username and Password not accepted") {
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
return nil, ErrUserNotExist{0, login}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !autoRegister {
|
||||
return u, nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
var loginName = name
|
||||
idx := strings.Index(name, "@")
|
||||
username := login
|
||||
idx := strings.Index(login, "@")
|
||||
if idx > -1 {
|
||||
loginName = name[:idx]
|
||||
username = login[:idx]
|
||||
}
|
||||
// fake a local user creation
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(loginName),
|
||||
Name: strings.ToLower(loginName),
|
||||
|
||||
user = &User{
|
||||
LowerName: strings.ToLower(username),
|
||||
Name: strings.ToLower(username),
|
||||
Email: login,
|
||||
Passwd: password,
|
||||
LoginType: LOGIN_SMTP,
|
||||
LoginSource: sourceID,
|
||||
LoginName: name,
|
||||
LoginName: login,
|
||||
IsActive: true,
|
||||
Passwd: passwd,
|
||||
Email: name,
|
||||
}
|
||||
err := CreateUser(u)
|
||||
return u, err
|
||||
return user, CreateUser(user)
|
||||
}
|
||||
|
||||
// __________ _____ _____
|
||||
@@ -424,101 +460,99 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTP
|
||||
// |____| \____|__ /\____|__ /
|
||||
// \/ \/
|
||||
|
||||
// Query if name/passwd can login against PAM
|
||||
// Create a local user if success
|
||||
// Return the same LoginUserPlain semantic
|
||||
func LoginUserPAMSource(u *User, name, passwd string, sourceID int64, cfg *PAMConfig, autoRegister bool) (*User, error) {
|
||||
if err := pam.PAMAuth(cfg.ServiceName, name, passwd); err != nil {
|
||||
// LoginViaPAM queries if login/password is valid against the PAM,
|
||||
// and create a local user if success when enabled.
|
||||
func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig, autoRegister bool) (*User, error) {
|
||||
if err := pam.PAMAuth(cfg.ServiceName, login, password); err != nil {
|
||||
if strings.Contains(err.Error(), "Authentication failure") {
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
return nil, ErrUserNotExist{0, login}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !autoRegister {
|
||||
return u, nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// fake a local user creation
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(name),
|
||||
Name: name,
|
||||
user = &User{
|
||||
LowerName: strings.ToLower(login),
|
||||
Name: login,
|
||||
Email: login,
|
||||
Passwd: password,
|
||||
LoginType: LOGIN_PAM,
|
||||
LoginSource: sourceID,
|
||||
LoginName: name,
|
||||
LoginName: login,
|
||||
IsActive: true,
|
||||
Passwd: passwd,
|
||||
Email: name,
|
||||
}
|
||||
return u, CreateUser(u)
|
||||
return user, CreateUser(user)
|
||||
}
|
||||
|
||||
func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
func ExternalUserLogin(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
if !source.IsActived {
|
||||
return nil, ErrLoginSourceNotActived
|
||||
}
|
||||
|
||||
switch source.Type {
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
return LoginUserLDAPSource(u, name, passwd, source, autoRegister)
|
||||
return LoginViaLDAP(user, login, password, source, autoRegister)
|
||||
case LOGIN_SMTP:
|
||||
return LoginUserSMTPSource(u, name, passwd, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
|
||||
return LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
|
||||
case LOGIN_PAM:
|
||||
return LoginUserPAMSource(u, name, passwd, source.ID, source.Cfg.(*PAMConfig), autoRegister)
|
||||
return LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister)
|
||||
}
|
||||
|
||||
return nil, ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
// UserSignIn validates user name and password.
|
||||
func UserSignIn(uname, passwd string) (*User, error) {
|
||||
var u *User
|
||||
if strings.Contains(uname, "@") {
|
||||
u = &User{Email: strings.ToLower(uname)}
|
||||
func UserSignIn(username, passowrd string) (*User, error) {
|
||||
var user *User
|
||||
if strings.Contains(username, "@") {
|
||||
user = &User{Email: strings.ToLower(username)}
|
||||
} else {
|
||||
u = &User{LowerName: strings.ToLower(uname)}
|
||||
user = &User{LowerName: strings.ToLower(username)}
|
||||
}
|
||||
|
||||
userExists, err := x.Get(u)
|
||||
hasUser, err := x.Get(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userExists {
|
||||
switch u.LoginType {
|
||||
if hasUser {
|
||||
switch user.LoginType {
|
||||
case LOGIN_NOTYPE, LOGIN_PLAIN:
|
||||
if u.ValidatePassword(passwd) {
|
||||
return u, nil
|
||||
if user.ValidatePassword(passowrd) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
return nil, ErrUserNotExist{u.Id, u.Name}
|
||||
return nil, ErrUserNotExist{user.ID, user.Name}
|
||||
|
||||
default:
|
||||
var source LoginSource
|
||||
hasSource, err := x.Id(u.LoginSource).Get(&source)
|
||||
hasSource, err := x.Id(user.LoginSource).Get(&source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !hasSource {
|
||||
return nil, ErrLoginSourceNotExist
|
||||
return nil, ErrLoginSourceNotExist{user.LoginSource}
|
||||
}
|
||||
|
||||
return ExternalUserLogin(u, u.LoginName, passwd, &source, false)
|
||||
return ExternalUserLogin(user, user.LoginName, passowrd, &source, false)
|
||||
}
|
||||
}
|
||||
|
||||
var sources []LoginSource
|
||||
sources := make([]*LoginSource, 3)
|
||||
if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
u, err := ExternalUserLogin(nil, uname, passwd, &source, true)
|
||||
authUser, err := ExternalUserLogin(nil, username, passowrd, source, true)
|
||||
if err == nil {
|
||||
return u, nil
|
||||
return authUser, nil
|
||||
}
|
||||
|
||||
log.Warn("Failed to login '%s' via '%s': %v", uname, source.Name, err)
|
||||
log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err)
|
||||
}
|
||||
|
||||
return nil, ErrUserNotExist{u.Id, u.Name}
|
||||
return nil, ErrUserNotExist{user.ID, user.Name}
|
||||
}
|
||||
183
models/mail.go
Normal file
183
models/mail.go
Normal 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.HTMLURL(),
|
||||
}
|
||||
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.HTMLURL(), issue.Repo.ComposeMetas()))
|
||||
data := composeTplData(subject, body, issue.HTMLURL())
|
||||
data["Doer"] = doer
|
||||
content, err := mailRender.HTMLString(string(tplName), data)
|
||||
if err != nil {
|
||||
log.Error(3, "HTMLString (%s): %v", tplName, err)
|
||||
}
|
||||
msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.User), 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"))
|
||||
}
|
||||
@@ -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,19 @@ 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
|
||||
// v0 -> v4: before 0.6.0 -> 0.7.33
|
||||
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
|
||||
|
||||
// v13 -> v14:v0.9.87
|
||||
NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
@@ -73,7 +80,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)
|
||||
@@ -239,7 +246,7 @@ func issueToIssueLabel(x *xorm.Engine) error {
|
||||
}
|
||||
|
||||
if err = sess.Sync2(new(IssueLabel)); err != nil {
|
||||
return fmt.Errorf("sync2: %v", err)
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
} else if _, err = sess.Insert(issueLabels); err != nil {
|
||||
return fmt.Errorf("insert issue-labels: %v", err)
|
||||
}
|
||||
@@ -453,3 +460,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
52
models/migrations/v13.go
Normal 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()
|
||||
}
|
||||
24
models/migrations/v14.go
Normal file
24
models/migrations/v14.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
func setCommentUpdatedWithCreated(x *xorm.Engine) (err error) {
|
||||
type Comment struct {
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
if err = x.Sync2(new(Comment)); err != nil {
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
} else if _, err = x.Exec("UPDATE comment SET updated_unix = created_unix"); err != nil {
|
||||
return fmt.Errorf("set update_unix: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -6,21 +6,19 @@ package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"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 +28,11 @@ type Engine interface {
|
||||
Exec(string, ...interface{}) (sql.Result, error)
|
||||
Find(interface{}, ...interface{}) error
|
||||
Get(interface{}) (bool, error)
|
||||
Id(interface{}) *xorm.Session
|
||||
In(string, ...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 +44,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{}
|
||||
@@ -75,13 +54,13 @@ var (
|
||||
}
|
||||
|
||||
EnableSQLite3 bool
|
||||
EnableTidb bool
|
||||
EnableTiDB bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
tables = append(tables,
|
||||
new(User), new(PublicKey), new(AccessToken),
|
||||
new(Repository), new(DeployKey), new(Collaboration), new(Access),
|
||||
new(Repository), new(DeployKey), new(Collaboration), new(Access), new(Upload),
|
||||
new(Watch), new(Star), new(Follow), new(Action),
|
||||
new(Issue), new(PullRequest), new(Comment), new(Attachment), new(IssueUser),
|
||||
new(Label), new(IssueLabel), new(Milestone),
|
||||
@@ -119,48 +98,65 @@ func LoadConfigs() {
|
||||
DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db")
|
||||
}
|
||||
|
||||
// parsePostgreSQLHostPort parses given input in various forms defined in
|
||||
// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
|
||||
// and returns proper host and port number.
|
||||
func parsePostgreSQLHostPort(info string) (string, string) {
|
||||
host, port := "127.0.0.1", "5432"
|
||||
if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
|
||||
idx := strings.LastIndex(info, ":")
|
||||
host = info[:idx]
|
||||
port = info[idx+1:]
|
||||
} else if len(info) > 0 {
|
||||
host = info
|
||||
}
|
||||
return host, port
|
||||
}
|
||||
|
||||
func getEngine() (*xorm.Engine, error) {
|
||||
cnnstr := ""
|
||||
connStr := ""
|
||||
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)
|
||||
connStr = 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)
|
||||
connStr = 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"
|
||||
fields := strings.Split(DbCfg.Host, ":")
|
||||
if len(fields) > 0 && len(strings.TrimSpace(fields[0])) > 0 {
|
||||
host = fields[0]
|
||||
host, port := parsePostgreSQLHostPort(DbCfg.Host)
|
||||
if host[0] == '/' { // looks like a unix socket
|
||||
connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
|
||||
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), port, DbCfg.Name, Param, DbCfg.SSLMode, host)
|
||||
} else {
|
||||
connStr = 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)
|
||||
}
|
||||
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)
|
||||
case "sqlite3":
|
||||
if !EnableSQLite3 {
|
||||
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||
return nil, errors.New("This binary version does not build support for SQLite3.")
|
||||
}
|
||||
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("Fail to create directories: %v", err)
|
||||
}
|
||||
cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
|
||||
connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
|
||||
case "tidb":
|
||||
if !EnableTidb {
|
||||
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||
if !EnableTiDB {
|
||||
return nil, errors.New("This binary version does not build support for TiDB.")
|
||||
}
|
||||
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("Fail to create directories: %v", err)
|
||||
}
|
||||
cnnstr = "goleveldb://" + DbCfg.Path
|
||||
connStr = "goleveldb://" + DbCfg.Path
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||
}
|
||||
return xorm.NewEngine(DbCfg.Type, cnnstr)
|
||||
return xorm.NewEngine(DbCfg.Type, connStr)
|
||||
}
|
||||
|
||||
func NewTestEngine(x *xorm.Engine) (err error) {
|
||||
@@ -226,7 +222,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))
|
||||
|
||||
33
models/models_test.go
Normal file
33
models/models_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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 (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_parsePostgreSQLHostPort(t *testing.T) {
|
||||
testSuites := []struct {
|
||||
input string
|
||||
host, port string
|
||||
}{
|
||||
{"127.0.0.1:1234", "127.0.0.1", "1234"},
|
||||
{"127.0.0.1", "127.0.0.1", "5432"},
|
||||
{"[::1]:1234", "[::1]", "1234"},
|
||||
{"[::1]", "[::1]", "5432"},
|
||||
{"/tmp/pg.sock:1234", "/tmp/pg.sock", "1234"},
|
||||
{"/tmp/pg.sock", "/tmp/pg.sock", "5432"},
|
||||
}
|
||||
|
||||
Convey("Parse PostgreSQL host and port", t, func() {
|
||||
for _, suite := range testSuites {
|
||||
host, port := parsePostgreSQLHostPort(suite.input)
|
||||
So(host, ShouldEqual, suite.host)
|
||||
So(port, ShouldEqual, suite.port)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -13,6 +13,6 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
EnableTidb = true
|
||||
EnableTiDB = true
|
||||
log.SetLevelByString("error")
|
||||
}
|
||||
|
||||
841
models/org.go
841
models/org.go
File diff suppressed because it is too large
Load Diff
618
models/org_team.go
Normal file
618
models/org_team.go
Normal 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)
|
||||
}
|
||||
359
models/pull.go
359
models/pull.go
@@ -20,8 +20,11 @@ import (
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/sync"
|
||||
)
|
||||
|
||||
var PullRequestQueue = sync.NewUniqueQueue(setting.Repository.PullRequestQueueLength)
|
||||
|
||||
type PullRequestType int
|
||||
|
||||
const (
|
||||
@@ -58,23 +61,89 @@ 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
|
||||
}
|
||||
|
||||
// Note: don't try to get Pull because will end up recursive querying.
|
||||
func (pr *PullRequest) BeforeUpdate() {
|
||||
pr.MergedUnix = pr.Merged.Unix()
|
||||
}
|
||||
|
||||
// Note: don't try to get Issue 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()
|
||||
}
|
||||
}
|
||||
|
||||
// Note: don't try to get Issue because will end up recursive querying.
|
||||
func (pr *PullRequest) loadAttributes(e Engine) (err error) {
|
||||
if pr.HasMerged && pr.Merger == nil {
|
||||
pr.Merger, err = getUserByID(e, pr.MergerID)
|
||||
if IsErrUserNotExist(err) {
|
||||
pr.MergerID = -1
|
||||
pr.Merger = NewGhostUser()
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("getUserByID [%d]: %v", pr.MergerID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pr *PullRequest) LoadAttributes() error {
|
||||
return pr.loadAttributes(x)
|
||||
}
|
||||
|
||||
func (pr *PullRequest) LoadIssue() (err error) {
|
||||
if pr.Issue != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pr.Issue, err = GetIssueByID(pr.IssueID)
|
||||
return err
|
||||
}
|
||||
|
||||
// This method assumes following fields have been assigned with valid values:
|
||||
// Required - Issue
|
||||
// Optional - Merger
|
||||
func (pr *PullRequest) APIFormat() *api.PullRequest {
|
||||
apiIssue := pr.Issue.APIFormat()
|
||||
apiPullRequest := &api.PullRequest{
|
||||
ID: pr.ID,
|
||||
Index: pr.Index,
|
||||
Poster: apiIssue.Poster,
|
||||
Title: apiIssue.Title,
|
||||
Body: apiIssue.Body,
|
||||
Labels: apiIssue.Labels,
|
||||
Milestone: apiIssue.Milestone,
|
||||
Assignee: apiIssue.Assignee,
|
||||
State: apiIssue.State,
|
||||
Comments: apiIssue.Comments,
|
||||
HTMLURL: pr.Issue.HTMLURL(),
|
||||
HasMerged: pr.HasMerged,
|
||||
}
|
||||
|
||||
if pr.Status != PULL_REQUEST_STATUS_CHECKING {
|
||||
mergeable := pr.Status != PULL_REQUEST_STATUS_CONFLICT
|
||||
apiPullRequest.Mergeable = &mergeable
|
||||
}
|
||||
if pr.HasMerged {
|
||||
apiPullRequest.Merged = &pr.Merged
|
||||
apiPullRequest.MergedCommitID = &pr.MergedCommitID
|
||||
apiPullRequest.MergedBy = pr.Merger.APIFormat()
|
||||
}
|
||||
|
||||
return apiPullRequest
|
||||
}
|
||||
|
||||
func (pr *PullRequest) getHeadRepo(e Engine) (err error) {
|
||||
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
|
||||
if err != nil && !IsErrRepoNotExist(err) {
|
||||
@@ -83,7 +152,7 @@ func (pr *PullRequest) getHeadRepo(e Engine) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pr *PullRequest) GetHeadRepo() (err error) {
|
||||
func (pr *PullRequest) GetHeadRepo() error {
|
||||
return pr.getHeadRepo(x)
|
||||
}
|
||||
|
||||
@@ -99,21 +168,6 @@ func (pr *PullRequest) GetBaseRepo() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pr *PullRequest) GetMerger() (err error) {
|
||||
if !pr.HasMerged || pr.Merger != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pr.Merger, err = GetUserByID(pr.MergerID)
|
||||
if IsErrUserNotExist(err) {
|
||||
pr.MergerID = -1
|
||||
pr.Merger = NewFakeUser()
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("GetUserByID: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsChecking returns true if this pull request is still checking conflict.
|
||||
func (pr *PullRequest) IsChecking() bool {
|
||||
return pr.Status == PULL_REQUEST_STATUS_CHECKING
|
||||
@@ -125,6 +179,7 @@ func (pr *PullRequest) CanAutoMerge() bool {
|
||||
}
|
||||
|
||||
// Merge merges pull request to base repository.
|
||||
// FIXME: add repoWorkingPull make sure two merges does not happen at same time.
|
||||
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
|
||||
if err = pr.GetHeadRepo(); err != nil {
|
||||
return fmt.Errorf("GetHeadRepo: %v", err)
|
||||
@@ -132,6 +187,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||
return fmt.Errorf("GetBaseRepo: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
go HookQueue.Add(pr.BaseRepo.ID)
|
||||
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
|
||||
}()
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
@@ -147,21 +207,6 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBranchCommitID: %v", err)
|
||||
}
|
||||
|
||||
if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
|
||||
return fmt.Errorf("mergePullRequestAction: %v", err)
|
||||
}
|
||||
|
||||
pr.HasMerged = true
|
||||
pr.Merged = time.Now()
|
||||
pr.MergerID = doer.Id
|
||||
if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
|
||||
return fmt.Errorf("update pull request: %v", err)
|
||||
}
|
||||
|
||||
// Clone base repo.
|
||||
tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
|
||||
@@ -217,37 +262,72 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||
return fmt.Errorf("git push: %s", stderr)
|
||||
}
|
||||
|
||||
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
||||
}
|
||||
|
||||
pr.HasMerged = true
|
||||
pr.Merged = time.Now()
|
||||
pr.MergerID = doer.ID
|
||||
if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
|
||||
return fmt.Errorf("update pull request: %v", err)
|
||||
}
|
||||
|
||||
if err = sess.Commit(); err != nil {
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
}
|
||||
|
||||
// Compose commit repository action
|
||||
if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
|
||||
log.Error(4, "MergePullRequestAction [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
// Reload pull request information.
|
||||
if err = pr.LoadAttributes(); err != nil {
|
||||
log.Error(4, "LoadAttributes: %v", err)
|
||||
return nil
|
||||
}
|
||||
if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
|
||||
Action: api.HOOK_ISSUE_CLOSED,
|
||||
Index: pr.Index,
|
||||
PullRequest: pr.APIFormat(),
|
||||
Repository: pr.Issue.Repo.APIFormat(nil),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBetween: %v", err)
|
||||
log.Error(4, "CommitsBetweenIDs: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: when squash commits, no need to append merge commit.
|
||||
// It is possible that head branch is not fully sync with base branch for merge commits,
|
||||
// so we need to get latest head commit and append merge commit manully
|
||||
// to avoid strange diff commits produced.
|
||||
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommit: %v", err)
|
||||
return nil
|
||||
}
|
||||
l.PushFront(mergeCommit)
|
||||
|
||||
p := &api.PushPayload{
|
||||
Ref: "refs/heads/" + pr.BaseBranch,
|
||||
Ref: git.BRANCH_PREFIX + pr.BaseBranch,
|
||||
Before: pr.MergeBase,
|
||||
After: pr.MergedCommitID,
|
||||
CompareUrl: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullRepoLink()),
|
||||
Repo: pr.BaseRepo.ComposePayload(),
|
||||
Pusher: &api.PayloadAuthor{
|
||||
Name: pr.HeadRepo.MustOwner().DisplayName(),
|
||||
Email: pr.HeadRepo.MustOwner().Email,
|
||||
UserName: pr.HeadRepo.MustOwner().Name,
|
||||
},
|
||||
Sender: &api.PayloadUser{
|
||||
UserName: doer.Name,
|
||||
ID: doer.Id,
|
||||
AvatarUrl: setting.AppUrl + doer.RelAvatarLink(),
|
||||
},
|
||||
CompareURL: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.HTMLURL()),
|
||||
Repo: pr.BaseRepo.APIFormat(nil),
|
||||
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
||||
Sender: doer.APIFormat(),
|
||||
}
|
||||
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks: %v", err)
|
||||
}
|
||||
go HookQueue.Add(pr.BaseRepo.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -280,22 +360,17 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
repoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID))
|
||||
|
||||
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
|
||||
|
||||
if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
|
||||
if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopy: %v", err)
|
||||
}
|
||||
|
||||
// Checkout base branch.
|
||||
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID),
|
||||
"git", "checkout", pr.BaseBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git checkout: %s", stderr)
|
||||
}
|
||||
|
||||
pr.Status = PULL_REQUEST_STATUS_CHECKING
|
||||
_, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
|
||||
"git", "apply", "--check", patchPath)
|
||||
if err != nil {
|
||||
@@ -321,26 +396,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
return err
|
||||
}
|
||||
|
||||
if err = newIssue(sess, repo, pull, labelIDs, uuids, true); err != nil {
|
||||
if err = newIssue(sess, NewIssueOptions{
|
||||
Repo: repo,
|
||||
Issue: pull,
|
||||
LableIDs: labelIDs,
|
||||
Attachments: uuids,
|
||||
IsPull: true,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("newIssue: %v", err)
|
||||
}
|
||||
|
||||
// Notify watchers.
|
||||
act := &Action{
|
||||
ActUserID: pull.Poster.Id,
|
||||
ActUserName: pull.Poster.Name,
|
||||
ActEmail: pull.Poster.Email,
|
||||
OpType: ACTION_CREATE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
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 {
|
||||
return fmt.Errorf("SavePatch: %v", err)
|
||||
@@ -350,6 +415,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
if err = pr.testPatch(); err != nil {
|
||||
return fmt.Errorf("testPatch: %v", err)
|
||||
}
|
||||
// No conflict appears after test means mergeable.
|
||||
if pr.Status == PULL_REQUEST_STATUS_CHECKING {
|
||||
pr.Status = PULL_REQUEST_STATUS_MERGEABLE
|
||||
}
|
||||
@@ -359,7 +425,39 @@ 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(&Action{
|
||||
ActUserID: pull.Poster.ID,
|
||||
ActUserName: pull.Poster.Name,
|
||||
OpType: ACTION_CREATE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %v", err)
|
||||
} else if err = pull.MailParticipants(); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
}
|
||||
|
||||
pr.Issue = pull
|
||||
pull.PullRequest = pr
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
|
||||
Action: api.HOOK_ISSUE_OPENED,
|
||||
Index: pull.Index,
|
||||
PullRequest: pr.APIFormat(),
|
||||
Repository: repo.APIFormat(nil),
|
||||
Sender: pull.Poster.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
}
|
||||
go HookQueue.Add(repo.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUnmergedPullRequest returnss a pull request that is open and has not been merged
|
||||
@@ -382,9 +480,9 @@ func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch
|
||||
// by given head information (repo and branch).
|
||||
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) {
|
||||
prs := make([]*PullRequest, 0, 2)
|
||||
return prs, x.Where("head_repo_id=? AND head_branch=? AND has_merged=? AND issue.is_closed=?",
|
||||
return prs, x.Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?",
|
||||
repoID, branch, false, false).
|
||||
Join("INNER", "issue", "issue.id=pull_request.issue_id").Find(&prs)
|
||||
Join("INNER", "issue", "issue.id = pull_request.issue_id").Find(&prs)
|
||||
}
|
||||
|
||||
// GetUnmergedPullRequestsByBaseInfo returnss all pull requests that are open and has not been merged
|
||||
@@ -396,30 +494,38 @@ func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequ
|
||||
Join("INNER", "issue", "issue.id=pull_request.issue_id").Find(&prs)
|
||||
}
|
||||
|
||||
// GetPullRequestByID returns a pull request by given ID.
|
||||
func GetPullRequestByID(id int64) (*PullRequest, error) {
|
||||
func getPullRequestByID(e Engine, id int64) (*PullRequest, error) {
|
||||
pr := new(PullRequest)
|
||||
has, err := x.Id(id).Get(pr)
|
||||
has, err := e.Id(id).Get(pr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrPullRequestNotExist{id, 0, 0, 0, "", ""}
|
||||
}
|
||||
return pr, nil
|
||||
return pr, pr.loadAttributes(e)
|
||||
}
|
||||
|
||||
// GetPullRequestByIssueID returns pull request by given issue ID.
|
||||
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
|
||||
// GetPullRequestByID returns a pull request by given ID.
|
||||
func GetPullRequestByID(id int64) (*PullRequest, error) {
|
||||
return getPullRequestByID(x, id)
|
||||
}
|
||||
|
||||
func getPullRequestByIssueID(e Engine, issueID int64) (*PullRequest, error) {
|
||||
pr := &PullRequest{
|
||||
IssueID: issueID,
|
||||
}
|
||||
has, err := x.Get(pr)
|
||||
has, err := e.Get(pr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrPullRequestNotExist{0, issueID, 0, 0, "", ""}
|
||||
}
|
||||
return pr, nil
|
||||
return pr, pr.loadAttributes(e)
|
||||
}
|
||||
|
||||
// GetPullRequestByIssueID returns pull request by given issue ID.
|
||||
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
|
||||
return getPullRequestByIssueID(x, issueID)
|
||||
}
|
||||
|
||||
// Update updates all fields of pull request.
|
||||
@@ -434,8 +540,6 @@ func (pr *PullRequest) UpdateCols(cols ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var PullRequestQueue = NewUniqueQueue(setting.Repository.PullRequestQueueLength)
|
||||
|
||||
// UpdatePatch generates and saves a new patch.
|
||||
func (pr *PullRequest) UpdatePatch() (err error) {
|
||||
if err = pr.GetHeadRepo(); err != nil {
|
||||
@@ -523,6 +627,37 @@ func (pr *PullRequest) AddToTaskQueue() {
|
||||
})
|
||||
}
|
||||
|
||||
type PullRequestList []*PullRequest
|
||||
|
||||
func (prs PullRequestList) loadAttributes(e Engine) error {
|
||||
if len(prs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load issues.
|
||||
issueIDs := make([]int64, 0, len(prs))
|
||||
for i := range prs {
|
||||
issueIDs = append(issueIDs, prs[i].IssueID)
|
||||
}
|
||||
issues := make([]*Issue, 0, len(issueIDs))
|
||||
if err := e.Where("id > 0").In("id", issueIDs).Find(&issues); err != nil {
|
||||
return fmt.Errorf("find issues: %v", err)
|
||||
}
|
||||
|
||||
set := make(map[int64]*Issue)
|
||||
for i := range issues {
|
||||
set[issues[i].ID] = issues[i]
|
||||
}
|
||||
for i := range prs {
|
||||
prs[i].Issue = set[prs[i].IssueID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (prs PullRequestList) LoadAttributes() error {
|
||||
return prs.loadAttributes(x)
|
||||
}
|
||||
|
||||
func addHeadRepoTasks(prs []*PullRequest) {
|
||||
for _, pr := range prs {
|
||||
log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID)
|
||||
@@ -540,19 +675,47 @@ func addHeadRepoTasks(prs []*PullRequest) {
|
||||
|
||||
// AddTestPullRequestTask adds new test tasks by given head/base repository and head/base branch,
|
||||
// and generate new patch for testing as needed.
|
||||
func AddTestPullRequestTask(repoID int64, branch string) {
|
||||
log.Trace("AddTestPullRequestTask[head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
|
||||
func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool) {
|
||||
log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
|
||||
prs, err := GetUnmergedPullRequestsByHeadInfo(repoID, branch)
|
||||
if err != nil {
|
||||
log.Error(4, "Find pull requests[head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
|
||||
log.Error(4, "Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
|
||||
return
|
||||
}
|
||||
|
||||
if isSync {
|
||||
if err = PullRequestList(prs).LoadAttributes(); err != nil {
|
||||
log.Error(4, "PullRequestList.LoadAttributes: %v", err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for _, pr := range prs {
|
||||
pr.Issue.PullRequest = pr
|
||||
if err = pr.Issue.LoadAttributes(); err != nil {
|
||||
log.Error(4, "LoadAttributes: %v", err)
|
||||
continue
|
||||
}
|
||||
if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
|
||||
Action: api.HOOK_ISSUE_SYNCHRONIZED,
|
||||
Index: pr.Issue.Index,
|
||||
PullRequest: pr.Issue.PullRequest.APIFormat(),
|
||||
Repository: pr.Issue.Repo.APIFormat(nil),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
||||
continue
|
||||
}
|
||||
go HookQueue.Add(pr.Issue.Repo.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addHeadRepoTasks(prs)
|
||||
|
||||
log.Trace("AddTestPullRequestTask[base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
||||
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
||||
prs, err = GetUnmergedPullRequestsByBaseInfo(repoID, branch)
|
||||
if err != nil {
|
||||
log.Error(4, "Find pull requests[base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
|
||||
log.Error(4, "Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
|
||||
return
|
||||
}
|
||||
for _, pr := range prs {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
941
models/repo.go
941
models/repo.go
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
// AddCollaborator adds new collaboration to a repository with default access mode.
|
||||
func (repo *Repository) AddCollaborator(u *User) error {
|
||||
collaboration := &Collaboration{
|
||||
RepoID: repo.ID,
|
||||
UserID: u.Id,
|
||||
UserID: u.ID,
|
||||
}
|
||||
|
||||
has, err := x.Get(collaboration)
|
||||
@@ -121,6 +120,9 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode
|
||||
return nil
|
||||
}
|
||||
|
||||
if collaboration.Mode == mode {
|
||||
return nil
|
||||
}
|
||||
collaboration.Mode = mode
|
||||
|
||||
sess := x.NewSession()
|
||||
|
||||
520
models/repo_editor.go
Normal file
520
models/repo_editor.go
Normal file
@@ -0,0 +1,520 @@
|
||||
// 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"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
git "github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
// ___________ .___.__ __ ___________.__.__
|
||||
// \_ _____/ __| _/|__|/ |_ \_ _____/|__| | ____
|
||||
// | __)_ / __ | | \ __\ | __) | | | _/ __ \
|
||||
// | \/ /_/ | | || | | \ | | |_\ ___/
|
||||
// /_______ /\____ | |__||__| \___ / |__|____/\___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
// discardLocalRepoBranchChanges discards local commits/changes of
|
||||
// given branch to make sure it is even to remote branch.
|
||||
func discardLocalRepoBranchChanges(localPath, branch string) error {
|
||||
if !com.IsExist(localPath) {
|
||||
return nil
|
||||
}
|
||||
// No need to check if nothing in the repository.
|
||||
if !git.IsBranchExist(localPath, branch) {
|
||||
return nil
|
||||
}
|
||||
|
||||
refName := "origin/" + branch
|
||||
if err := git.ResetHEAD(localPath, true, refName); err != nil {
|
||||
return fmt.Errorf("git reset --hard %s: %v", refName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
|
||||
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
|
||||
}
|
||||
|
||||
// checkoutNewBranch checks out to a new branch from the a branch name.
|
||||
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
|
||||
if err := git.Checkout(localPath, git.CheckoutOptions{
|
||||
Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
|
||||
Branch: newBranch,
|
||||
OldBranch: oldBranch,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("git checkout -b %s %s: %v", newBranch, oldBranch, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
|
||||
return checkoutNewBranch(repo.RepoPath(), repo.LocalCopyPath(), oldBranch, newBranch)
|
||||
}
|
||||
|
||||
type UpdateRepoFileOptions struct {
|
||||
LastCommitID string
|
||||
OldBranch string
|
||||
NewBranch string
|
||||
OldTreeName string
|
||||
NewTreeName string
|
||||
Message string
|
||||
Content string
|
||||
IsNewFile bool
|
||||
}
|
||||
|
||||
// UpdateRepoFile adds or updates a file in repository.
|
||||
func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
|
||||
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
|
||||
}
|
||||
|
||||
if opts.OldBranch != opts.NewBranch {
|
||||
if err := repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
|
||||
}
|
||||
}
|
||||
|
||||
localPath := repo.LocalCopyPath()
|
||||
oldFilePath := path.Join(localPath, opts.OldTreeName)
|
||||
filePath := path.Join(localPath, opts.NewTreeName)
|
||||
os.MkdirAll(path.Dir(filePath), os.ModePerm)
|
||||
|
||||
// If it's meant to be a new file, make sure it doesn't exist.
|
||||
if opts.IsNewFile {
|
||||
if com.IsExist(filePath) {
|
||||
return ErrRepoFileAlreadyExist{filePath}
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore move step if it's a new file under a directory.
|
||||
// Otherwise, move the file when name changed.
|
||||
if com.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
|
||||
if err = git.MoveFile(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
|
||||
return fmt.Errorf("git mv %s %s: %v", opts.OldTreeName, opts.NewTreeName, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(filePath, []byte(opts.Content), 0666); err != nil {
|
||||
return fmt.Errorf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("git add --all: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: opts.Message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository: %v", err)
|
||||
return nil
|
||||
}
|
||||
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Simulate push event.
|
||||
pushCommits := &PushCommits{
|
||||
Len: 1,
|
||||
Commits: []*PushCommit{CommitToPushCommit(commit)},
|
||||
}
|
||||
oldCommitID := opts.LastCommitID
|
||||
if opts.NewBranch != opts.OldBranch {
|
||||
oldCommitID = git.EMPTY_SHA
|
||||
}
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
OldCommitID: oldCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
}); err != nil {
|
||||
log.Error(4, "CommitRepoAction: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDiffPreview produces and returns diff result of a file which is not yet committed.
|
||||
func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *Diff, err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoBranchChanges(branch); err != nil {
|
||||
return nil, fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", branch, err)
|
||||
} else if err = repo.UpdateLocalCopyBranch(branch); err != nil {
|
||||
return nil, fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", branch, err)
|
||||
}
|
||||
|
||||
localPath := repo.LocalCopyPath()
|
||||
filePath := path.Join(localPath, treePath)
|
||||
os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
|
||||
if err = ioutil.WriteFile(filePath, []byte(content), 0666); err != nil {
|
||||
return nil, fmt.Errorf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", "diff", treePath)
|
||||
cmd.Dir = localPath
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("StdoutPipe: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("Start: %v", err)
|
||||
}
|
||||
|
||||
pid := process.Add(fmt.Sprintf("GetDiffPreview [repo_path: %s]", repo.RepoPath()), cmd)
|
||||
defer process.Remove(pid)
|
||||
|
||||
diff, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ParsePatch: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("Wait: %v", err)
|
||||
}
|
||||
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
// ________ .__ __ ___________.__.__
|
||||
// \______ \ ____ | | _____/ |_ ____ \_ _____/|__| | ____
|
||||
// | | \_/ __ \| | _/ __ \ __\/ __ \ | __) | | | _/ __ \
|
||||
// | ` \ ___/| |_\ ___/| | \ ___/ | \ | | |_\ ___/
|
||||
// /_______ /\___ >____/\___ >__| \___ > \___ / |__|____/\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
//
|
||||
|
||||
type DeleteRepoFileOptions struct {
|
||||
LastCommitID string
|
||||
OldBranch string
|
||||
NewBranch string
|
||||
TreePath string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
|
||||
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
|
||||
}
|
||||
|
||||
if opts.OldBranch != opts.NewBranch {
|
||||
if err := repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
|
||||
}
|
||||
}
|
||||
|
||||
localPath := repo.LocalCopyPath()
|
||||
if err = os.Remove(path.Join(localPath, opts.TreePath)); err != nil {
|
||||
return fmt.Errorf("Remove: %v", err)
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("git add --all: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: opts.Message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository: %v", err)
|
||||
return nil
|
||||
}
|
||||
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Simulate push event.
|
||||
pushCommits := &PushCommits{
|
||||
Len: 1,
|
||||
Commits: []*PushCommit{CommitToPushCommit(commit)},
|
||||
}
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
OldCommitID: opts.LastCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
}); err != nil {
|
||||
log.Error(4, "CommitRepoAction: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ____ ___ .__ .___ ___________.___.__
|
||||
// | | \______ | | _________ __| _/ \_ _____/| | | ____ ______
|
||||
// | | /\____ \| | / _ \__ \ / __ | | __) | | | _/ __ \ / ___/
|
||||
// | | / | |_> > |_( <_> ) __ \_/ /_/ | | \ | | |_\ ___/ \___ \
|
||||
// |______/ | __/|____/\____(____ /\____ | \___ / |___|____/\___ >____ >
|
||||
// |__| \/ \/ \/ \/ \/
|
||||
//
|
||||
|
||||
// Upload represent a uploaded file to a repo to be deleted when moved
|
||||
type Upload struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UUID string `xorm:"uuid UNIQUE"`
|
||||
Name string
|
||||
}
|
||||
|
||||
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
|
||||
func UploadLocalPath(uuid string) string {
|
||||
return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
|
||||
}
|
||||
|
||||
// LocalPath returns where uploads are temporarily stored in local file system.
|
||||
func (upload *Upload) LocalPath() string {
|
||||
return UploadLocalPath(upload.UUID)
|
||||
}
|
||||
|
||||
// NewUpload creates a new upload object.
|
||||
func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err error) {
|
||||
upload := &Upload{
|
||||
UUID: gouuid.NewV4().String(),
|
||||
Name: name,
|
||||
}
|
||||
|
||||
localPath := upload.LocalPath()
|
||||
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("MkdirAll: %v", err)
|
||||
}
|
||||
|
||||
fw, err := os.Create(localPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Create: %v", err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
if _, err = fw.Write(buf); err != nil {
|
||||
return nil, fmt.Errorf("Write: %v", err)
|
||||
} else if _, err = io.Copy(fw, file); err != nil {
|
||||
return nil, fmt.Errorf("Copy: %v", err)
|
||||
}
|
||||
|
||||
if _, err := x.Insert(upload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return upload, nil
|
||||
}
|
||||
|
||||
func GetUploadByUUID(uuid string) (*Upload, error) {
|
||||
upload := &Upload{UUID: uuid}
|
||||
has, err := x.Get(upload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrUploadNotExist{0, uuid}
|
||||
}
|
||||
return upload, nil
|
||||
}
|
||||
|
||||
func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
|
||||
if len(uuids) == 0 {
|
||||
return []*Upload{}, nil
|
||||
}
|
||||
|
||||
// Silently drop invalid uuids.
|
||||
uploads := make([]*Upload, 0, len(uuids))
|
||||
return uploads, x.In("uuid", uuids).Find(&uploads)
|
||||
}
|
||||
|
||||
func DeleteUploads(uploads ...*Upload) (err error) {
|
||||
if len(uploads) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids := make([]int64, len(uploads))
|
||||
for i := 0; i < len(uploads); i++ {
|
||||
ids[i] = uploads[i].ID
|
||||
}
|
||||
if _, err = sess.In("id", ids).Delete(new(Upload)); err != nil {
|
||||
return fmt.Errorf("delete uploads: %v", err)
|
||||
}
|
||||
|
||||
for _, upload := range uploads {
|
||||
localPath := upload.LocalPath()
|
||||
if !com.IsFile(localPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.Remove(localPath); err != nil {
|
||||
return fmt.Errorf("remove upload: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func DeleteUpload(u *Upload) error {
|
||||
return DeleteUploads(u)
|
||||
}
|
||||
|
||||
func DeleteUploadByUUID(uuid string) error {
|
||||
upload, err := GetUploadByUUID(uuid)
|
||||
if err != nil {
|
||||
if IsErrUploadNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("GetUploadByUUID: %v", err)
|
||||
}
|
||||
|
||||
if err := DeleteUpload(upload); err != nil {
|
||||
return fmt.Errorf("DeleteUpload: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type UploadRepoFileOptions struct {
|
||||
LastCommitID string
|
||||
OldBranch string
|
||||
NewBranch string
|
||||
TreePath string
|
||||
Message string
|
||||
Files []string // In UUID format.
|
||||
}
|
||||
|
||||
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) (err error) {
|
||||
if len(opts.Files) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
uploads, err := GetUploadsByUUIDs(opts.Files)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %v", opts.Files, err)
|
||||
}
|
||||
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
|
||||
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
|
||||
}
|
||||
|
||||
if opts.OldBranch != opts.NewBranch {
|
||||
if err = repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
|
||||
}
|
||||
}
|
||||
|
||||
localPath := repo.LocalCopyPath()
|
||||
dirPath := path.Join(localPath, opts.TreePath)
|
||||
os.MkdirAll(dirPath, os.ModePerm)
|
||||
|
||||
// Copy uploaded files into repository.
|
||||
for _, upload := range uploads {
|
||||
tmpPath := upload.LocalPath()
|
||||
targetPath := path.Join(dirPath, upload.Name)
|
||||
if !com.IsFile(tmpPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = com.Copy(tmpPath, targetPath); err != nil {
|
||||
return fmt.Errorf("Copy: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("git add --all: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: opts.Message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
|
||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository: %v", err)
|
||||
return nil
|
||||
}
|
||||
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Simulate push event.
|
||||
pushCommits := &PushCommits{
|
||||
Len: 1,
|
||||
Commits: []*PushCommit{CommitToPushCommit(commit)},
|
||||
}
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
OldCommitID: opts.LastCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
}); err != nil {
|
||||
log.Error(4, "CommitRepoAction: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return DeleteUploads(uploads...)
|
||||
}
|
||||
243
models/repo_mirror.go
Normal file
243
models/repo_mirror.go
Normal file
@@ -0,0 +1,243 @@
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/sync"
|
||||
)
|
||||
|
||||
var MirrorQueue = sync.NewUniqueQueue(setting.Repository.MirrorQueueLength)
|
||||
|
||||
// Mirror represents mirror information of a repository.
|
||||
type Mirror struct {
|
||||
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 {
|
||||
case "repo_id":
|
||||
m.Repo, err = GetRepositoryByID(m.RepoID)
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
// ScheduleNextUpdate calculates and sets next update time.
|
||||
func (m *Mirror) ScheduleNextUpdate() {
|
||||
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
|
||||
}
|
||||
|
||||
func (m *Mirror) readAddress() {
|
||||
if len(m.address) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := ini.Load(m.Repo.GitConfigPath())
|
||||
if err != nil {
|
||||
log.Error(4, "Load: %v", err)
|
||||
return
|
||||
}
|
||||
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
|
||||
}
|
||||
|
||||
// HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL
|
||||
// with placeholder <credentials>.
|
||||
// It will fail for any other forms of clone addresses.
|
||||
func HandleCloneUserCredentials(url string, mosaics bool) string {
|
||||
i := strings.Index(url, "@")
|
||||
if i == -1 {
|
||||
return url
|
||||
}
|
||||
start := strings.Index(url, "://")
|
||||
if start == -1 {
|
||||
return url
|
||||
}
|
||||
if mosaics {
|
||||
return url[:start+3] + "<credentials>" + url[i:]
|
||||
}
|
||||
return url[:start+3] + url[i+1:]
|
||||
}
|
||||
|
||||
// Address returns mirror address from Git repository config without credentials.
|
||||
func (m *Mirror) Address() string {
|
||||
m.readAddress()
|
||||
return HandleCloneUserCredentials(m.address, false)
|
||||
}
|
||||
|
||||
// FullAddress returns mirror address from Git repository config.
|
||||
func (m *Mirror) FullAddress() string {
|
||||
m.readAddress()
|
||||
return m.address
|
||||
}
|
||||
|
||||
// SaveAddress writes new address to Git repository config.
|
||||
func (m *Mirror) SaveAddress(addr string) error {
|
||||
configPath := m.Repo.GitConfigPath()
|
||||
cfg, err := ini.Load(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Load: %v", err)
|
||||
}
|
||||
|
||||
cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
|
||||
return cfg.SaveToIndent(configPath, "\t")
|
||||
}
|
||||
|
||||
// runSync returns true if sync finished without error.
|
||||
func (m *Mirror) runSync() bool {
|
||||
repoPath := m.Repo.RepoPath()
|
||||
wikiPath := m.Repo.WikiPath()
|
||||
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
|
||||
|
||||
gitArgs := []string{"remote", "update"}
|
||||
if m.EnablePrune {
|
||||
gitArgs = append(gitArgs, "--prune")
|
||||
}
|
||||
|
||||
if _, stderr, err := process.ExecDir(
|
||||
timeout, repoPath, fmt.Sprintf("Mirror.runSync: %s", repoPath),
|
||||
"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 {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if m.Repo.HasWiki() {
|
||||
if _, stderr, err := process.ExecDir(
|
||||
timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath),
|
||||
"git", "remote", "update", "--prune"); err != nil {
|
||||
desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr)
|
||||
log.Error(4, desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func getMirrorByRepoID(e Engine, repoID int64) (*Mirror, error) {
|
||||
m := &Mirror{RepoID: repoID}
|
||||
has, err := e.Get(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrMirrorNotExist
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetMirrorByRepoID returns mirror information of a repository.
|
||||
func GetMirrorByRepoID(repoID int64) (*Mirror, error) {
|
||||
return getMirrorByRepoID(x, repoID)
|
||||
}
|
||||
|
||||
func updateMirror(e Engine, m *Mirror) error {
|
||||
_, err := e.Id(m.ID).AllCols().Update(m)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateMirror(m *Mirror) error {
|
||||
return updateMirror(x, m)
|
||||
}
|
||||
|
||||
func DeleteMirrorByRepoID(repoID int64) error {
|
||||
_, err := x.Delete(&Mirror{RepoID: repoID})
|
||||
return err
|
||||
}
|
||||
|
||||
// MirrorUpdate checks and updates mirror repositories.
|
||||
func MirrorUpdate() {
|
||||
if taskStatusTable.IsRunning(_MIRROR_UPDATE) {
|
||||
return
|
||||
}
|
||||
taskStatusTable.Start(_MIRROR_UPDATE)
|
||||
defer taskStatusTable.Stop(_MIRROR_UPDATE)
|
||||
|
||||
log.Trace("Doing: MirrorUpdate")
|
||||
|
||||
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean interface{}) error {
|
||||
m := bean.(*Mirror)
|
||||
if m.Repo == nil {
|
||||
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
MirrorQueue.Add(m.RepoID)
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Error(4, "MirrorUpdate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// SyncMirrors checks and syncs mirrors.
|
||||
// TODO: sync more mirrors at same time.
|
||||
func SyncMirrors() {
|
||||
// Start listening on new sync requests.
|
||||
for repoID := range MirrorQueue.Queue() {
|
||||
log.Trace("SyncMirrors [repo_id: %v]", repoID)
|
||||
MirrorQueue.Remove(repoID)
|
||||
|
||||
m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
|
||||
if err != nil {
|
||||
log.Error(4, "GetMirrorByRepoID [%d]: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !m.runSync() {
|
||||
continue
|
||||
}
|
||||
|
||||
m.ScheduleNextUpdate()
|
||||
if err = UpdateMirror(m); err != nil {
|
||||
log.Error(4, "UpdateMirror [%d]: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func InitSyncMirrors() {
|
||||
go SyncMirrors()
|
||||
}
|
||||
62
models/repo_test.go
Normal file
62
models/repo_test.go
Normal 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}")
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// 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"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@@ -24,7 +29,7 @@ func Test_SSHParsePublicKey(t *testing.T) {
|
||||
"rsa-2048": {"rsa", 2048, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"},
|
||||
"ecdsa-256": {"ecdsa", 256, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"},
|
||||
"ecdsa-384": {"ecdsa", 384, "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment"},
|
||||
"ecdsa-521": {"ecdsa", 521, "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACGt3UG3EzRwNOI17QR84l6PgiAcvCE7v6aXPj/SC6UWKg4EL8vW9ZBcdYL9wzs4FZXh4MOV8jAzu3KRWNTwb4k2wFNUpGOt7l28MztFFEtH5BDDrtAJSPENPy8pvPLMfnPg5NhvWycqIBzNcHipem5wSJFN5PdpNOC2xMrPWKNqj+ZjQ== nocomment"},
|
||||
// "ecdsa-521": {"ecdsa", 521, "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACGt3UG3EzRwNOI17QR84l6PgiAcvCE7v6aXPj/SC6UWKg4EL8vW9ZBcdYL9wzs4FZXh4MOV8jAzu3KRWNTwb4k2wFNUpGOt7l28MztFFEtH5BDDrtAJSPENPy8pvPLMfnPg5NhvWycqIBzNcHipem5wSJFN5PdpNOC2xMrPWKNqj+ZjQ== nocomment"},
|
||||
}
|
||||
|
||||
Convey("Parse public keys in both native and ssh-keygen", t, func() {
|
||||
@@ -37,7 +42,13 @@ func Test_SSHParsePublicKey(t *testing.T) {
|
||||
So(lengthN, ShouldEqual, key.length)
|
||||
|
||||
keyTypeK, lengthK, errK := SSHKeyGenParsePublicKey(key.content)
|
||||
So(errK, ShouldBeNil)
|
||||
if errK != nil {
|
||||
// Some server just does not support ecdsa format.
|
||||
if strings.Contains(errK.Error(), "line 1 too long:") {
|
||||
continue
|
||||
}
|
||||
So(errK, ShouldBeNil)
|
||||
}
|
||||
So(keyTypeK, ShouldEqual, key.typeName)
|
||||
So(lengthK, ShouldEqual, key.length)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -47,6 +47,19 @@ func DeleteUpdateTaskByUUID(uuid string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// CommitToPushCommit transforms a git.Commit to PushCommit type.
|
||||
func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
||||
return &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,
|
||||
}
|
||||
}
|
||||
|
||||
func ListToPushCommits(l *list.List) *PushCommits {
|
||||
commits := make([]*PushCommit, 0)
|
||||
var actEmail string
|
||||
@@ -55,33 +68,28 @@ func ListToPushCommits(l *list.List) *PushCommits {
|
||||
if actEmail == "" {
|
||||
actEmail = commit.Committer.Email
|
||||
}
|
||||
commits = append(commits,
|
||||
&PushCommit{commit.ID.String(),
|
||||
commit.Message(),
|
||||
commit.Author.Email,
|
||||
commit.Author.Name,
|
||||
})
|
||||
commits = append(commits, CommitToPushCommit(commit))
|
||||
}
|
||||
return &PushCommits{l.Len(), commits, "", nil}
|
||||
}
|
||||
|
||||
type PushUpdateOptions struct {
|
||||
RefName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
PusherID int64
|
||||
PusherName string
|
||||
RepoUserName string
|
||||
RepoName string
|
||||
RefFullName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
}
|
||||
|
||||
// PushUpdate must be called for any push actions in order to
|
||||
// generates necessary push action history feeds.
|
||||
func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
isNewRef := strings.HasPrefix(opts.OldCommitID, "0000000")
|
||||
isDelRef := strings.HasPrefix(opts.NewCommitID, "0000000")
|
||||
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
||||
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
||||
if isNewRef && isDelRef {
|
||||
return fmt.Errorf("Old and new revisions both start with 000000")
|
||||
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA)
|
||||
}
|
||||
|
||||
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
||||
@@ -94,7 +102,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
|
||||
if isDelRef {
|
||||
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d",
|
||||
opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
||||
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -103,41 +111,30 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
repoUser, err := GetUserByName(opts.RepoUserName)
|
||||
owner, err := GetUserByName(opts.RepoUserName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByName: %v", err)
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName)
|
||||
repo, err := GetRepositoryByName(owner.ID, opts.RepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByName: %v", err)
|
||||
}
|
||||
|
||||
// Push tags.
|
||||
if strings.HasPrefix(opts.RefName, "refs/tags/") {
|
||||
tag, err := gitRepo.GetTag(git.RefEndName(opts.RefName))
|
||||
if err != nil {
|
||||
return fmt.Errorf("gitRepo.GetTag: %v", err)
|
||||
}
|
||||
|
||||
// When tagger isn't available, fall back to get committer email.
|
||||
var actEmail string
|
||||
if tag.Tagger != nil {
|
||||
actEmail = tag.Tagger.Email
|
||||
} else {
|
||||
cmt, err := tag.Commit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("tag.Commit: %v", err)
|
||||
}
|
||||
actEmail = cmt.Committer.Email
|
||||
}
|
||||
|
||||
commit := &PushCommits{}
|
||||
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 {
|
||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: opts.PusherName,
|
||||
RepoOwnerID: owner.ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: opts.RefFullName,
|
||||
OldCommitID: opts.OldCommitID,
|
||||
NewCommitID: opts.NewCommitID,
|
||||
Commits: &PushCommits{},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitRepoAction (tag): %v", err)
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
||||
@@ -159,9 +156,15 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: opts.PusherName,
|
||||
RepoOwnerID: owner.ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: opts.RefFullName,
|
||||
OldCommitID: opts.OldCommitID,
|
||||
NewCommitID: opts.NewCommitID,
|
||||
Commits: ListToPushCommits(l),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitRepoAction (branch): %v", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
448
models/user.go
448
models/user.go
@@ -12,19 +12,20 @@ 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"
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
@@ -36,8 +37,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 (
|
||||
@@ -45,14 +46,13 @@ var (
|
||||
ErrEmailNotExist = errors.New("E-mail does not exist")
|
||||
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
|
||||
ErrUserNameIllegal = errors.New("User name contains illegal characters")
|
||||
ErrLoginSourceNotExist = errors.New("Login source does not exist")
|
||||
ErrLoginSourceNotActived = errors.New("Login source is not actived")
|
||||
ErrUnsupportedLoginType = errors.New("Login source is unknown")
|
||||
)
|
||||
|
||||
// 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,36 @@ 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()
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) APIFormat() *api.User {
|
||||
return &api.User{
|
||||
ID: u.ID,
|
||||
UserName: u.Name,
|
||||
FullName: u.FullName,
|
||||
Email: u.Email,
|
||||
AvatarUrl: u.AvatarLink(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +147,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 +178,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 +194,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 +209,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 +232,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 +254,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 +262,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 +279,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 +289,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 {
|
||||
@@ -292,7 +307,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
|
||||
// NewGitSig generates and returns the signature of given user.
|
||||
func (u *User) NewGitSig() *git.Signature {
|
||||
return &git.Signature{
|
||||
Name: u.Name,
|
||||
Name: u.DisplayName(),
|
||||
Email: u.Email,
|
||||
When: time.Now(),
|
||||
}
|
||||
@@ -319,7 +334,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 +363,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 +393,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 +415,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,36 +473,57 @@ 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)
|
||||
}
|
||||
|
||||
// NewFakeUser creates and returns a fake user for someone has deleted his/her account.
|
||||
func NewFakeUser() *User {
|
||||
// NewGhostUser creates and returns a fake user for someone has deleted his/her account.
|
||||
func NewGhostUser() *User {
|
||||
return &User{
|
||||
Id: -1,
|
||||
Name: "Someone",
|
||||
LowerName: "someone",
|
||||
ID: -1,
|
||||
Name: "Ghost",
|
||||
LowerName: "ghost",
|
||||
}
|
||||
}
|
||||
|
||||
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 +551,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 +606,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 +622,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 +636,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 +652,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 +667,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 +686,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 +715,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 +723,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 +740,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 +752,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 +763,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 +804,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 +824,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 +848,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 +886,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 +923,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 +1008,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
198
models/user_mail.go
Normal 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()
|
||||
}
|
||||
@@ -10,10 +10,8 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
@@ -22,8 +20,11 @@ import (
|
||||
"github.com/gogits/gogs/modules/httplib"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/sync"
|
||||
)
|
||||
|
||||
var HookQueue = sync.NewUniqueQueue(setting.Webhook.QueueLength)
|
||||
|
||||
type HookContentType int
|
||||
|
||||
const (
|
||||
@@ -58,8 +59,9 @@ func IsValidHookContentType(name string) bool {
|
||||
}
|
||||
|
||||
type HookEvents struct {
|
||||
Create bool `json:"create"`
|
||||
Push bool `json:"push"`
|
||||
Create bool `json:"create"`
|
||||
Push bool `json:"push"`
|
||||
PullRequest bool `json:"pull_request"`
|
||||
}
|
||||
|
||||
// HookEvent represents events that will delivery hook.
|
||||
@@ -94,8 +96,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 +120,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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,14 +159,23 @@ func (w *Webhook) HasPushEvent() bool {
|
||||
(w.ChooseEvents && w.HookEvents.Push)
|
||||
}
|
||||
|
||||
// HasPullRequestEvent returns true if hook enabled pull request event.
|
||||
func (w *Webhook) HasPullRequestEvent() bool {
|
||||
return w.SendEverything ||
|
||||
(w.ChooseEvents && w.HookEvents.PullRequest)
|
||||
}
|
||||
|
||||
func (w *Webhook) EventsArray() []string {
|
||||
events := make([]string, 0, 2)
|
||||
events := make([]string, 0, 3)
|
||||
if w.HasCreateEvent() {
|
||||
events = append(events, "create")
|
||||
}
|
||||
if w.HasPushEvent() {
|
||||
events = append(events, "push")
|
||||
}
|
||||
if w.HasPullRequestEvent() {
|
||||
events = append(events, "pull_request")
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
@@ -160,28 +185,47 @@ 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.
|
||||
func GetActiveWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) {
|
||||
err = x.Where("repo_id=?", repoID).And("is_active=?", true).Find(&ws)
|
||||
return ws, err
|
||||
func GetActiveWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
|
||||
webhooks := make([]*Webhook, 0, 5)
|
||||
return webhooks, x.Find(&webhooks, &Webhook{
|
||||
RepoID: repoID,
|
||||
IsActive: true,
|
||||
})
|
||||
}
|
||||
|
||||
// GetWebhooksByRepoID returns all webhooks of repository.
|
||||
func GetWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) {
|
||||
err = x.Find(&ws, &Webhook{RepoID: repoID})
|
||||
return ws, err
|
||||
// GetWebhooksByRepoID returns all webhooks of a repository.
|
||||
func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
|
||||
webhooks := make([]*Webhook, 0, 5)
|
||||
return webhooks, x.Find(&webhooks, &Webhook{RepoID: repoID})
|
||||
}
|
||||
|
||||
// UpdateWebhook updates information of webhook.
|
||||
@@ -190,25 +234,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
|
||||
}
|
||||
@@ -262,8 +323,9 @@ func IsValidHookTaskType(name string) bool {
|
||||
type HookEventType string
|
||||
|
||||
const (
|
||||
HOOK_EVENT_CREATE HookEventType = "create"
|
||||
HOOK_EVENT_PUSH HookEventType = "push"
|
||||
HOOK_EVENT_CREATE HookEventType = "create"
|
||||
HOOK_EVENT_PUSH HookEventType = "push"
|
||||
HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
|
||||
)
|
||||
|
||||
// HookRequest represents hook task request information.
|
||||
@@ -375,17 +437,13 @@ func UpdateHookTask(t *HookTask) error {
|
||||
|
||||
// PrepareWebhooks adds new webhooks to task queue for given payload.
|
||||
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
|
||||
if err := repo.GetOwner(); err != nil {
|
||||
return fmt.Errorf("GetOwner: %v", err)
|
||||
}
|
||||
|
||||
ws, err := GetActiveWebhooksByRepoID(repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err)
|
||||
}
|
||||
|
||||
// check if repo belongs to org and append additional webhooks
|
||||
if repo.Owner.IsOrganization() {
|
||||
if repo.MustOwner().IsOrganization() {
|
||||
// get hooks for org
|
||||
orgws, err := GetActiveWebhooksByOrgID(repo.OwnerID)
|
||||
if err != nil {
|
||||
@@ -409,6 +467,10 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
if !w.HasPushEvent() {
|
||||
continue
|
||||
}
|
||||
case HOOK_EVENT_PULL_REQUEST:
|
||||
if !w.HasPullRequestEvent() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
|
||||
@@ -430,7 +492,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
URL: w.URL,
|
||||
Payloader: payloader,
|
||||
ContentType: w.ContentType,
|
||||
EventType: HOOK_EVENT_PUSH,
|
||||
EventType: event,
|
||||
IsSSL: w.IsSSL,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CreateHookTask: %v", err)
|
||||
@@ -439,64 +501,6 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// UniqueQueue represents a queue that guarantees only one instance of same ID is in the line.
|
||||
type UniqueQueue struct {
|
||||
lock sync.Mutex
|
||||
ids map[string]bool
|
||||
|
||||
queue chan string
|
||||
}
|
||||
|
||||
func (q *UniqueQueue) Queue() <-chan string {
|
||||
return q.queue
|
||||
}
|
||||
|
||||
func NewUniqueQueue(queueLength int) *UniqueQueue {
|
||||
if queueLength <= 0 {
|
||||
queueLength = 100
|
||||
}
|
||||
|
||||
return &UniqueQueue{
|
||||
ids: make(map[string]bool),
|
||||
queue: make(chan string, queueLength),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *UniqueQueue) Remove(id interface{}) {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
delete(q.ids, com.ToStr(id))
|
||||
}
|
||||
|
||||
func (q *UniqueQueue) AddFunc(id interface{}, fn func()) {
|
||||
newid := com.ToStr(id)
|
||||
|
||||
if q.Exist(id) {
|
||||
return
|
||||
}
|
||||
|
||||
q.lock.Lock()
|
||||
q.ids[newid] = true
|
||||
if fn != nil {
|
||||
fn()
|
||||
}
|
||||
q.lock.Unlock()
|
||||
q.queue <- newid
|
||||
}
|
||||
|
||||
func (q *UniqueQueue) Add(id interface{}) {
|
||||
q.AddFunc(id, nil)
|
||||
}
|
||||
|
||||
func (q *UniqueQueue) Exist(id interface{}) bool {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
|
||||
return q.ids[com.ToStr(id)]
|
||||
}
|
||||
|
||||
var HookQueue = NewUniqueQueue(setting.Webhook.QueueLength)
|
||||
|
||||
func (t *HookTask) deliver() {
|
||||
t.IsDelivered = true
|
||||
|
||||
@@ -526,7 +530,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 +538,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 +574,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.
|
||||
@@ -601,7 +597,7 @@ func DeliverHooks() {
|
||||
|
||||
// Start listening on new hook requests.
|
||||
for repoID := range HookQueue.Queue() {
|
||||
log.Trace("DeliverHooks [%v]: processing delivery hooks", repoID)
|
||||
log.Trace("DeliverHooks [repo_id: %v]", repoID)
|
||||
HookQueue.Remove(repoID)
|
||||
|
||||
tasks = make([]*HookTask, 0, 5)
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
type SlackMeta struct {
|
||||
@@ -34,6 +36,7 @@ type SlackPayload struct {
|
||||
type SlackAttachment struct {
|
||||
Fallback string `json:"fallback"`
|
||||
Color string `json:"color"`
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
@@ -49,13 +52,20 @@ func (p *SlackPayload) JSONPayload() ([]byte, error) {
|
||||
|
||||
// see: https://api.slack.com/docs/formatting
|
||||
func SlackTextFormatter(s string) string {
|
||||
// take only first line of commit
|
||||
first := strings.Split(s, "\n")[0]
|
||||
// replace & < >
|
||||
first = strings.Replace(first, "&", "&", -1)
|
||||
first = strings.Replace(first, "<", "<", -1)
|
||||
first = strings.Replace(first, ">", ">", -1)
|
||||
return first
|
||||
s = strings.Replace(s, "&", "&", -1)
|
||||
s = strings.Replace(s, "<", "<", -1)
|
||||
s = strings.Replace(s, ">", ">", -1)
|
||||
return s
|
||||
}
|
||||
|
||||
func SlackShortTextFormatter(s string) string {
|
||||
s = strings.Split(s, "\n")[0]
|
||||
// replace & < >
|
||||
s = strings.Replace(s, "&", "&", -1)
|
||||
s = strings.Replace(s, "<", "<", -1)
|
||||
s = strings.Replace(s, ">", ">", -1)
|
||||
return s
|
||||
}
|
||||
|
||||
func SlackLinkFormatter(url string, text string) string {
|
||||
@@ -66,8 +76,8 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa
|
||||
// created tag/branch
|
||||
refName := git.RefEndName(p.Ref)
|
||||
|
||||
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
|
||||
refLink := SlackLinkFormatter(p.Repo.URL+"/src/"+refName, refName)
|
||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
||||
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
|
||||
|
||||
return &SlackPayload{
|
||||
@@ -91,37 +101,83 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
|
||||
} else {
|
||||
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
|
||||
}
|
||||
if len(p.CompareUrl) > 0 {
|
||||
commitString = SlackLinkFormatter(p.CompareUrl, commitDesc)
|
||||
if len(p.CompareURL) > 0 {
|
||||
commitString = SlackLinkFormatter(p.CompareURL, commitDesc)
|
||||
} else {
|
||||
commitString = commitDesc
|
||||
}
|
||||
|
||||
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
|
||||
branchLink := SlackLinkFormatter(p.Repo.URL+"/src/"+branchName, branchName)
|
||||
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name)
|
||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
|
||||
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
|
||||
|
||||
var attachmentText string
|
||||
// for each commit, generate attachment text
|
||||
for i, commit := range p.Commits {
|
||||
attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
|
||||
attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
|
||||
// add linebreak to each commit but the last
|
||||
if i < len(p.Commits)-1 {
|
||||
attachmentText += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
slackAttachments := []SlackAttachment{{
|
||||
Color: slack.Color,
|
||||
Text: attachmentText,
|
||||
}}
|
||||
return &SlackPayload{
|
||||
Channel: slack.Channel,
|
||||
Text: text,
|
||||
Username: slack.Username,
|
||||
IconURL: slack.IconURL,
|
||||
Attachments: []SlackAttachment{{
|
||||
Color: slack.Color,
|
||||
Text: attachmentText,
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||
senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
|
||||
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
|
||||
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
|
||||
var text, title, attachmentText string
|
||||
switch p.Action {
|
||||
case api.HOOK_ISSUE_OPENED:
|
||||
text = fmt.Sprintf("[%s] Pull request submitted by %s", p.Repository.FullName, senderLink)
|
||||
title = titleLink
|
||||
attachmentText = SlackTextFormatter(p.PullRequest.Body)
|
||||
case api.HOOK_ISSUE_CLOSED:
|
||||
if p.PullRequest.HasMerged {
|
||||
text = fmt.Sprintf("[%s] Pull request merged: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
} else {
|
||||
text = fmt.Sprintf("[%s] Pull request closed: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
}
|
||||
case api.HOOK_ISSUE_REOPENED:
|
||||
text = fmt.Sprintf("[%s] Pull request re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HOOK_ISSUE_EDITED:
|
||||
text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
attachmentText = SlackTextFormatter(p.PullRequest.Body)
|
||||
case api.HOOK_ISSUE_ASSIGNED:
|
||||
text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName,
|
||||
SlackLinkFormatter(setting.AppUrl+p.PullRequest.Assignee.UserName, p.PullRequest.Assignee.UserName),
|
||||
titleLink, senderLink)
|
||||
case api.HOOK_ISSUE_UNASSIGNED:
|
||||
text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HOOK_ISSUE_LABEL_UPDATED:
|
||||
text = fmt.Sprintf("[%s] Pull request labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HOOK_ISSUE_LABEL_CLEARED:
|
||||
text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HOOK_ISSUE_SYNCHRONIZED:
|
||||
text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
}
|
||||
|
||||
return &SlackPayload{
|
||||
Channel: slack.Channel,
|
||||
Text: text,
|
||||
Username: slack.Username,
|
||||
IconURL: slack.IconURL,
|
||||
Attachments: slackAttachments,
|
||||
Channel: slack.Channel,
|
||||
Text: text,
|
||||
Username: slack.Username,
|
||||
IconURL: slack.IconURL,
|
||||
Attachments: []SlackAttachment{{
|
||||
Color: slack.Color,
|
||||
Title: title,
|
||||
Text: attachmentText,
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -138,6 +194,8 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP
|
||||
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
|
||||
case HOOK_EVENT_PUSH:
|
||||
return getSlackPushPayload(p.(*api.PushPayload), slack)
|
||||
case HOOK_EVENT_PULL_REQUEST:
|
||||
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
||||
@@ -12,67 +12,28 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/sync"
|
||||
)
|
||||
|
||||
// workingPool represents a pool of working status which makes sure
|
||||
// that only one instance of same task is performing at a time.
|
||||
// However, different type of tasks can performing at the same time.
|
||||
type workingPool struct {
|
||||
lock sync.Mutex
|
||||
pool map[string]*sync.Mutex
|
||||
count map[string]int
|
||||
}
|
||||
|
||||
// CheckIn checks in a task and waits if others are running.
|
||||
func (p *workingPool) CheckIn(name string) {
|
||||
p.lock.Lock()
|
||||
|
||||
lock, has := p.pool[name]
|
||||
if !has {
|
||||
lock = &sync.Mutex{}
|
||||
p.pool[name] = lock
|
||||
}
|
||||
p.count[name]++
|
||||
|
||||
p.lock.Unlock()
|
||||
lock.Lock()
|
||||
}
|
||||
|
||||
// CheckOut checks out a task to let other tasks run.
|
||||
func (p *workingPool) CheckOut(name string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
p.pool[name].Unlock()
|
||||
if p.count[name] == 1 {
|
||||
delete(p.pool, name)
|
||||
delete(p.count, name)
|
||||
} else {
|
||||
p.count[name]--
|
||||
}
|
||||
}
|
||||
|
||||
var wikiWorkingPool = &workingPool{
|
||||
pool: make(map[string]*sync.Mutex),
|
||||
count: make(map[string]int),
|
||||
}
|
||||
var wikiWorkingPool = sync.NewExclusivePool()
|
||||
|
||||
// ToWikiPageURL formats a string to corresponding wiki URL name.
|
||||
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.
|
||||
@@ -103,6 +64,8 @@ func (repo *Repository) InitWiki() error {
|
||||
|
||||
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
|
||||
return fmt.Errorf("InitRepository: %v", err)
|
||||
} else if err = createUpdateHook(repo.WikiPath()); err != nil {
|
||||
return fmt.Errorf("createUpdateHook: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -113,24 +76,13 @@ func (repo *Repository) LocalWikiPath() string {
|
||||
|
||||
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
|
||||
func (repo *Repository) UpdateLocalWiki() error {
|
||||
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
|
||||
// Don't pass branch name here because it fails to clone and
|
||||
// checkout to a specific branch when wiki is an empty repository.
|
||||
return UpdateLocalCopyBranch(repo.WikiPath(), repo.LocalWikiPath(), "")
|
||||
}
|
||||
|
||||
// discardLocalWikiChanges discards local commits make sure
|
||||
// it is even to remote branch when local copy exists.
|
||||
func discardLocalWikiChanges(localPath string) error {
|
||||
if !com.IsExist(localPath) {
|
||||
return nil
|
||||
}
|
||||
// No need to check if nothing in the repository.
|
||||
if !git.IsBranchExist(localPath, "master") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := git.ResetHEAD(localPath, true, "origin/master"); err != nil {
|
||||
return fmt.Errorf("ResetHEAD: %v", err)
|
||||
}
|
||||
return nil
|
||||
return discardLocalRepoBranchChanges(localPath, "master")
|
||||
}
|
||||
|
||||
// updateWikiPage adds new page to repository wiki.
|
||||
@@ -149,7 +101,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 +113,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)
|
||||
}
|
||||
@@ -170,7 +129,10 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
|
||||
}
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
@@ -198,7 +160,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)
|
||||
|
||||
@@ -206,7 +168,10 @@ func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -111,10 +113,11 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type WebhookForm struct {
|
||||
Events string
|
||||
Create bool
|
||||
Push bool
|
||||
Active bool
|
||||
Events string
|
||||
Create bool
|
||||
Push bool
|
||||
PullRequest bool
|
||||
Active bool
|
||||
}
|
||||
|
||||
func (f WebhookForm) PushOnly() bool {
|
||||
@@ -141,7 +144,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
|
||||
@@ -166,7 +169,7 @@ type CreateIssueForm struct {
|
||||
MilestoneID int64
|
||||
AssigneeID int64
|
||||
Content string
|
||||
Attachments []string
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
@@ -174,9 +177,9 @@ func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
}
|
||||
|
||||
type CreateCommentForm struct {
|
||||
Content string
|
||||
Status string `binding:"OmitEmpty;In(reopen,close)"`
|
||||
Attachments []string
|
||||
Content string
|
||||
Status string `binding:"OmitEmpty;In(reopen,close)"`
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
@@ -217,6 +220,14 @@ func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type InitializeLabelsForm struct {
|
||||
TemplateName string `binding:"Required"`
|
||||
}
|
||||
|
||||
func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
// \______ \ ____ | | ____ _____ ______ ____
|
||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
||||
@@ -266,3 +277,79 @@ type NewWikiForm struct {
|
||||
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// ___________ .___.__ __
|
||||
// \_ _____/ __| _/|__|/ |_
|
||||
// | __)_ / __ | | \ __\
|
||||
// | \/ /_/ | | || |
|
||||
// /_______ /\____ | |__||__|
|
||||
// \/ \/
|
||||
|
||||
type EditRepoFileForm struct {
|
||||
TreePath string `binding:"Required;MaxSize(500)"`
|
||||
Content string `binding:"Required"`
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
|
||||
LastCommit string
|
||||
}
|
||||
|
||||
func (f *EditRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type EditPreviewDiffForm struct {
|
||||
Content string
|
||||
}
|
||||
|
||||
func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// ____ ___ .__ .___
|
||||
// | | \______ | | _________ __| _/
|
||||
// | | /\____ \| | / _ \__ \ / __ |
|
||||
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
|
||||
// |______/ | __/|____/\____(____ /\____ |
|
||||
// |__| \/ \/
|
||||
//
|
||||
|
||||
type UploadRepoFileForm struct {
|
||||
TreePath string `binding:MaxSize(500)"`
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *UploadRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type RemoveUploadFileForm struct {
|
||||
File string `binding:"Required;MaxSize(50)"`
|
||||
}
|
||||
|
||||
func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// ________ .__ __
|
||||
// \______ \ ____ | | _____/ |_ ____
|
||||
// | | \_/ __ \| | _/ __ \ __\/ __ \
|
||||
// | ` \ ___/| |_\ ___/| | \ ___/
|
||||
// /_______ /\___ >____/\___ >__| \___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type DeleteRepoFileForm struct {
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
|
||||
}
|
||||
|
||||
func (f *DeleteRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func EncodeSha1(str string) string {
|
||||
}
|
||||
|
||||
func ShortSha(sha1 string) string {
|
||||
if len(sha1) == 40 {
|
||||
if len(sha1) > 10 {
|
||||
return sha1[:10]
|
||||
}
|
||||
return sha1
|
||||
@@ -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
|
||||
@@ -506,18 +518,18 @@ func IsLetter(ch rune) bool {
|
||||
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
|
||||
}
|
||||
|
||||
func IsTextFile(data []byte) (string, bool) {
|
||||
contentType := http.DetectContentType(data)
|
||||
if strings.Index(contentType, "text/") != -1 {
|
||||
return contentType, true
|
||||
// IsTextFile returns true if file content format is plain text or empty.
|
||||
func IsTextFile(data []byte) bool {
|
||||
if len(data) == 0 {
|
||||
return true
|
||||
}
|
||||
return contentType, false
|
||||
return strings.Index(http.DetectContentType(data), "text/") != -1
|
||||
}
|
||||
|
||||
func IsImageFile(data []byte) (string, bool) {
|
||||
contentType := http.DetectContentType(data)
|
||||
if strings.Index(contentType, "image/") != -1 {
|
||||
return contentType, true
|
||||
}
|
||||
return contentType, false
|
||||
func IsImageFile(data []byte) bool {
|
||||
return strings.Index(http.DetectContentType(data), "image/") != -1
|
||||
}
|
||||
|
||||
func IsPDFFile(data []byte) bool {
|
||||
return strings.Index(http.DetectContentType(data), "application/pdf") != -1
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
73
modules/context/api.go
Normal file
73
modules/context/api.go
Normal 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)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user