mirror of
https://github.com/gogs/gogs.git
synced 2026-02-28 17:20:59 +01:00
Compare commits
826 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
0ea0c5ec4f | ||
|
|
58f0c68151 | ||
|
|
12b5a76b0d | ||
|
|
a4452864ea | ||
|
|
d57be01485 | ||
|
|
d8738f5bfd | ||
|
|
9cf7f3e46f | ||
|
|
14aba3489e | ||
|
|
13bd16af92 | ||
|
|
922a6f13a3 | ||
|
|
9c91e27933 | ||
|
|
c2ca103d30 | ||
|
|
c18f67ac6a | ||
|
|
a5b0400be7 | ||
|
|
045f14fbd0 | ||
|
|
05d8664f15 | ||
|
|
52fdecf97b | ||
|
|
9c0f84cee8 | ||
|
|
414eb22ef9 | ||
|
|
1d3ec27cb7 | ||
|
|
a0cd59bd0e | ||
|
|
a2f13eae55 | ||
|
|
2a931937a8 | ||
|
|
dfd6f8f7ab | ||
|
|
275464e7fb | ||
|
|
e2d370f0da | ||
|
|
4cb8bf1b75 | ||
|
|
5335e671be | ||
|
|
2d2d85bba4 | ||
|
|
9df6ce48c5 | ||
|
|
4d5911dbcf | ||
|
|
d57a2b908a | ||
|
|
2f228ddf31 | ||
|
|
1ca171dbe9 | ||
|
|
f6759a731a | ||
|
|
dfbda48afc | ||
|
|
260723e2cc | ||
|
|
1cbc5b49e3 | ||
|
|
f3358f5927 | ||
|
|
f946040fa9 | ||
|
|
434614506e | ||
|
|
7f2733fa1b | ||
|
|
edb7967dc7 | ||
|
|
c9901bbba5 | ||
|
|
4d930f3598 | ||
|
|
13e71acadf | ||
|
|
37ac743da7 | ||
|
|
c47a6c1510 | ||
|
|
94f9ff1ac9 | ||
|
|
97429a25ab | ||
|
|
9e89584cb4 | ||
|
|
ea80274229 | ||
|
|
42a556a082 | ||
|
|
a71a5bfeb4 | ||
|
|
6cee434b04 | ||
|
|
9d44cd79ee | ||
|
|
548440b48f | ||
|
|
8055a0bdac | ||
|
|
83c74878df | ||
|
|
d320915ad2 | ||
|
|
8e160edbd5 | ||
|
|
c0eaae200e | ||
|
|
79ae163296 | ||
|
|
7a91d7e776 | ||
|
|
6465adfe5c | ||
|
|
db14949209 | ||
|
|
ab4bc653ab | ||
|
|
ab4eacd15f | ||
|
|
7845075bd2 | ||
|
|
129638117f | ||
|
|
4438b7793b | ||
|
|
baaf6046a1 | ||
|
|
5418c2c5e4 | ||
|
|
c27038e392 | ||
|
|
51f15880d1 | ||
|
|
d324500959 | ||
|
|
3d218861e2 | ||
|
|
e721c5cf86 | ||
|
|
e3570ae45d | ||
|
|
2f27ee2232 | ||
|
|
c65bd65254 | ||
|
|
72ce06eab8 | ||
|
|
912f7b51e9 | ||
|
|
90fab0be6b | ||
|
|
c9516c4c60 | ||
|
|
6e74dd4388 | ||
|
|
d160c7e565 | ||
|
|
8ac04a3f29 | ||
|
|
b91b35b565 | ||
|
|
ac78bae7b5 | ||
|
|
926e75d721 | ||
|
|
d5a3021a7d | ||
|
|
d8a994ef24 | ||
|
|
7140dbac95 | ||
|
|
acf094fb07 | ||
|
|
7e0baf4136 | ||
|
|
a703f7d7b4 | ||
|
|
a9981d8099 | ||
|
|
5649556a33 | ||
|
|
834d92a47b | ||
|
|
e2f95c2845 | ||
|
|
5609585ec1 | ||
|
|
b7f3d94cd0 | ||
|
|
f6c98465c7 | ||
|
|
aa12135b97 | ||
|
|
f38d5e57dd | ||
|
|
341da3cea7 | ||
|
|
7162095635 | ||
|
|
0b54035d7a | ||
|
|
dbd4697001 | ||
|
|
2408df3f35 | ||
|
|
a1b28fc33c | ||
|
|
a467184e13 | ||
|
|
658bfc2704 | ||
|
|
736a46dff9 | ||
|
|
0f1b26ed1e | ||
|
|
60896c66af | ||
|
|
eb009923f4 | ||
|
|
338af89d56 | ||
|
|
2fdf8fc938 | ||
|
|
89d6b18dad | ||
|
|
b97780ba51 | ||
|
|
ccc94dd11c | ||
|
|
d5ca913b2f | ||
|
|
dab74f21b7 | ||
|
|
9eef2e706c | ||
|
|
12403bdfb0 | ||
|
|
3af1d3c581 | ||
|
|
24829f314b | ||
|
|
779b71eda4 | ||
|
|
9cf4fe043b | ||
|
|
2765b5c7cf | ||
|
|
632c27802c | ||
|
|
dc89c51f3e | ||
|
|
bb595666ac | ||
|
|
e9b9e6eb53 | ||
|
|
58e004f7da | ||
|
|
fd92d91da3 | ||
|
|
d8631b616e | ||
|
|
aa5e837c65 | ||
|
|
4f6c3e8bb2 | ||
|
|
a1d97e8f5c | ||
|
|
daa43cfb6e | ||
|
|
9adfe453d5 | ||
|
|
29cd8ac270 | ||
|
|
d710b5e791 | ||
|
|
c47866b34a | ||
|
|
15d37b7a95 | ||
|
|
15394f613f | ||
|
|
3650bd8528 | ||
|
|
de3be370f7 | ||
|
|
364874937e | ||
|
|
10e4887b2b | ||
|
|
643acdd32d | ||
|
|
8662990746 | ||
|
|
25845ea1a5 | ||
|
|
d3ca5accfd | ||
|
|
8ab5399e83 | ||
|
|
ec478b4b06 | ||
|
|
1feecd6beb | ||
|
|
a3e8c32a30 | ||
|
|
779bb890fa | ||
|
|
1fa4fe706a | ||
|
|
f4bc9263d9 | ||
|
|
600d8edaca | ||
|
|
ce3708b3ea | ||
|
|
23bc9a2911 | ||
|
|
47adc0e8f7 | ||
|
|
5258ee3740 | ||
|
|
59745c62b4 | ||
|
|
0ad5f51059 | ||
|
|
6b3e47b103 | ||
|
|
297e772c20 | ||
|
|
8bf3032b16 | ||
|
|
e40d94bb4f | ||
|
|
7ffe845c61 | ||
|
|
af8e323248 | ||
|
|
b09ddc72d2 | ||
|
|
a881f776d0 | ||
|
|
40f9d4f920 | ||
|
|
dd7608a36e | ||
|
|
662482d366 | ||
|
|
08ff1b7d4b | ||
|
|
3808638df1 | ||
|
|
ee53204e02 | ||
|
|
f15a2f9b25 | ||
|
|
3b102a71a2 | ||
|
|
133397ee0d | ||
|
|
e2b4a24cb6 | ||
|
|
d37cf09ccd | ||
|
|
2cfe6f8c60 | ||
|
|
16270ee9a4 | ||
|
|
1dfead1eef | ||
|
|
894946c319 | ||
|
|
45db167f7a | ||
|
|
10fbb1aa2f | ||
|
|
bc0eee48d5 | ||
|
|
fa5a1cb54f | ||
|
|
e797a225b6 | ||
|
|
6d5c986d4f | ||
|
|
45659d0fd2 | ||
|
|
acfc942ad7 | ||
|
|
db150f2e42 | ||
|
|
9fe9cd8b5c | ||
|
|
f8182ac521 | ||
|
|
4e96a4a62b | ||
|
|
90e9e3c89d | ||
|
|
d4583ebd4b | ||
|
|
b024de7bf5 | ||
|
|
4a0d2edc3d | ||
|
|
8e40f86d2c | ||
|
|
2bfb8bb5fd | ||
|
|
137a49e834 | ||
|
|
a3bdede2ce | ||
|
|
ddf9fa06c7 | ||
|
|
d91004ee71 | ||
|
|
739d5aa1d3 | ||
|
|
04be8c0de5 | ||
|
|
c3ff476ed6 | ||
|
|
fb1708e1af | ||
|
|
a47baa1b7a | ||
|
|
995487e822 | ||
|
|
5e97693e0e | ||
|
|
452bc385fe | ||
|
|
71bb7f6053 | ||
|
|
0255e6a703 | ||
|
|
5a27aea8e0 | ||
|
|
0e4ae27caa | ||
|
|
1c74612b3c | ||
|
|
d3ba246693 | ||
|
|
a93af59b36 | ||
|
|
0d41827f23 | ||
|
|
32efc3ec0a | ||
|
|
d33ed36fb4 | ||
|
|
9d67528c82 | ||
|
|
66d2ba1b4e | ||
|
|
84749736a8 | ||
|
|
857b340498 | ||
|
|
3e0a27157c | ||
|
|
3abad75a1b | ||
|
|
d568019306 | ||
|
|
b3e0efc0c3 | ||
|
|
caa4ca46c0 | ||
|
|
5d192c2ebf | ||
|
|
29c3e9f428 | ||
|
|
532f9fdd99 | ||
|
|
4848620594 | ||
|
|
bead46363b | ||
|
|
57c10aae33 | ||
|
|
0e0cd9100b | ||
|
|
90780a0d90 | ||
|
|
fdad234445 | ||
|
|
bba1847a8e | ||
|
|
a9d68a6884 | ||
|
|
9cf95e4e37 | ||
|
|
8c4588c4c9 | ||
|
|
e35791b2b2 | ||
|
|
5eafe2b17e | ||
|
|
1c1246fcb9 | ||
|
|
8436d69eaf | ||
|
|
20403f75fb | ||
|
|
295de51b99 | ||
|
|
6e03f61617 | ||
|
|
055c1ea02d | ||
|
|
abc5abce30 | ||
|
|
112a7cab31 | ||
|
|
ee814bf8d6 | ||
|
|
a4a23c0268 | ||
|
|
cd89d387b6 | ||
|
|
beefc53e59 | ||
|
|
1becf01cfa | ||
|
|
9fbf54ee6b | ||
|
|
12c8953381 | ||
|
|
b7b30cd85e | ||
|
|
81e5722bcc | ||
|
|
303d091ea9 | ||
|
|
c11c3b6c11 | ||
|
|
566163ab82 | ||
|
|
e2dde6eb0a | ||
|
|
b900150b1d | ||
|
|
4deb876343 | ||
|
|
0617720c0c | ||
|
|
9b8ad01bc0 | ||
|
|
96dee1c354 | ||
|
|
674c5c37be | ||
|
|
5deb726f3f | ||
|
|
1ab8a60d73 | ||
|
|
8eb0577791 | ||
|
|
85335c5f56 | ||
|
|
93f40995b3 | ||
|
|
646e90d833 | ||
|
|
d943429672 | ||
|
|
3a9fd81f59 | ||
|
|
edc414c584 | ||
|
|
a849ac0164 | ||
|
|
b31c7fe074 | ||
|
|
2665728ee7 | ||
|
|
f65dedc3be | ||
|
|
b921161666 | ||
|
|
2cc1ee3fc0 | ||
|
|
ab0ba4bbae | ||
|
|
86f841dd71 | ||
|
|
e3075865e4 | ||
|
|
3509f1f610 | ||
|
|
7ca1821725 | ||
|
|
ee5d6fb025 | ||
|
|
1372cab35a | ||
|
|
e33ddac9bf | ||
|
|
71b9537393 | ||
|
|
b33abc6280 | ||
|
|
9032bd097b | ||
|
|
38efa72146 | ||
|
|
4ae7e64e2a | ||
|
|
863ff19e1f | ||
|
|
eb14fbf95f | ||
|
|
a3eab8185d | ||
|
|
f36c82c3b3 | ||
|
|
1105a3139f | ||
|
|
fb99d50fa1 | ||
|
|
b8d0367a6c | ||
|
|
7ef9a05588 | ||
|
|
c631a4a9b9 | ||
|
|
dccfadf7b8 | ||
|
|
d1675c2701 | ||
|
|
29b07693dd | ||
|
|
f75b5f4287 | ||
|
|
40413c5c6c | ||
|
|
a72f57374d | ||
|
|
98306a5d8a | ||
|
|
cb92af4a6c | ||
|
|
ae2c6d42fd | ||
|
|
ab89be33a9 | ||
|
|
a1a4f1103c | ||
|
|
653e1506ad | ||
|
|
41fdaabcf7 | ||
|
|
8e09e03127 | ||
|
|
688fc515f8 | ||
|
|
53a63de9dc | ||
|
|
f610bfa8a2 | ||
|
|
fc4a4d38d1 | ||
|
|
939d96813c | ||
|
|
f43cc90841 | ||
|
|
a2ef9a2b64 | ||
|
|
c199703e2a | ||
|
|
db719abff2 | ||
|
|
91bab801aa | ||
|
|
17c4400b12 | ||
|
|
efa0e7b27a | ||
|
|
cd966787f3 | ||
|
|
e2f0587ca3 | ||
|
|
9620f48ed0 | ||
|
|
4db0e1d340 | ||
|
|
8a93113192 | ||
|
|
86bce4a2ae | ||
|
|
21d7b5acaf | ||
|
|
bcf6aed452 | ||
|
|
4331d1d2a0 | ||
|
|
62edc5c59a | ||
|
|
cc8c67ff29 | ||
|
|
697b0e2aba | ||
|
|
03427fb005 | ||
|
|
7655337a1f | ||
|
|
bf11ad19ea | ||
|
|
e0f0f72a36 | ||
|
|
ca35ddd078 | ||
|
|
f4309bbb05 | ||
|
|
6dc407c7d9 | ||
|
|
81ed5c4bee | ||
|
|
73474c043b | ||
|
|
0d5dc8a064 | ||
|
|
0cb7396840 | ||
|
|
4ea75dfcbe | ||
|
|
cc22c8a1ae | ||
|
|
2481fe2f56 | ||
|
|
2087156119 | ||
|
|
3870a7a3c8 | ||
|
|
19c234db39 | ||
|
|
8fe5d887ae | ||
|
|
4e6d048ba1 | ||
|
|
0df39b33eb | ||
|
|
7392b6a755 | ||
|
|
cb8134da52 | ||
|
|
590637246b | ||
|
|
053d1424b2 | ||
|
|
4993ab1a76 | ||
|
|
a62290de52 | ||
|
|
8d58e06ad8 | ||
|
|
b8fbf6559d | ||
|
|
44637f03cc | ||
|
|
7bab3d682f | ||
|
|
34f01aab5e | ||
|
|
240fe07287 | ||
|
|
93f03707a7 | ||
|
|
85af36332b | ||
|
|
13fe733037 | ||
|
|
4c896bb620 | ||
|
|
157d868254 | ||
|
|
e16042010e | ||
|
|
227dcc3cb9 | ||
|
|
e914969e4c | ||
|
|
a49af93faf | ||
|
|
76d4af891f | ||
|
|
0721095944 | ||
|
|
c62a6b7a12 | ||
|
|
cadf03db68 | ||
|
|
5ff6eedf5e | ||
|
|
53eb37d529 | ||
|
|
3bcdb3855c | ||
|
|
f00fef0cd0 | ||
|
|
2d3ecbe5b2 | ||
|
|
09c981846b | ||
|
|
037a01c4e4 | ||
|
|
1d95844d55 | ||
|
|
1c9dd11ba7 | ||
|
|
1e7e092992 | ||
|
|
33a99d587a | ||
|
|
9cd16c5b12 | ||
|
|
6673dcb038 | ||
|
|
71142929cc | ||
|
|
d7b924f17d | ||
|
|
b117befc2b | ||
|
|
7786cb76f3 | ||
|
|
eb918c2368 | ||
|
|
8ecbf0f16d | ||
|
|
b13caa23d9 | ||
|
|
fd79fad2ec | ||
|
|
19423957b1 | ||
|
|
3362b3a44f | ||
|
|
50264200f0 | ||
|
|
7436ce6403 | ||
|
|
91789930bc | ||
|
|
ea375c0dcc | ||
|
|
7509fa2c33 | ||
|
|
acdb4d8bdd | ||
|
|
95f9c85bcc | ||
|
|
79dcd7ee6e | ||
|
|
ed001d70e4 | ||
|
|
42a8c15ad0 | ||
|
|
9a27e5ccdc | ||
|
|
71123c816d | ||
|
|
168c69273f | ||
|
|
4df378b892 | ||
|
|
351dfc95a9 | ||
|
|
837155577a | ||
|
|
7e88420bc6 | ||
|
|
5911fc3512 | ||
|
|
4108c12092 | ||
|
|
e444a67d59 | ||
|
|
0cce4439ce | ||
|
|
59c965a5ec | ||
|
|
76bdbcc969 | ||
|
|
477b4d3b50 | ||
|
|
4d31eb2c0d | ||
|
|
d0b0d24f22 | ||
|
|
5d95ffe3eb | ||
|
|
98da7241a0 | ||
|
|
bc17f2f759 | ||
|
|
40f3142264 | ||
|
|
b21160a13a | ||
|
|
5b2afd8ec8 | ||
|
|
7a3eccc709 | ||
|
|
2a8d71367d | ||
|
|
3d5d61778a | ||
|
|
ddcc8d998c | ||
|
|
99e9bbef6c | ||
|
|
0e96a46020 | ||
|
|
df5ed64cca | ||
|
|
2a0bb1fa90 | ||
|
|
c6083c335e | ||
|
|
2e9c4ddedb | ||
|
|
fa8bf0f1d7 | ||
|
|
9a2e43bff2 | ||
|
|
bd5dc626e8 | ||
|
|
626dc1f0bd | ||
|
|
1b0ef0ec0b | ||
|
|
e4a092fb5a | ||
|
|
b886fb4bf0 | ||
|
|
fa5e372f75 | ||
|
|
356f1438a6 | ||
|
|
a19aaa439d | ||
|
|
0d469f261e | ||
|
|
c3440c4dd3 | ||
|
|
718d3ae258 | ||
|
|
b8d48bdb62 | ||
|
|
15d62bba82 | ||
|
|
eb6c634475 | ||
|
|
eec06fb3df | ||
|
|
df05134494 | ||
|
|
9bd3ebe207 | ||
|
|
a576224d0e | ||
|
|
989f30eb41 | ||
|
|
06d293a84e | ||
|
|
120cd4e471 | ||
|
|
1cbd4c01fb | ||
|
|
2528c482e9 | ||
|
|
b1a53f6d8e | ||
|
|
fde9c69679 | ||
|
|
3df5dcc1dc | ||
|
|
14080dd61d | ||
|
|
da2585c11e | ||
|
|
dd8a06a397 | ||
|
|
4e0c697aaf | ||
|
|
3ffbb54337 | ||
|
|
67cfb6735b | ||
|
|
b7508b06fa | ||
|
|
2a0db47935 | ||
|
|
dce2a9e7e1 | ||
|
|
abb02889f2 | ||
|
|
e2ca53029e | ||
|
|
b5f6206a65 | ||
|
|
3de9c11ea7 | ||
|
|
ae54d878c0 | ||
|
|
89244b74c6 | ||
|
|
ca8ce793d1 | ||
|
|
978dc00305 | ||
|
|
bf26808fb3 | ||
|
|
404867f206 | ||
|
|
f0ee33267c | ||
|
|
f3eaa4c592 | ||
|
|
f41360d864 | ||
|
|
e82ee40e9e | ||
|
|
1ee7c33e93 | ||
|
|
e538ff2770 | ||
|
|
76d4b9288b | ||
|
|
05ba8622f0 | ||
|
|
4795fa01d8 | ||
|
|
942fd6be53 | ||
|
|
56dd430a10 | ||
|
|
e0bae9547a | ||
|
|
bfe6027266 | ||
|
|
4d9499c2d3 | ||
|
|
98e989d52c | ||
|
|
5742f9fe69 | ||
|
|
1802d52362 | ||
|
|
cab2911f23 | ||
|
|
81133d45a1 | ||
|
|
a51acf1751 | ||
|
|
edbb67cb3f | ||
|
|
c5e249c0be | ||
|
|
37a372f6f5 | ||
|
|
f122d0856e | ||
|
|
4a6016f5af | ||
|
|
cc8f5add6e | ||
|
|
ec2423ad7c | ||
|
|
c4bab163cb | ||
|
|
0068b8106b | ||
|
|
2580e7b57e | ||
|
|
3d3498bda1 | ||
|
|
29375059e1 | ||
|
|
85449b2f11 | ||
|
|
b83cb36049 | ||
|
|
73d9eebf01 | ||
|
|
b73241ceb1 | ||
|
|
e350d74c8a | ||
|
|
149e540322 | ||
|
|
314664892c | ||
|
|
a9a386a1e5 | ||
|
|
3eae4ecde7 | ||
|
|
ec98deeb8c | ||
|
|
61fdd8c571 | ||
|
|
4813665d0a | ||
|
|
640dce12a8 | ||
|
|
99b958db43 | ||
|
|
22b0dfbb35 | ||
|
|
4a64ae4abf | ||
|
|
926e91820a | ||
|
|
91ae2ad28b | ||
|
|
db30ea03d8 | ||
|
|
0be8b1b1a1 | ||
|
|
d45302a6ba | ||
|
|
834d38a8fb | ||
|
|
5572884c6b | ||
|
|
3460ec1039 | ||
|
|
53bf23d965 | ||
|
|
573305f3d3 | ||
|
|
7ccce4d110 | ||
|
|
9ed60d96a9 | ||
|
|
b6d2b96259 | ||
|
|
e5fe367b82 | ||
|
|
19e8ce0354 | ||
|
|
f907a5c98b | ||
|
|
da607c611d | ||
|
|
3d54f6c0a4 | ||
|
|
2093586241 | ||
|
|
117afe7620 | ||
|
|
d3a5ff7b6b | ||
|
|
dcb391d341 | ||
|
|
830d000667 | ||
|
|
5a14c3cf98 | ||
|
|
e57b2dffa4 | ||
|
|
ca96e04e5f | ||
|
|
9950f5a5bd | ||
|
|
1d7a1b6034 | ||
|
|
a59b1fcc21 | ||
|
|
c5a9be9115 | ||
|
|
f86afb04a2 | ||
|
|
5d1f5f32d0 | ||
|
|
e42fcb033d | ||
|
|
392f3ee210 | ||
|
|
c50a3503e6 | ||
|
|
aaa3f1b2b9 | ||
|
|
2b10fdc4dc | ||
|
|
2f28a0310b | ||
|
|
253513cedd | ||
|
|
eb30cbab81 | ||
|
|
144663a3cf | ||
|
|
ba92f4687e | ||
|
|
968edb3e44 | ||
|
|
3ca544912f | ||
|
|
7f9598141b | ||
|
|
56c66ee486 | ||
|
|
21ad4bf0fe | ||
|
|
0128036514 | ||
|
|
ec8d41765d | ||
|
|
ffbeda077c | ||
|
|
880849a283 | ||
|
|
b2fb7e3fd2 | ||
|
|
737da1a374 | ||
|
|
f63a468dfc | ||
|
|
efaf60ba5a | ||
|
|
e6b2a01e5d | ||
|
|
52c8f69163 | ||
|
|
b80e848d02 | ||
|
|
f12832c61e | ||
|
|
dcc740fd26 | ||
|
|
8966750fd4 | ||
|
|
3623b0927e |
@@ -1,6 +1,6 @@
|
||||
[run]
|
||||
init_cmds = [
|
||||
#["grep", "-rn", "FIXME", "."],
|
||||
["make", "build-dev", "TAGS=sqlite"],
|
||||
["./gogs", "web"]
|
||||
]
|
||||
watch_all = true
|
||||
@@ -11,9 +11,9 @@ watch_dirs = [
|
||||
"$WORKDIR/routers"
|
||||
]
|
||||
watch_exts = [".go"]
|
||||
ignore_files = [".+_test.go"]
|
||||
build_delay = 1500
|
||||
cmds = [
|
||||
["go", "install", "-race"], # sqlite redis memcache cert pam tidb
|
||||
["go", "build", "-race"],
|
||||
["make", "build-dev", "TAGS=sqlite"], # cert pam tidb
|
||||
["./gogs", "web"]
|
||||
]
|
||||
@@ -1,20 +1,19 @@
|
||||
.git
|
||||
.git/
|
||||
.git/*
|
||||
conf
|
||||
conf/
|
||||
conf/*
|
||||
.git/**
|
||||
packager
|
||||
packager/
|
||||
packager/*
|
||||
packager/**
|
||||
scripts
|
||||
scripts/
|
||||
scripts/*
|
||||
scripts/**
|
||||
.github/
|
||||
.github/**
|
||||
config.codekit
|
||||
.dockerignore
|
||||
*.yml
|
||||
*.md
|
||||
.bra.toml
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.gopmfile
|
||||
config.codekit
|
||||
LICENSE
|
||||
Dockerfile*
|
||||
vendor
|
||||
vendor/**
|
||||
gogs
|
||||
|
||||
14
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
14
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@@ -42,21 +42,11 @@ There is no standard form of making a feature request. Just try to describe the
|
||||
|
||||
### Pull Request
|
||||
|
||||
Pull requests are always welcome, but note that **ALL PULL REQUESTS MUST APPLY TO THE `develop` BRANCH**.
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
|
||||
|
||||
If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve.
|
||||
|
||||
We're trying very hard to keep Gogs lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature. We believe you do like to discuss with us first in [Gitter](https://gitter.im/gogits/gogs).
|
||||
Please read detailed information on [Wiki](https://github.com/gogits/gogs/wiki/Contributing-Code).
|
||||
|
||||
### 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.md) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
|
||||
|
||||
## Things To Notice
|
||||
|
||||
Please take a moment to check that an issue on [GitHub](https://github.com/gogits/gogs/issues) or card on [Trello](https://trello.com/b/uxAoeLUl/gogs-go-git-service) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
||||
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.
|
||||
|
||||
## Code of conduct
|
||||
|
||||
22
.github/ISSUE_TEMPLATE.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
We DO NOT take questions or config/deploy problems on GitHub, please use our forum: https://discuss.gogs.io
|
||||
|
||||
Please take a moment to search that an issue doesn't already exist.
|
||||
|
||||
For bug reports, please give the relevant info:
|
||||
|
||||
- Gogs version (or commit ref):
|
||||
- Git version:
|
||||
- Operating system:
|
||||
- Database:
|
||||
- [ ] PostgreSQL
|
||||
- [ ] MySQL
|
||||
- [ ] SQLite
|
||||
- Can you reproduce the bug at http://try.gogs.io:
|
||||
- [ ] Yes (provide example URL)
|
||||
- [ ] No
|
||||
- [ ] Not relevant
|
||||
- Log gist:
|
||||
|
||||
## Description
|
||||
|
||||
...
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Please, make sure you are targeting the `develop` branch!
|
||||
|
||||
More instructions about contributing with Gogs code can be found here:
|
||||
https://github.com/gogits/gogs/wiki/Contributing-Code
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -8,32 +8,13 @@ data/
|
||||
.idea/
|
||||
*.iml
|
||||
public/img/avatar/
|
||||
files/
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
_obj
|
||||
_test
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
_testmain.go
|
||||
*.exe
|
||||
*.exe~
|
||||
/gogs
|
||||
profile/
|
||||
__pycache__
|
||||
*.pem
|
||||
output*
|
||||
.brackets.json
|
||||
docker/fig.yml
|
||||
docker/docker/Dockerfile
|
||||
docker/docker/init_gogs.sh
|
||||
gogs.sublime-project
|
||||
gogs.sublime-workspace
|
||||
.tags*
|
||||
release
|
||||
/release
|
||||
vendor
|
||||
|
||||
71
.gopmfile
71
.gopmfile
@@ -2,45 +2,56 @@
|
||||
path = github.com/gogits/gogs
|
||||
|
||||
[deps]
|
||||
github.com/bradfitz/gomemcache = commit:72a68649ba
|
||||
github.com/codegangsta/cli = commit:0302d39
|
||||
github.com/go-macaron/binding = commit:864a5ce
|
||||
github.com/bradfitz/gomemcache = commit:fb1f79c
|
||||
github.com/codegangsta/cli = commit:1efa31f
|
||||
github.com/go-macaron/binding = commit:9440f33
|
||||
github.com/go-macaron/cache = commit:5617353
|
||||
github.com/go-macaron/captcha = commit:875ff77
|
||||
github.com/go-macaron/csrf = commit:3372b25
|
||||
github.com/go-macaron/gzip = commit:4938e9b
|
||||
github.com/go-macaron/i18n = commit:5e728b6
|
||||
github.com/go-macaron/captcha = commit:8aa5919
|
||||
github.com/go-macaron/csrf = commit:6a9a7df
|
||||
github.com/go-macaron/gzip = commit:cad1c65
|
||||
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:ab30a81
|
||||
github.com/go-sql-driver/mysql = commit:d512f20
|
||||
github.com/go-xorm/core = commit:3e10003353
|
||||
github.com/go-xorm/xorm = commit:c643188
|
||||
github.com/gogits/chardet = commit:2404f77725
|
||||
github.com/gogits/go-gogs-client = commit:7c02c95
|
||||
github.com/issue9/identicon = commit:5a61672
|
||||
github.com/klauspost/compress = commit:bbfa9dc
|
||||
github.com/klauspost/cpuid = commit:8d9fe96
|
||||
github.com/klauspost/crc32 = commit:3e5c38b
|
||||
github.com/lib/pq = commit:83c4f41
|
||||
github.com/mattn/go-sqlite3 = commit:5651a9d
|
||||
github.com/go-macaron/toolbox = commit:82b5115
|
||||
github.com/go-sql-driver/mysql = commit:3654d25
|
||||
github.com/go-xorm/core = commit:bc1b7f8
|
||||
github.com/go-xorm/xorm = commit:b8b1711
|
||||
github.com/gogits/chardet = commit:2404f77
|
||||
github.com/gogits/cron = commit:96040e4
|
||||
github.com/gogits/git-module = commit:db93fa5
|
||||
github.com/gogits/go-gogs-client = commit:ee68cd9
|
||||
github.com/issue9/identicon = commit:d36b545
|
||||
github.com/jaytaylor/html2text = commit:52d9b78
|
||||
github.com/kardianos/minwinsvc = commit:cad6b2b
|
||||
github.com/klauspost/compress = commit:14eb9c4
|
||||
github.com/klauspost/cpuid = commit:09cded8
|
||||
github.com/klauspost/crc32 = commit:19b0b33
|
||||
github.com/lib/pq = commit:ee1442b
|
||||
github.com/mattn/go-sqlite3 = commit:38ee283
|
||||
github.com/mcuadros/go-version = commit:d52711f
|
||||
github.com/microcosm-cc/bluemonday = commit:4ac6f27
|
||||
github.com/msteinert/pam = commit:6534f23b39
|
||||
github.com/nfnt/resize = commit:dc93e1b98c
|
||||
github.com/russross/blackfriday = commit:300106c
|
||||
github.com/msteinert/pam = commit:02ccfbf
|
||||
github.com/nfnt/resize = commit:4d93a29
|
||||
github.com/russross/blackfriday = commit:4e6f303
|
||||
github.com/satori/go.uuid = commit:879c588
|
||||
github.com/sergi/go-diff = commit:ec7fdbb
|
||||
github.com/shurcooL/sanitized_anchor_name = commit:10ef21a
|
||||
github.com/Unknwon/cae = commit:7f5e046
|
||||
github.com/Unknwon/com = commit:28b053d
|
||||
github.com/Unknwon/i18n = commit:7457d88830
|
||||
github.com/Unknwon/i18n = commit:39d6f27
|
||||
github.com/Unknwon/paginater = commit:7748a72
|
||||
golang.org/x/net =
|
||||
golang.org/x/text =
|
||||
golang.org/x/crypto =
|
||||
gopkg.in/gomail.v2 = commit:df6fc79
|
||||
gopkg.in/ini.v1 = commit:2e44421
|
||||
gopkg.in/macaron.v1 = commit:1c6dd87
|
||||
gopkg.in/redis.v2 = commit:e617904962
|
||||
golang.org/x/crypto = commit:77f4136
|
||||
golang.org/x/net = commit:3f122ce
|
||||
golang.org/x/sys = commit:7f918dd
|
||||
golang.org/x/text = commit:e477511
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
|
||||
gopkg.in/asn1-ber.v1 = commit:4e86f43
|
||||
gopkg.in/bufio.v1 = commit:567b2bf
|
||||
gopkg.in/gomail.v2 = commit:81ebce5
|
||||
gopkg.in/ini.v1 = commit:72ba3e6
|
||||
gopkg.in/ldap.v2 = commit:0e7db8e
|
||||
gopkg.in/macaron.v1 = commit:2133042
|
||||
gopkg.in/redis.v2 = commit:e617904
|
||||
|
||||
[res]
|
||||
include = public|scripts|templates
|
||||
|
||||
@@ -24,4 +24,4 @@ before:
|
||||
- mv packager/.godir .
|
||||
after:
|
||||
- mv bin/main gogs
|
||||
after_install: ./packager/debian/postinst
|
||||
after_install: ./packager/hooks/postinst
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
@@ -13,7 +13,9 @@ before_install:
|
||||
install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script: go build -v -tags "pam"
|
||||
script:
|
||||
- go build -v -tags "pam"
|
||||
- go test -v -cover -race ./...
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
16
Dockerfile
16
Dockerfile
@@ -1,13 +1,10 @@
|
||||
FROM alpine:3.2
|
||||
MAINTAINER roemer.jp@gmail.com
|
||||
FROM alpine:3.3
|
||||
MAINTAINER jp@roemer.im
|
||||
|
||||
# Install system utils & Gogs runtime dependencies
|
||||
ADD https://github.com/tianon/gosu/releases/download/1.6/gosu-amd64 /usr/sbin/gosu
|
||||
RUN echo "@edge http://dl-4.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories \
|
||||
&& echo "@community http://dl-4.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories \
|
||||
&& apk -U --no-progress upgrade \
|
||||
&& apk -U --no-progress add ca-certificates bash git linux-pam s6@edge curl openssh socat \
|
||||
&& chmod +x /usr/sbin/gosu
|
||||
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 tzdata
|
||||
|
||||
ENV GOGS_CUSTOM /data/gogs
|
||||
|
||||
@@ -15,6 +12,9 @@ COPY . /app/gogs/
|
||||
WORKDIR /app/gogs/
|
||||
RUN ./docker/build.sh
|
||||
|
||||
# Configure LibC Name Service
|
||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
|
||||
# Configure Docker Container
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 22 3000
|
||||
|
||||
25
Dockerfile.rpi
Normal file
25
Dockerfile.rpi
Normal file
@@ -0,0 +1,25 @@
|
||||
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.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 tzdata
|
||||
|
||||
ENV GOGS_CUSTOM /data/gogs
|
||||
|
||||
COPY . /app/gogs/
|
||||
WORKDIR /app/gogs/
|
||||
RUN ./docker/build.sh
|
||||
|
||||
# Configure LibC Name Service
|
||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
|
||||
# Configure Docker Container
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 22 3000
|
||||
ENTRYPOINT ["docker/start.sh"]
|
||||
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
|
||||
41
Makefile
41
Makefile
@@ -1,21 +1,32 @@
|
||||
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildTime=$(shell date -u '+%Y-%m-%d %I:%M:%S %Z')"
|
||||
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildGitHash=$(shell git rev-parse HEAD)"
|
||||
|
||||
DATA_FILES := $(shell find conf | sed 's/ /\\ /g')
|
||||
LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
|
||||
GENERATED := modules/bindata/bindata.go public/css/gogs.css
|
||||
|
||||
TAGS = ""
|
||||
BUILD_FLAGS = "-v"
|
||||
|
||||
RELEASE_ROOT = "release"
|
||||
RELEASE_GOGS = "release/gogs"
|
||||
NOW = $(shell date -u '+%Y%m%d%I%M%S')
|
||||
|
||||
.PHONY: build pack release bindata clean
|
||||
.PHONY: build pack release bindata clean
|
||||
|
||||
build:
|
||||
go install -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
go build -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
.IGNORE: public/css/gogs.css
|
||||
|
||||
build: $(GENERATED)
|
||||
go install $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
|
||||
govet:
|
||||
go tool vet -composites=false -methods=false -structtags=false .
|
||||
|
||||
build-dev: $(GENERATED) govet
|
||||
go install $(BUILD_FLAGS) -race -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
|
||||
pack:
|
||||
rm -rf $(RELEASE_GOGS)
|
||||
mkdir -p $(RELEASE_GOGS)
|
||||
@@ -25,11 +36,27 @@ pack:
|
||||
|
||||
release: build pack
|
||||
|
||||
bindata:
|
||||
go-bindata -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
|
||||
bindata: modules/bindata/bindata.go
|
||||
|
||||
modules/bindata/bindata.go: $(DATA_FILES)
|
||||
go-bindata -o=$@ -ignore="\\.DS_Store|README.md|TRANSLATORS" -pkg=bindata conf/...
|
||||
|
||||
less: public/css/gogs.css
|
||||
|
||||
public/css/gogs.css: $(LESS_FILES)
|
||||
lessc $< $@
|
||||
|
||||
clean:
|
||||
go clean -i ./...
|
||||
|
||||
clean-mac: clean
|
||||
find . -name ".DS_Store" -print0 | xargs -0 rm
|
||||
find . -name ".DS_Store" -print0 | xargs -0 rm
|
||||
|
||||
test:
|
||||
go test -cover -race ./...
|
||||
|
||||
fixme:
|
||||
grep -rnw "FIXME" routers models modules
|
||||
|
||||
todo:
|
||||
grep -rnw "TODO" routers models modules
|
||||
|
||||
72
README.md
72
README.md
@@ -1,39 +1,24 @@
|
||||
Gogs - Go Git Service [](https://travis-ci.org/gogits/gogs)
|
||||
Gogs - Go Git Service [](https://travis-ci.org/gogits/gogs) [](https://crowdin.com/project/gogs) [](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
=====================
|
||||
|
||||
[](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||

|
||||
|
||||

|
||||
##### Current tip version: 0.9.46 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
|
||||
|
||||
##### Current version: 0.7.19 Beta
|
||||
| Web | UI | Preview |
|
||||
|:-------------:|:-------:|:-------:|
|
||||
||||
|
||||
||||
|
||||
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="33%"><img src="http://gogs.io/img/screenshots/1.png"></td>
|
||||
<td width="33%"><img src="http://gogs.io/img/screenshots/2.png"></td>
|
||||
<td width="33%"><img src="http://gogs.io/img/screenshots/3.png"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="http://gogs.io/img/screenshots/4.png"></td>
|
||||
<td><img src="http://gogs.io/img/screenshots/5.png"></td>
|
||||
<td><img src="http://gogs.io/img/screenshots/6.png"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="http://gogs.io/img/screenshots/7.png"></td>
|
||||
<td><img src="http://gogs.io/img/screenshots/8.png"></td>
|
||||
<td><img src="http://gogs.io/img/screenshots/9.png"></td>
|
||||
</tr>
|
||||
</table>
|
||||
### Important Notes
|
||||
|
||||
### NOTICES
|
||||
|
||||
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||
- The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
|
||||
- :bangbang:<span style="color: red">You **MUST** read [CONTRIBUTING.md](CONTRIBUTING.md) before you start filing an issue or making a Pull Request, and **MUST** discuss with us on [Gitter](https://gitter.im/gogits/gogs) for UI changes, otherwise it's high possibilities that we are not going to merge it.</span>:bangbang:
|
||||
- Please [start discussion](http://forum.gogs.io/category/2/general-discussion) or [ask a question](http://forum.gogs.io/category/4/getting-help) on [the forum](http://forum.gogs.io/). GitHub issue tracker only keeps **bugs** and **feature requests**, all other topics will be closed without reason.
|
||||
- If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
|
||||
- If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
|
||||
- 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.
|
||||
1. **YOU MUST READ [Contributing Code](https://github.com/gogits/gogs/wiki/Contributing-Code) BEFORE STARTING TO WORK ON A PULL REQUEST**.
|
||||
2. Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) was reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||
3. The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
|
||||
4. If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
|
||||
5. If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
|
||||
6. If your team/company is using Gogs and would like to put your logo on [our website](http://gogs.io), contact us by any means.
|
||||
|
||||
[简体中文](README_ZH.md)
|
||||
|
||||
@@ -45,8 +30,8 @@ The goal of this project is to make the easiest, fastest, and most painless way
|
||||
|
||||
- Please see the [Documentation](http://gogs.io/docs/intro) for common usages and change log.
|
||||
- See the [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
|
||||
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs) or go down to the **Installation -> Install from binary** section!
|
||||
- Having trouble? Get help with [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html).
|
||||
- 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)!
|
||||
|
||||
## Features
|
||||
@@ -58,14 +43,13 @@ The goal of this project is to make the easiest, fastest, and most painless way
|
||||
- Account/Organization/Repository management
|
||||
- Repository/Organization webhooks (including Slack)
|
||||
- Repository Git hooks/deploy keys
|
||||
- Repository issues and pull requests
|
||||
- Repository issues, pull requests and wiki
|
||||
- Add/Remove repository collaborators
|
||||
- Gravatar and custom source
|
||||
- Mail service
|
||||
- Administration panel
|
||||
- CI integration: [Drone](https://github.com/drone/drone)
|
||||
- Supports MySQL, PostgreSQL, SQLite3 and [TiDB](https://github.com/pingcap/tidb) (experimental)
|
||||
- Multi-language support ([14 languages](https://crowdin.com/project/gogs))
|
||||
- Multi-language support ([18 languages](https://crowdin.com/project/gogs))
|
||||
|
||||
## System Requirements
|
||||
|
||||
@@ -97,10 +81,11 @@ There are 5 ways to install Gogs:
|
||||
- [阿里云上 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)
|
||||
- [Gogs on Raspberry Pi](http://blog.meinside.pe.kr/Gogs-on-Raspberry-Pi/)
|
||||
- [Cloudflare Full SSL with GOGS (Go Git Service) using NGINX](http://www.listekconsulting.com/articles/cloudflare-full-ssl-with-gogs-go-git-service-using-nginx/)
|
||||
|
||||
### Screencasts
|
||||
|
||||
- [Instalando Gogs no Ubuntu](http://blog.linuxpro.com.br/2015/08/14/instalando-gogs-no-ubuntu/) (Português)
|
||||
- [Instalando Gogs no Ubuntu](https://www.youtube.com/watch?v=4UkHAR1F7ZA) (Português)
|
||||
|
||||
### Deploy to Cloud
|
||||
|
||||
@@ -109,6 +94,19 @@ There are 5 ways to install Gogs:
|
||||
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
|
||||
- [Portal](https://portaldemo.xyz/cloud/)
|
||||
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
|
||||
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
|
||||
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
|
||||
- [DPlatform](https://github.com/j8r/DPlatform)
|
||||
|
||||
## Software and Service Support
|
||||
|
||||
- [Drone](https://github.com/drone/drone) (CI)
|
||||
- [Fabric8](http://fabric8.io/) (DevOps)
|
||||
- [Taiga](https://taiga.io/) (Project Management)
|
||||
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT)
|
||||
- [Kanboard](http://kanboard.net/plugin/gogs-webhook) (Project Management)
|
||||
- [BearyChat](https://bearychat.com/) (Team Communication)
|
||||
- [HiWork](http://www.hiwork.cc/) (Team Communication)
|
||||
|
||||
### Product Support
|
||||
|
||||
@@ -118,11 +116,11 @@ There are 5 ways to install Gogs:
|
||||
## Acknowledgments
|
||||
|
||||
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
|
||||
- Modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
|
||||
- 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 [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.
|
||||
|
||||
## Contributors
|
||||
|
||||
|
||||
24
README_ZH.md
24
README_ZH.md
@@ -11,8 +11,8 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
- 有关基本用法和变更日志,请通过 [使用手册](http://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://try.gogs.io/gogs/gogs) 。
|
||||
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
|
||||
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](http://gogs.io/docs/features/i18n.html)!
|
||||
|
||||
## 功能特性
|
||||
@@ -24,14 +24,13 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
- 支持用户、组织和仓库管理系统
|
||||
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
|
||||
- 支持仓库 Git 钩子和部署密钥
|
||||
- 支持仓库工单(Issue)和合并请求(Pull Request)
|
||||
- 支持仓库工单(Issue)、合并请求(Pull Request)以及 Wiki
|
||||
- 支持添加和删除仓库协作者
|
||||
- 支持 Gravatar 以及自定义源
|
||||
- 支持邮件服务
|
||||
- 支持后台管理面板
|
||||
- 支持 CI 集成:[Drone](https://github.com/drone/drone)
|
||||
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
|
||||
- 支持多语言本地化([14 种语言]([more](https://crowdin.com/project/gogs)))
|
||||
- 支持多语言本地化([18 种语言]([more](https://crowdin.com/project/gogs)))
|
||||
|
||||
## 系统要求
|
||||
|
||||
@@ -67,6 +66,19 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
|
||||
- [Portal](https://portaldemo.xyz/cloud/)
|
||||
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
|
||||
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
|
||||
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
|
||||
- [DPlatform](https://github.com/j8r/DPlatform)
|
||||
|
||||
## 软件及服务支持
|
||||
|
||||
- [Drone](https://github.com/drone/drone)(CI)
|
||||
- [Fabric8](http://fabric8.io/)(DevOps)
|
||||
- [Taiga](https://taiga.io/)(项目管理)
|
||||
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)(IT)
|
||||
- [Kanboard](http://kanboard.net/plugin/gogs-webhook)(项目管理)
|
||||
- [BearyChat](https://bearychat.com/)(团队交流)
|
||||
- [HiWork](http://www.hiwork.cc/)(团队交流)
|
||||
|
||||
### 产品支持
|
||||
|
||||
@@ -76,11 +88,11 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
## 特别鸣谢
|
||||
|
||||
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
|
||||
- 基于 [WeTalk](https://github.com/beego/wetalk) 修改的模块设计。
|
||||
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
||||
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
|
||||
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
|
||||
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
|
||||
- 感谢 [KeyCDN](https://www.keycdn.com/) 提供 CDN 服务赞助。
|
||||
|
||||
## 贡献成员
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -14,14 +14,15 @@ import (
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||
Action: runCert,
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Please use build tags "cert" to rebuild Gogs in order to have this ability`,
|
||||
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
|
||||
}
|
||||
|
||||
54
cmd/dump.go
54
cmd/dump.go
@@ -11,6 +11,8 @@ import (
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/Unknwon/cae/zip"
|
||||
"github.com/codegangsta/cli"
|
||||
|
||||
@@ -26,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")
|
||||
}
|
||||
@@ -38,16 +41,27 @@ func runDump(ctx *cli.Context) {
|
||||
models.LoadConfigs()
|
||||
models.SetEngine()
|
||||
|
||||
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)
|
||||
}
|
||||
log.Printf("Creating tmp work dir: %s", TmpWorkDir)
|
||||
|
||||
reposDump := path.Join(TmpWorkDir, "gogs-repo.zip")
|
||||
dbDump := path.Join(TmpWorkDir, "gogs-db.sql")
|
||||
|
||||
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
|
||||
zip.Verbose = ctx.Bool("verbose")
|
||||
defer os.Remove("gogs-repo.zip")
|
||||
if err := zip.PackTo(setting.RepoRootPath, "gogs-repo.zip", true); err != nil {
|
||||
if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
|
||||
log.Fatalf("Fail to dump local repositories: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Dumping database...")
|
||||
defer os.Remove("gogs-db.sql")
|
||||
if err := models.DumpDatabase("gogs-db.sql"); err != nil {
|
||||
if err := models.DumpDatabase(dbDump); err != nil {
|
||||
log.Fatalf("Fail to dump database: %v", err)
|
||||
}
|
||||
|
||||
@@ -59,16 +73,32 @@ func runDump(ctx *cli.Context) {
|
||||
log.Fatalf("Fail to create %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
workDir, _ := setting.WorkDir()
|
||||
z.AddFile("gogs-repo.zip", path.Join(workDir, "gogs-repo.zip"))
|
||||
z.AddFile("gogs-db.sql", path.Join(workDir, "gogs-db.sql"))
|
||||
z.AddDir("custom", path.Join(workDir, "custom"))
|
||||
z.AddDir("log", path.Join(workDir, "log"))
|
||||
if err := z.AddFile("gogs-repo.zip", reposDump); err != nil {
|
||||
log.Fatalf("Fail to include gogs-repo.zip: %v", err)
|
||||
}
|
||||
if err := z.AddFile("gogs-db.sql", dbDump); err != nil {
|
||||
log.Fatalf("Fail to include gogs-db.sql: %v", err)
|
||||
}
|
||||
customDir, err := os.Stat(setting.CustomPath)
|
||||
if err == nil && customDir.IsDir() {
|
||||
if err := z.AddDir("custom", setting.CustomPath); err != nil {
|
||||
log.Fatalf("Fail to include custom: %v", err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
|
||||
}
|
||||
if err := z.AddDir("log", setting.LogRootPath); err != nil {
|
||||
log.Fatalf("Fail to include log: %v", err)
|
||||
}
|
||||
// FIXME: SSH key file.
|
||||
if err = z.Close(); err != nil {
|
||||
os.Remove(fileName)
|
||||
log.Fatalf("Fail to save %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
log.Println("Finish dumping!")
|
||||
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
|
||||
os.RemoveAll(TmpWorkDir)
|
||||
log.Printf("Finish dumping in file %s", fileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
95
cmd/serve.go
95
cmd/serve.go
@@ -15,12 +15,13 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/codegangsta/cli"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/httplib"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -41,11 +42,6 @@ func setup(logPath string) {
|
||||
setting.NewContext()
|
||||
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
|
||||
|
||||
if setting.DisableSSH {
|
||||
println("Gogs: SSH has been disabled")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
models.LoadConfigs()
|
||||
|
||||
if setting.UseSQLite3 || setting.UseTiDB {
|
||||
@@ -65,7 +61,7 @@ func parseCmd(cmd string) (string, string) {
|
||||
}
|
||||
|
||||
var (
|
||||
COMMANDS = map[string]models.AccessMode{
|
||||
allowedCommands = map[string]models.AccessMode{
|
||||
"git-upload-pack": models.ACCESS_MODE_READ,
|
||||
"git-upload-archive": models.ACCESS_MODE_READ,
|
||||
"git-receive-pack": models.ACCESS_MODE_WRITE,
|
||||
@@ -76,6 +72,9 @@ func fail(userMessage, logMessage string, args ...interface{}) {
|
||||
fmt.Fprintln(os.Stderr, "Gogs:", userMessage)
|
||||
|
||||
if len(logMessage) > 0 {
|
||||
if !setting.ProdMode {
|
||||
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
|
||||
}
|
||||
log.GitLogger.Fatal(3, logMessage, args...)
|
||||
return
|
||||
}
|
||||
@@ -84,7 +83,7 @@ func fail(userMessage, logMessage string, args ...interface{}) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func handleUpdateTask(uuid string, user *models.User, repoUserName, repoName string) {
|
||||
func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string, isWiki bool) {
|
||||
task, err := models.GetUpdateTaskByUUID(uuid)
|
||||
if err != nil {
|
||||
if models.IsErrUpdateTaskNotExist(err) {
|
||||
@@ -92,20 +91,29 @@ func handleUpdateTask(uuid string, user *models.User, repoUserName, repoName str
|
||||
return
|
||||
}
|
||||
log.GitLogger.Fatal(2, "GetUpdateTaskByUUID: %v", err)
|
||||
}
|
||||
|
||||
if err = models.Update(task.RefName, task.OldCommitID, task.NewCommitID,
|
||||
user.Name, repoUserName, repoName, user.Id); err != nil {
|
||||
log.GitLogger.Error(2, "Update: %v", err)
|
||||
}
|
||||
|
||||
if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
|
||||
} else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
|
||||
log.GitLogger.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
|
||||
}
|
||||
|
||||
if isWiki {
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.PushUpdate(models.PushUpdateOptions{
|
||||
RefName: task.RefName,
|
||||
OldCommitID: task.OldCommitID,
|
||||
NewCommitID: task.NewCommitID,
|
||||
PusherID: user.Id,
|
||||
PusherName: user.Name,
|
||||
RepoUserName: repoUser.Name,
|
||||
RepoName: reponame,
|
||||
}); err != nil {
|
||||
log.GitLogger.Error(2, "Update: %v", err)
|
||||
}
|
||||
|
||||
// Ask for running deliver hook and test pull request tasks.
|
||||
reqURL := setting.AppUrl + repoUserName + "/" + repoName + "/tasks/trigger?branch=" +
|
||||
strings.TrimPrefix(task.RefName, "refs/heads/")
|
||||
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
|
||||
strings.TrimPrefix(task.RefName, "refs/heads/") + "&secret=" + base.EncodeMD5(repoUser.Salt)
|
||||
log.GitLogger.Trace("Trigger task: %s", reqURL)
|
||||
|
||||
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
||||
@@ -121,12 +129,18 @@ func handleUpdateTask(uuid string, user *models.User, repoUserName, repoName str
|
||||
}
|
||||
}
|
||||
|
||||
func runServ(c *cli.Context) {
|
||||
func runServ(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
setup("serv.log")
|
||||
|
||||
if setting.SSH.Disabled {
|
||||
println("Gogs: SSH has been disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(c.Args()) < 1 {
|
||||
fail("Not enough arguments", "Not enough arguments")
|
||||
}
|
||||
@@ -135,7 +149,7 @@ func runServ(c *cli.Context) {
|
||||
if len(cmd) == 0 {
|
||||
println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
|
||||
println("If this is unexpected, please log in with password and setup Gogs under another user.")
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
verb, args := parseCmd(cmd)
|
||||
@@ -144,26 +158,32 @@ func runServ(c *cli.Context) {
|
||||
if len(rr) != 2 {
|
||||
fail("Invalid repository path", "Invalid repository path: %v", args)
|
||||
}
|
||||
repoUserName := strings.ToLower(rr[0])
|
||||
repoName := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||
username := strings.ToLower(rr[0])
|
||||
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||
|
||||
repoUser, err := models.GetUserByName(repoUserName)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
fail("Repository owner does not exist", "Unregistered owner: %s", repoUserName)
|
||||
}
|
||||
fail("Internal error", "Failed to get repository owner(%s): %v", repoUserName, err)
|
||||
isWiki := false
|
||||
if strings.HasSuffix(reponame, ".wiki") {
|
||||
isWiki = true
|
||||
reponame = reponame[:len(reponame)-5]
|
||||
}
|
||||
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
|
||||
repoUser, err := models.GetUserByName(username)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
fail("Repository owner does not exist", "Unregistered owner: %s", username)
|
||||
}
|
||||
fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
|
||||
}
|
||||
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, repoName)
|
||||
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, reponame)
|
||||
}
|
||||
fail("Internal error", "Failed to get repository: %v", err)
|
||||
}
|
||||
|
||||
requestedMode, has := COMMANDS[verb]
|
||||
requestedMode, has := allowedCommands[verb]
|
||||
if !has {
|
||||
fail("Unknown git command", "Unknown git command %s", verb)
|
||||
}
|
||||
@@ -197,7 +217,7 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
// Check if this deploy key belongs to current repository.
|
||||
if !models.HasDeployKey(key.ID, repo.ID) {
|
||||
fail("Key access denied", "Key access denied: %d-%d", key.ID, repo.ID)
|
||||
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
// Update deploy key activity.
|
||||
@@ -231,9 +251,14 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
uuid := uuid.NewV4().String()
|
||||
uuid := gouuid.NewV4().String()
|
||||
os.Setenv("uuid", uuid)
|
||||
|
||||
// Special handle for Windows.
|
||||
if setting.IsWindows {
|
||||
verb = strings.Replace(verb, "-", " ", 1)
|
||||
}
|
||||
|
||||
var gitcmd *exec.Cmd
|
||||
verbs := strings.Split(verb, " ")
|
||||
if len(verbs) == 2 {
|
||||
@@ -250,7 +275,7 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
|
||||
if requestedMode == models.ACCESS_MODE_WRITE {
|
||||
handleUpdateTask(uuid, user, repoUserName, repoName)
|
||||
handleUpdateTask(uuid, user, repoUser, reponame, isWiki)
|
||||
}
|
||||
|
||||
// Update user key activity.
|
||||
@@ -265,4 +290,6 @@ func runServ(c *cli.Context) {
|
||||
fail("Internal error", "UpdatePublicKey: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
|
||||
var CmdUpdate = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "This command should only be called by SSH shell",
|
||||
Usage: "This command should only be called by Git hook",
|
||||
Description: `Update get pushed info and insert into database`,
|
||||
Action: runUpdate,
|
||||
Flags: []cli.Flag{
|
||||
@@ -24,22 +24,23 @@ var CmdUpdate = cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func runUpdate(c *cli.Context) {
|
||||
func runUpdate(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
|
||||
if cmd == "" {
|
||||
return
|
||||
}
|
||||
|
||||
setup("update.log")
|
||||
|
||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||
log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
|
||||
return nil
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
if len(args) != 3 {
|
||||
log.GitLogger.Fatal(2, "received less 3 parameters")
|
||||
} else if args[0] == "" {
|
||||
log.GitLogger.Fatal(2, "refName is empty, shouldn't use")
|
||||
log.GitLogger.Fatal(2, "Arguments received are not equal to three")
|
||||
} else if len(args[0]) == 0 {
|
||||
log.GitLogger.Fatal(2, "First argument 'refName' is empty, shouldn't use")
|
||||
}
|
||||
|
||||
task := models.UpdateTask{
|
||||
@@ -52,4 +53,6 @@ func runUpdate(c *cli.Context) {
|
||||
if err := models.AddUpdateTask(&task); err != nil {
|
||||
log.GitLogger.Fatal(2, "AddUpdateTask: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
272
cmd/web.go
272
cmd/web.go
@@ -7,7 +7,6 @@ package cmd
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
gotmpl "html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/fcgi"
|
||||
@@ -29,20 +28,19 @@ import (
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
"github.com/gogits/git-module"
|
||||
"github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/auth/apiv1"
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/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"
|
||||
"github.com/gogits/gogs/routers/admin"
|
||||
"github.com/gogits/gogs/routers/api/v1"
|
||||
apiv1 "github.com/gogits/gogs/routers/api/v1"
|
||||
"github.com/gogits/gogs/routers/dev"
|
||||
"github.com/gogits/gogs/routers/org"
|
||||
"github.com/gogits/gogs/routers/repo"
|
||||
@@ -80,19 +78,24 @@ func checkVersion() {
|
||||
|
||||
// Check dependency version.
|
||||
checkers := []VerChecker{
|
||||
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.4.4.1029"},
|
||||
{"github.com/Unknwon/macaron", macaron.Version, "0.5.4"},
|
||||
{"github.com/go-macaron/binding", binding.Version, "0.1.0"},
|
||||
{"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.3"},
|
||||
{"github.com/go-macaron/i18n", i18n.Version, "0.0.7"},
|
||||
{"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.3.4"},
|
||||
{"gopkg.in/ini.v1", ini.Version, "1.8.4"},
|
||||
{"gopkg.in/macaron.v1", macaron.Version, "1.1.4"},
|
||||
{"github.com/gogits/git-module", git.Version, "0.3.2"},
|
||||
{"github.com/gogits/go-gogs-client", gogs.Version, "0.7.4"},
|
||||
}
|
||||
for _, c := range checkers {
|
||||
if !version.Compare(c.Version(), c.Expected, ">=") {
|
||||
log.Fatal(4, "Package '%s' version is too old(%s -> %s), did you forget to update?", c.ImportPath, c.Version(), c.Expected)
|
||||
log.Fatal(4, `Dependency outdated!
|
||||
Package '%s' current version (%s) is below requirement (%s),
|
||||
please use following command to update this package and recompile Gogs:
|
||||
go get -u %[1]s`, c.ImportPath, c.Version(), c.Expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,11 +126,16 @@ func newMacaron() *macaron.Macaron {
|
||||
SkipLogging: setting.DisableRouterLog,
|
||||
},
|
||||
))
|
||||
|
||||
funcMap := template.NewFuncMap()
|
||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||
Directory: path.Join(setting.StaticRootPath, "templates"),
|
||||
Funcs: []gotmpl.FuncMap{template.Funcs},
|
||||
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 {
|
||||
@@ -143,6 +151,7 @@ func newMacaron() *macaron.Macaron {
|
||||
CustomDirectory: path.Join(setting.CustomPath, "conf/locale"),
|
||||
Langs: setting.Langs,
|
||||
Names: setting.Names,
|
||||
DefaultLang: "en-US",
|
||||
Redirect: true,
|
||||
}))
|
||||
m.Use(cache.Cacher(cache.Options{
|
||||
@@ -156,6 +165,7 @@ func newMacaron() *macaron.Macaron {
|
||||
m.Use(session.Sessioner(setting.SessionConfig))
|
||||
m.Use(csrf.Csrfer(csrf.Options{
|
||||
Secret: setting.SecretKey,
|
||||
Cookie: setting.CSRFCookieName,
|
||||
SetCookie: true,
|
||||
Header: "X-Csrf-Token",
|
||||
CookiePath: setting.AppSubUrl,
|
||||
@@ -168,11 +178,11 @@ func newMacaron() *macaron.Macaron {
|
||||
},
|
||||
},
|
||||
}))
|
||||
m.Use(middleware.Contexter())
|
||||
m.Use(context.Contexter())
|
||||
return m
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) {
|
||||
func runWeb(ctx *cli.Context) error {
|
||||
if ctx.IsSet("config") {
|
||||
setting.CustomConf = ctx.String("config")
|
||||
}
|
||||
@@ -181,80 +191,28 @@ 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})
|
||||
|
||||
bind := binding.Bind
|
||||
bindIgnErr := binding.BindIgnErr
|
||||
|
||||
// FIXME: not all routes need go through same middlewares.
|
||||
// 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 *****
|
||||
// FIXME: custom form error response.
|
||||
m.Group("/api", func() {
|
||||
m.Group("/v1", func() {
|
||||
// Miscellaneous.
|
||||
m.Post("/markdown", bindIgnErr(apiv1.MarkdownForm{}), v1.Markdown)
|
||||
m.Post("/markdown/raw", v1.MarkdownRaw)
|
||||
|
||||
// Users.
|
||||
m.Group("/users", func() {
|
||||
m.Get("/search", v1.SearchUsers)
|
||||
|
||||
m.Group("/:username", func() {
|
||||
m.Get("", v1.GetUserInfo)
|
||||
|
||||
m.Group("/tokens", func() {
|
||||
m.Combo("").Get(v1.ListAccessTokens).
|
||||
Post(bind(v1.CreateAccessTokenForm{}), v1.CreateAccessToken)
|
||||
}, middleware.ApiReqBasicAuth())
|
||||
})
|
||||
})
|
||||
|
||||
// Repositories.
|
||||
m.Combo("/user/repos", middleware.ApiReqToken()).Get(v1.ListMyRepos).
|
||||
Post(bind(api.CreateRepoOption{}), v1.CreateRepo)
|
||||
m.Post("/org/:org/repos", middleware.ApiReqToken(), bind(api.CreateRepoOption{}), v1.CreateOrgRepo)
|
||||
|
||||
m.Group("/repos", func() {
|
||||
m.Get("/search", v1.SearchRepos)
|
||||
})
|
||||
|
||||
m.Group("/repos", func() {
|
||||
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.MigrateRepo)
|
||||
m.Combo("/:username/:reponame").Get(v1.GetRepo).
|
||||
Delete(v1.DeleteRepo)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Combo("/hooks").Get(v1.ListRepoHooks).
|
||||
Post(bind(api.CreateHookOption{}), v1.CreateRepoHook)
|
||||
m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), v1.EditRepoHook)
|
||||
m.Get("/raw/*", middleware.RepoRef(), v1.GetRepoRawFile)
|
||||
m.Get("/archive/*", v1.GetRepoArchive)
|
||||
|
||||
m.Group("/keys", func() {
|
||||
m.Combo("").Get(v1.ListRepoDeployKeys).
|
||||
Post(bind(api.CreateDeployKeyOption{}), v1.CreateRepoDeployKey)
|
||||
m.Combo("/:id").Get(v1.GetRepoDeployKey).
|
||||
Delete(v1.DeleteRepoDeploykey)
|
||||
})
|
||||
}, middleware.ApiRepoAssignment())
|
||||
}, middleware.ApiReqToken())
|
||||
|
||||
m.Any("/*", func(ctx *middleware.Context) {
|
||||
ctx.Error(404)
|
||||
})
|
||||
})
|
||||
}, ignSignIn)
|
||||
// ***** END: API *****
|
||||
|
||||
// ***** START: User *****
|
||||
m.Group("/user", func() {
|
||||
m.Get("/login", user.SignIn)
|
||||
@@ -269,6 +227,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("", user.Settings)
|
||||
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
|
||||
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), user.SettingsAvatar)
|
||||
m.Post("/avatar/delete", user.SettingsDeleteAvatar)
|
||||
m.Combo("/email").Get(user.SettingsEmails).
|
||||
Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
|
||||
m.Post("/email/delete", user.DeleteEmail)
|
||||
@@ -281,7 +240,7 @@ func runWeb(ctx *cli.Context) {
|
||||
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)
|
||||
m.Post("/applications/delete", user.SettingsDeleteApplication)
|
||||
m.Route("/delete", "GET,POST", user.SettingsDelete)
|
||||
}, reqSignIn, func(ctx *middleware.Context) {
|
||||
}, reqSignIn, func(ctx *context.Context) {
|
||||
ctx.Data["PageIsUserSettings"] = true
|
||||
})
|
||||
|
||||
@@ -296,25 +255,19 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
// ***** END: User *****
|
||||
|
||||
// Gravatar service.
|
||||
avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
|
||||
os.MkdirAll("public/img/avatar/", os.ModePerm)
|
||||
m.Get("/avatar/:hash", avt.ServeHTTP)
|
||||
|
||||
adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
|
||||
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
|
||||
|
||||
// ***** START: Admin *****
|
||||
m.Group("/admin", func() {
|
||||
m.Get("", adminReq, admin.Dashboard)
|
||||
m.Get("/config", admin.Config)
|
||||
m.Post("/config/test_mail", admin.SendTestMail)
|
||||
m.Get("/monitor", admin.Monitor)
|
||||
|
||||
m.Group("/users", func() {
|
||||
m.Get("", admin.Users)
|
||||
m.Get("/new", admin.NewUser)
|
||||
m.Post("/new", bindIgnErr(auth.AdminCrateUserForm{}), admin.NewUserPost)
|
||||
m.Get("/:userid", admin.EditUser)
|
||||
m.Post("/:userid", bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost)
|
||||
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCrateUserForm{}), admin.NewUserPost)
|
||||
m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost)
|
||||
m.Post("/:userid/delete", admin.DeleteUser)
|
||||
})
|
||||
|
||||
@@ -323,13 +276,13 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
|
||||
m.Group("/repos", func() {
|
||||
m.Get("", admin.Repositories)
|
||||
m.Get("", admin.Repos)
|
||||
m.Post("/delete", admin.DeleteRepo)
|
||||
})
|
||||
|
||||
m.Group("/auths", func() {
|
||||
m.Get("", admin.Authentications)
|
||||
m.Get("/new", admin.NewAuthSource)
|
||||
m.Post("/new", bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost)
|
||||
m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost)
|
||||
m.Combo("/:authid").Get(admin.EditAuthSource).
|
||||
Post(bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost)
|
||||
m.Post("/:authid/delete", admin.DeleteAuthSource)
|
||||
@@ -337,14 +290,21 @@ func runWeb(ctx *cli.Context) {
|
||||
|
||||
m.Group("/notices", func() {
|
||||
m.Get("", admin.Notices)
|
||||
m.Get("/:id:int/delete", admin.DeleteNotice)
|
||||
m.Post("/delete", admin.DeleteNotices)
|
||||
m.Get("/empty", admin.EmptyNotices)
|
||||
})
|
||||
}, adminReq)
|
||||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/:username", user.Profile)
|
||||
m.Get("/attachments/:uuid", func(ctx *middleware.Context) {
|
||||
m.Group("/:username", func() {
|
||||
m.Get("", user.Profile)
|
||||
m.Get("/followers", user.Followers)
|
||||
m.Get("/following", user.Following)
|
||||
m.Get("/stars", user.Stars)
|
||||
})
|
||||
|
||||
m.Get("/attachments/:uuid", func(ctx *context.Context) {
|
||||
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
|
||||
if err != nil {
|
||||
if models.IsErrAttachmentNotExist(err) {
|
||||
@@ -373,11 +333,16 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/issues/attachments", repo.UploadIssueAttachment)
|
||||
}, ignSignIn)
|
||||
|
||||
m.Group("/:username", func() {
|
||||
m.Get("/action/:action", user.Action)
|
||||
}, reqSignIn)
|
||||
|
||||
if macaron.Env == macaron.DEV {
|
||||
m.Get("/template/*", dev.TemplatePreview)
|
||||
}
|
||||
|
||||
reqRepoAdmin := middleware.RequireRepoAdmin()
|
||||
reqRepoAdmin := context.RequireRepoAdmin()
|
||||
reqRepoWriter := context.RequireRepoWriter()
|
||||
|
||||
// ***** START: Organization *****
|
||||
m.Group("/org", func() {
|
||||
@@ -391,11 +356,14 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("/members/action/:action", org.MembersAction)
|
||||
|
||||
m.Get("/teams", org.Teams)
|
||||
}, context.OrgAssignment(true))
|
||||
|
||||
m.Group("/:org", func() {
|
||||
m.Get("/teams/:team", org.TeamMembers)
|
||||
m.Get("/teams/:team/repositories", org.TeamRepositories)
|
||||
m.Get("/teams/:team/action/:action", org.TeamsAction)
|
||||
m.Get("/teams/:team/action/repo/:action", org.TeamsRepoAction)
|
||||
}, middleware.OrgAssignment(true, true))
|
||||
m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction)
|
||||
m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction)
|
||||
}, context.OrgAssignment(true, false, true))
|
||||
|
||||
m.Group("/:org", func() {
|
||||
m.Get("/teams/new", org.NewTeam)
|
||||
@@ -408,6 +376,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Combo("").Get(org.Settings).
|
||||
Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
|
||||
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), org.SettingsAvatar)
|
||||
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", org.Webhooks)
|
||||
@@ -424,11 +393,8 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
|
||||
m.Route("/invitations/new", "GET,POST", org.Invitation)
|
||||
}, middleware.OrgAssignment(true, true, true))
|
||||
}, context.OrgAssignment(true, true))
|
||||
}, reqSignIn)
|
||||
m.Group("/org", func() {
|
||||
m.Get("/:org", org.Home)
|
||||
}, ignSignIn, middleware.OrgAssignment(true))
|
||||
// ***** END: Organization *****
|
||||
|
||||
// ***** START: Repository *****
|
||||
@@ -445,7 +411,11 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Group("/settings", func() {
|
||||
m.Combo("").Get(repo.Settings).
|
||||
Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost)
|
||||
m.Route("/collaboration", "GET,POST", repo.Collaboration)
|
||||
m.Group("/collaboration", func() {
|
||||
m.Combo("").Get(repo.Collaboration).Post(repo.CollaborationPost)
|
||||
m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
|
||||
m.Post("/delete", repo.DeleteCollaboration)
|
||||
})
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", repo.Webhooks)
|
||||
@@ -454,6 +424,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Get("/:id", repo.WebHooksEdit)
|
||||
m.Post("/:id/test", repo.TestWebhook)
|
||||
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||
|
||||
@@ -461,7 +432,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("", repo.GitHooks)
|
||||
m.Combo("/:name").Get(repo.GitHooksEdit).
|
||||
Post(repo.GitHooksEditPost)
|
||||
}, middleware.GitHookService())
|
||||
}, context.GitHookService())
|
||||
})
|
||||
|
||||
m.Group("/keys", func() {
|
||||
@@ -470,16 +441,15 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/delete", repo.DeleteDeployKey)
|
||||
})
|
||||
|
||||
}, func(ctx *middleware.Context) {
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["PageIsSettings"] = true
|
||||
})
|
||||
}, reqSignIn, middleware.RepoAssignment(true), reqRepoAdmin, middleware.RepoRef())
|
||||
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
|
||||
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/action/:action", repo.Action)
|
||||
|
||||
m.Group("/issues", func() {
|
||||
m.Combo("/new").Get(repo.NewIssue).
|
||||
m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
|
||||
|
||||
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
|
||||
@@ -487,7 +457,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/label", repo.UpdateIssueLabel)
|
||||
m.Post("/milestone", repo.UpdateIssueMilestone)
|
||||
m.Post("/assignee", repo.UpdateIssueAssignee)
|
||||
}, reqRepoAdmin)
|
||||
}, reqRepoWriter)
|
||||
|
||||
m.Group("/:index", func() {
|
||||
m.Post("/title", repo.UpdateIssueTitle)
|
||||
@@ -499,15 +469,15 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
||||
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
||||
m.Post("/delete", repo.DeleteLabel)
|
||||
}, reqRepoAdmin)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
m.Group("/milestones", func() {
|
||||
m.Get("/new", repo.NewMilestone)
|
||||
m.Post("/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||
m.Combo("/new").Get(repo.NewMilestone).
|
||||
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||
m.Get("/:id/edit", repo.EditMilestone)
|
||||
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
|
||||
m.Get("/:id/:action", repo.ChangeMilestonStatus)
|
||||
m.Post("/delete", repo.DeleteMilestone)
|
||||
}, reqRepoAdmin)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
@@ -515,51 +485,65 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("/edit/:tagname", repo.EditRelease)
|
||||
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
||||
m.Post("/delete", repo.DeleteRelease)
|
||||
}, reqRepoAdmin, middleware.RepoRef())
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
m.Combo("/compare/*").Get(repo.CompareAndPullRequest).
|
||||
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
}, reqSignIn, middleware.RepoAssignment(true))
|
||||
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("", func() {
|
||||
m.Get("/releases", repo.Releases)
|
||||
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
|
||||
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
|
||||
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
|
||||
m.Get("/milestones", repo.Milestones)
|
||||
}, middleware.RepoRef(),
|
||||
func(ctx *middleware.Context) {
|
||||
ctx.Data["PageIsList"] = true
|
||||
})
|
||||
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
|
||||
}, context.RepoRef())
|
||||
|
||||
// m.Get("/branches", repo.Branches)
|
||||
|
||||
m.Group("/wiki", func() {
|
||||
m.Get("/?:page", repo.Wiki)
|
||||
m.Get("/_pages", repo.WikiPages)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_new").Get(repo.NewWiki).
|
||||
Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
|
||||
m.Combo("/:page/_edit").Get(repo.EditWiki).
|
||||
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
|
||||
m.Post("/:page/delete", repo.DeleteWikiPagePost)
|
||||
}, reqSignIn, reqRepoWriter)
|
||||
}, repo.MustEnableWiki, context.RepoRef())
|
||||
|
||||
m.Get("/branches", repo.Branches)
|
||||
m.Get("/archive/*", repo.Download)
|
||||
|
||||
m.Group("/pulls/:index", func() {
|
||||
m.Get("/commits", repo.ViewPullCommits)
|
||||
m.Get("/files", repo.ViewPullFiles)
|
||||
m.Post("/merge", reqRepoAdmin, repo.MergePullRequest)
|
||||
})
|
||||
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
|
||||
m.Get("/files", context.RepoRef(), repo.ViewPullFiles)
|
||||
m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
|
||||
}, repo.MustAllowPulls)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/src/*", repo.Home)
|
||||
m.Get("/raw/*", repo.SingleDownload)
|
||||
m.Get("/commits/*", repo.RefCommits)
|
||||
m.Get("/commit/*", repo.Diff)
|
||||
m.Get("/stars", repo.Stars)
|
||||
m.Get("/watchers", repo.Watchers)
|
||||
m.Get("/commit/:sha([a-z0-9]{40})$", repo.Diff)
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, middleware.RepoRef())
|
||||
}, context.RepoRef())
|
||||
m.Get("/commit/:sha([a-z0-9]{40})\\.:ext(patch|diff)", repo.RawDiff)
|
||||
|
||||
m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff)
|
||||
}, ignSignIn, middleware.RepoAssignment(true))
|
||||
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.CompareDiff)
|
||||
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/stars", repo.Stars)
|
||||
m.Get("/watchers", repo.Watchers)
|
||||
}, 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, true), middleware.RepoRef())
|
||||
}, ignSignIn, context.RepoAssignment(true), context.RepoRef())
|
||||
|
||||
m.Group("/:reponame", func() {
|
||||
m.Any("/*", ignSignInAndCsrf, repo.HTTP)
|
||||
@@ -568,8 +552,12 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
// ***** END: Repository *****
|
||||
|
||||
m.Group("/api", func() {
|
||||
apiv1.RegisterRoutes(m)
|
||||
}, ignSignIn)
|
||||
|
||||
// robots.txt
|
||||
m.Get("/robots.txt", func(ctx *middleware.Context) {
|
||||
m.Get("/robots.txt", func(ctx *context.Context) {
|
||||
if setting.HasRobotsTxt {
|
||||
ctx.ServeFileContent(path.Join(setting.CustomPath, "robots.txt"))
|
||||
} else {
|
||||
@@ -604,4 +592,6 @@ func runWeb(ctx *cli.Context) {
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to start server: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
Execute following command in ROOT directory when anything is changed:
|
||||
|
||||
$ go-bindata -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
|
||||
|
||||
Add -debug flag to make life easier in development(somehow isn't working):
|
||||
|
||||
$ go-bindata -debug -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
|
||||
$ make bindata
|
||||
122
conf/app.ini
122
conf/app.ini
@@ -12,9 +12,11 @@ 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
|
||||
|
||||
@@ -25,6 +27,12 @@ EXPLORE_PAGING_NUM = 20
|
||||
ISSUE_PAGING_NUM = 10
|
||||
; Number of maximum commits showed in one activity feed
|
||||
FEED_MAX_COMMIT_NUM = 5
|
||||
; Value of `theme-color` meta tag, used by Android >= 5.0
|
||||
; 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
|
||||
@@ -32,30 +40,50 @@ USER_PAGING_NUM = 50
|
||||
; Number of repos that are showed in one page
|
||||
REPO_PAGING_NUM = 50
|
||||
; Number of notices that are showed in one page
|
||||
NOTICE_PAGING_NUM = 50
|
||||
NOTICE_PAGING_NUM = 25
|
||||
; Number of organization that are showed in one page
|
||||
ORG_PAGING_NUM = 50
|
||||
|
||||
[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 =
|
||||
|
||||
[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
|
||||
; 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 = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
|
||||
; Disable SSH feature when not available
|
||||
DISABLE_SSH = false
|
||||
; Whether use builtin SSH server or not.
|
||||
START_SSH_SERVER = false
|
||||
; Domain name to be exposed in clone URL
|
||||
SSH_DOMAIN = %(DOMAIN)s
|
||||
; Port number to be exposed in clone URL
|
||||
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 =
|
||||
; Directory to create temporary files when test publick key using ssh-keygen,
|
||||
; default is system temporary directory.
|
||||
SSH_KEY_TEST_PATH =
|
||||
; Path to ssh-keygen, default is 'ssh-keygen' and let shell find out which one to call.
|
||||
SSH_KEYGEN_PATH = ssh-keygen
|
||||
; Indicate whether to check minimum key size with corresponding type
|
||||
MINIMUM_KEY_SIZE_CHECK = false
|
||||
; Disable CDN even in "prod" mode
|
||||
OFFLINE_MODE = false
|
||||
DISABLE_ROUTER_LOG = false
|
||||
; Generate steps:
|
||||
; $ cd path/to/gogs/custom/https
|
||||
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
|
||||
;
|
||||
; Or from a .pfx file exported from the Windows certificate store (do
|
||||
@@ -67,11 +95,20 @@ 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"
|
||||
LANDING_PAGE = home
|
||||
|
||||
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
|
||||
[ssh.minimum_key_sizes]
|
||||
ED25519 = 256
|
||||
ECDSA = 256
|
||||
RSA = 2048
|
||||
DSA = 1024
|
||||
|
||||
[database]
|
||||
; Either "mysql", "postgres" or "sqlite3", it's your choice
|
||||
DB_TYPE = mysql
|
||||
@@ -81,7 +118,7 @@ USER = root
|
||||
PASSWD =
|
||||
; For "postgres" only, either "disable", "require" or "verify-full"
|
||||
SSL_MODE = disable
|
||||
; For "sqlite3" and "tidb"
|
||||
; For "sqlite3" and "tidb", use absolute path when you start as service
|
||||
PATH = data/gogs.db
|
||||
|
||||
[admin]
|
||||
@@ -106,28 +143,14 @@ REGISTER_EMAIL_CONFIRM = false
|
||||
DISABLE_REGISTRATION = false
|
||||
; User must sign in to view anything.
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
; Cache avatar as picture
|
||||
ENABLE_CACHE_AVATAR = false
|
||||
; Mail notification
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
; More detail: https://github.com/gogits/gogs/issues/165
|
||||
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
; Do not check minimum key size with corresponding type
|
||||
DISABLE_MINIMUM_KEY_SIZE_CHECK = false
|
||||
; Enable captcha validation for registration
|
||||
ENABLE_CAPTCHA = true
|
||||
|
||||
; used to filter keys which are too short
|
||||
[service.minimum_key_sizes]
|
||||
ED25519 = 256
|
||||
ECDSA = 256
|
||||
NTRU = 1087
|
||||
MCE = 1702
|
||||
McE = 1702
|
||||
RSA = 1024
|
||||
DSA = 1024
|
||||
|
||||
[webhook]
|
||||
; Hook task queue length
|
||||
QUEUE_LENGTH = 1000
|
||||
@@ -146,24 +169,26 @@ SEND_BUFFER_LEN = 100
|
||||
SUBJECT = %(APP_NAME)s
|
||||
; Mail server
|
||||
; Gmail: smtp.gmail.com:587
|
||||
; QQ: smtp.qq.com:25
|
||||
; QQ: smtp.qq.com:465
|
||||
; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
|
||||
HOST =
|
||||
HOST =
|
||||
; Disable HELO operation when hostname are different.
|
||||
DISABLE_HELO =
|
||||
DISABLE_HELO =
|
||||
; Custom hostname for HELO operation, default is from system.
|
||||
HELO_HOSTNAME =
|
||||
HELO_HOSTNAME =
|
||||
; Do not verify the certificate of the server. Only use this for self-signed certificates
|
||||
SKIP_VERIFY =
|
||||
SKIP_VERIFY =
|
||||
; Use client certificate
|
||||
USE_CERTIFICATE = false
|
||||
CERT_FILE = custom/mailer/cert.pem
|
||||
KEY_FILE = custom/mailer/key.pem
|
||||
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
|
||||
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
|
||||
FROM =
|
||||
; Mailer user name and password
|
||||
USER =
|
||||
PASSWD =
|
||||
; Use text/html as alternative format of content
|
||||
ENABLE_HTML_ALTERNATIVE = false
|
||||
|
||||
[cache]
|
||||
; Either "memory", "redis", or "memcache", default is "memory"
|
||||
@@ -176,7 +201,7 @@ INTERVAL = 60
|
||||
HOST =
|
||||
|
||||
[session]
|
||||
; Either "memory", "file", "redis" or "mysql", default is "memory"
|
||||
; Either "memory", "file", or "redis", default is "memory"
|
||||
PROVIDER = memory
|
||||
; Provider config options
|
||||
; memory: not have any config yet
|
||||
@@ -196,8 +221,6 @@ GC_INTERVAL_TIME = 86400
|
||||
SESSION_LIFE_TIME = 86400
|
||||
|
||||
[picture]
|
||||
; The place to picture data, either "server" or "qiniu", default is "server"
|
||||
SERVICE = server
|
||||
AVATAR_UPLOAD_PATH = data/avatars
|
||||
; Chinese users can choose "duoshuo"
|
||||
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
||||
@@ -265,8 +288,8 @@ ADDR =
|
||||
; For "smtp" mode only
|
||||
[log.smtp]
|
||||
LEVEL =
|
||||
; Name displayed in mail title, default is "Diagnostic message from serve"
|
||||
SUBJECT = Diagnostic message from serve
|
||||
; Name displayed in mail title, default is "Diagnostic message from server"
|
||||
SUBJECT = Diagnostic message from server
|
||||
; Mail server
|
||||
HOST =
|
||||
; Mailer user name and password
|
||||
@@ -296,9 +319,10 @@ SCHEDULE = @every 1h
|
||||
; Repository health check
|
||||
[cron.repo_health_check]
|
||||
SCHEDULE = @every 24h
|
||||
; Arguments for command 'git fsck', e.g.: "--unreachable --tags"
|
||||
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]
|
||||
@@ -306,20 +330,37 @@ RUN_AT_START = true
|
||||
SCHEDULE = @every 24h
|
||||
|
||||
[git]
|
||||
MAX_GIT_DIFF_LINES = 10000
|
||||
; Arguments for command 'git gc', e.g.: "--aggressive --auto"
|
||||
; 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]
|
||||
MIGRATE = 600
|
||||
MIRROR = 300
|
||||
CLONE = 300
|
||||
PULL = 300
|
||||
|
||||
[api]
|
||||
; Max number of items will response in a page
|
||||
MAX_RESPONSE_ITEMS = 50
|
||||
|
||||
[i18n]
|
||||
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT
|
||||
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano
|
||||
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
|
||||
@@ -331,6 +372,13 @@ pt-BR = pt-BR
|
||||
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
|
||||
[highlight.mapping]
|
||||
|
||||
[other]
|
||||
SHOW_FOOTER_BRANDING = false
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
Creative Commons CC0 1.0 Universal
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,29 +1,61 @@
|
||||
# This file lists all PUBLIC individuals having contributed content to the translation.
|
||||
# Entries are in alphabetical order.
|
||||
|
||||
Adam Strzelecki <ono AT java DOT pl>
|
||||
Adrian Verde <me AT adrianverde DOT com>
|
||||
Akihiro YAGASAKI <yaggytter AT momiage DOT com>
|
||||
Aleksejs Grocevs <aleksejs AT grocevs DOT pro>
|
||||
Aleksey Tarakin <hukendo AT yandex DOT ru>
|
||||
Alexander Steinhöfer <kontakt AT lx-s DOT de>
|
||||
Alexandre Magno <alexandre DOT mbm AT gmail DOT com>
|
||||
Andrey Nering <andrey AT nering DOT com DOT br>
|
||||
Andrey Solomatin <toadron AT yandex DOT ru>
|
||||
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>
|
||||
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
|
||||
ilko <kontact-mr.k AT outlook DOT com">
|
||||
Ilya Makarov
|
||||
Jamie Mansfield <dev AT jamierocks DOT uk>
|
||||
Jean THOMAS <contact AT tibounise DOT com>
|
||||
Juraj Bubniak <contact AT jbub DOT eu>
|
||||
Lafriks <lafriks AT gmail DOT com>
|
||||
Lauri Ojansivu <x AT xet7 DOT org>
|
||||
Luc Stepniewski <luc AT stepniewski DOT fr>
|
||||
Luca Bozzo <luca AT bozzo DOT it>
|
||||
Luca Kröger <l DOT kroeger01 AT gmail DOT com>
|
||||
Marc Schiller <marc AT schiller DOT im>
|
||||
Marvin Menzerath <github AT marvin-menzerath DOT de>
|
||||
Michael Härtl <haertl DOT mike AT gmail DOT com>
|
||||
Miguel de la Cruz <miguel AT mcrx DOT me>
|
||||
Mikhail Burdin <xdshot9000 AT gmail DOT com>
|
||||
Morten Sørensen <klim8d AT gmail DOT com>
|
||||
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>
|
||||
Toni Villena Jiménez <tonivj5 AT gmail DOT com>
|
||||
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>
|
||||
Łukasz Jan Niemier <lukasz AT niemier DOT pl>
|
||||
Pablo Saavedra <psaavedra AT igalia DOT com>
|
||||
|
||||
393
conf/locale/locale_bg-BG.ini
Executable file → Normal file
393
conf/locale/locale_bg-BG.ini
Executable file → Normal file
@@ -2,12 +2,12 @@ app_desc=Безпроблемен собствен Git сървър
|
||||
|
||||
home=Начало
|
||||
dashboard=Табло
|
||||
explore=Разгледай
|
||||
explore=Каталог
|
||||
help=Помощ
|
||||
sign_in=Влизане
|
||||
sign_out=Излизане
|
||||
sign_in=Вход
|
||||
sign_out=Изход
|
||||
sign_up=Регистрирайте се
|
||||
register=Регистриране
|
||||
register=Регистрация
|
||||
website=Уебсайт
|
||||
version=Версия
|
||||
page=Страница
|
||||
@@ -28,6 +28,7 @@ organization=Организация
|
||||
mirror=Огледало
|
||||
new_repo=Ново хранилище
|
||||
new_migrate=Нова миграция
|
||||
new_mirror=Ново огледало
|
||||
new_fork=Ново разклонено хранилище
|
||||
new_org=Нова организация
|
||||
manage_org=Управление на организации
|
||||
@@ -37,19 +38,12 @@ settings=Настройки
|
||||
your_profile=Вашият профил
|
||||
your_settings=Вашите настройки
|
||||
|
||||
news_feed=Поток новини
|
||||
activities=Активности
|
||||
pull_requests=Заявки за сливане
|
||||
issues=Проблеми
|
||||
issues=Задачи
|
||||
|
||||
cancel=Отказ
|
||||
|
||||
[search]
|
||||
search=Търсене...
|
||||
repository=Хранилище
|
||||
user=Потребител
|
||||
issue=Проблем
|
||||
code=Код
|
||||
|
||||
[install]
|
||||
install=Инсталация
|
||||
title=Стъпки за инсталиране при първоначално стартиране
|
||||
@@ -64,7 +58,7 @@ db_name=Име на база данни
|
||||
db_helper=Моля, използвайте INNODB engine с utf8_general_ci кодиране на знаци за MySQL.
|
||||
ssl_mode=Режим SSL
|
||||
path=Път
|
||||
sqlite_helper=Файл на SQLite3 или TiDB база данни.
|
||||
sqlite_helper=Файл на SQLite3 или TiDB база данни.<br>Моля използвайте абсолютен път до файл когато стартирате Gogs като услуга.
|
||||
err_empty_db_path=Пътят до SQLite3 или TiDB база данни не може да е празен.
|
||||
err_invalid_tidb_name=TiDB не позволява "." и "-" в името на базата данни.
|
||||
no_admin_and_disable_registration=Невъзможно изключване на регистрациите без предварително да е създаден поне един административен профил.
|
||||
@@ -85,6 +79,8 @@ http_port=HTTP порт
|
||||
http_port_helper=Порт, на който приложението ще слуша.
|
||||
app_url=URL адрес на приложението
|
||||
app_url_helper=Този настройка променя HTTP/HTTPS адреса за клониране, а понякога и адреса на ел. поща.
|
||||
log_root_path=Път към журналите
|
||||
log_root_path_helper=Директория в която се записват журналите.
|
||||
|
||||
optional_title=Опционални настройки
|
||||
email_title=Настройки на пощенска услуга
|
||||
@@ -121,9 +117,10 @@ run_user_not_match=Потребителският контекст на прил
|
||||
save_config_failed=Неуспешно запазване на конфигурация: %v
|
||||
invalid_admin_setting=Настройките на профил на администратора са невалидни: %v
|
||||
install_success=Добре дошли! Радваме се, че избрахте Gogs, и Ви пожелаваме приятна работа и сърдечни поздрави!
|
||||
invalid_log_root_path=Основният път към журналите е невалиден: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Потребителско име или ел. поща
|
||||
uname_holder=Име или ел. поща
|
||||
password_holder=Парола
|
||||
switch_dashboard_context=Превключи контекст на таблото
|
||||
my_repos=Моите хранилища
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=Във Вашите хранилища
|
||||
|
||||
[explore]
|
||||
repos=Хранилища
|
||||
users=Потребители
|
||||
search=Търсене
|
||||
|
||||
[auth]
|
||||
create_new_account=Създай нов профил
|
||||
@@ -158,13 +157,14 @@ reset_password=Нулиране на паролата
|
||||
invalid_code=За съжаление Вашия код за потвърждение е изтекъл или е невалиден.
|
||||
reset_password_helper=Щракнете тук, за да нулирате паролата си
|
||||
password_too_short=Размерът на паролата не може да бъде по-малък от 6 знака.
|
||||
non_local_account=Non-local accounts cannot change passwords through Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=Моля активирайте Вашия профил
|
||||
activate_email=Провери адрес на ел. поща
|
||||
reset_password=Нулиране на паролата
|
||||
register_success=Успешна регистрация и добре дошли
|
||||
register_notify=Welcome on board
|
||||
register_notify=Добре дошли
|
||||
|
||||
[modal]
|
||||
yes=Да
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=Името на хранилището вече се пол
|
||||
org_name_been_taken=Името на организацията вече се ползва.
|
||||
team_name_been_taken=Името на екипа вече се ползва.
|
||||
email_been_used=Този адрес на ел. поща вече се ползва.
|
||||
illegal_team_name=Името на екипа съдържа недопустими знаци.
|
||||
username_password_incorrect=Потребителското име или паролата не са верни.
|
||||
enterred_invalid_repo_name=Моля уверете се, че въведеното име на хранилище е вярно.
|
||||
enterred_invalid_owner_name=Моля уверете се, че въведеното име на притежател е вярно.
|
||||
@@ -215,22 +214,21 @@ unable_verify_ssh_key=Gogs не може да провери Вашия SSH кл
|
||||
auth_failed=Неуспешно удостоверяване: %v
|
||||
|
||||
still_own_repo=Вашият профил притежава поне едно хранилище. Първо трябва да ги изтриете или да ги прехвърлите на друг потребител.
|
||||
still_has_org=Вашият профил все още е член на поне една организация. Първо трябва да напуснете или изтриете Вашите членства.
|
||||
still_has_org=Вашият профил все още участва в поне една организация. Първо трябва да напуснете или изтриете Вашите участия в организациите.
|
||||
org_still_own_repo=Тази организация все още притежава хранилище. Първо трябва да го изтриете или да го прехвърлите на друга организация.
|
||||
|
||||
still_own_user=Това удостоверяване се използва от поне един потребител. Моля премахнете потребителите към него и опитайте отново.
|
||||
|
||||
target_branch_not_exist=Целевият клон не съществува.
|
||||
|
||||
[user]
|
||||
change_avatar=Сменете Вашия аватар на gravatar.com
|
||||
change_custom_avatar=Сменете Вашия аватар в настройките
|
||||
join_on=Регистриран на
|
||||
change_avatar=Change your avatar
|
||||
join_on=Регистриран
|
||||
repositories=Хранилища
|
||||
activity=Публична дейност
|
||||
followers=Последователи
|
||||
starred=Харесано
|
||||
following=Следване
|
||||
follow=Следване
|
||||
unfollow=Не следвай
|
||||
|
||||
form.name_reserved=Потребителското име '%s' е запазено.
|
||||
form.name_pattern_not_allowed=Потребителското име '%s' не е допустимо.
|
||||
@@ -247,10 +245,11 @@ uid=UID
|
||||
|
||||
public_profile=Публичен профил
|
||||
profile_desc=Вашият адрес на ел. поща е публичен и ще бъде използван за всички свързани с профила Ви уведомления и всички уеб базирани операции, направени чрез сайта.
|
||||
password_username_disabled=Нелокални потребители не могат да променят името си от тук.
|
||||
full_name=Пълно име
|
||||
website=Уебсайт
|
||||
location=Локация
|
||||
update_profile=Обнови профила
|
||||
update_profile=Запази профила
|
||||
update_profile_success=Вашият профил е запазен успешно.
|
||||
change_username=Потребителското име е променено
|
||||
change_username_prompt=Този промяна ще засегне всички връзки сочещи към профила Ви.
|
||||
@@ -258,19 +257,19 @@ continue=Продължи
|
||||
cancel=Отказ
|
||||
|
||||
enable_custom_avatar=Разреши потребителски аватар
|
||||
enable_custom_avatar_helper=Включете тази опция, за да забраните зареждане от Gravatar
|
||||
choose_new_avatar=Избери нов аватар
|
||||
update_avatar=Обнови настройките на аватара
|
||||
choose_new_avatar=Избор на нов аватар
|
||||
update_avatar=Запази настройките на аватара
|
||||
delete_current_avatar=Изтрий аватар
|
||||
uploaded_avatar_not_a_image=Каченият файл не е изображение.
|
||||
no_custom_avatar_available=Невъзможно използване на външен аватар, защото не е активирано.
|
||||
update_avatar_success=Настройките на аватара са запазени успешно.
|
||||
|
||||
change_password=Промени парола
|
||||
change_password=Промяна на собствената парола
|
||||
old_password=Текуща парола
|
||||
new_password=Нова парола
|
||||
retype_new_password=Повторно новата парола
|
||||
password_incorrect=Въведената парола не е вярна.
|
||||
change_password_success=Вашата парола е променена успешно. Вече може да влизате, използвайки тази нова парола.
|
||||
password_change_disabled=Нелокални потребители не могат да променят паролата си от тук.
|
||||
|
||||
emails=Адреси на ел. поща
|
||||
manage_emails=Управление на адреси на ел. поща
|
||||
@@ -289,7 +288,7 @@ add_email_success=Ваш нов адрес на ел. поща е добавен
|
||||
manage_ssh_keys=Управление на SSH ключове
|
||||
add_key=Добави ключ
|
||||
ssh_desc=Това е списък на SSH ключове, свързани с Вашия акаунт. Тъй като тези ключове позволяват на всеки, който ги използва да получи достъп до хранилищата Ви, много е важно да се уверите, че ги разпознавате.
|
||||
ssh_helper=<strong>Не знам как?</strong> Проверете на GitHub упътването как да <a href="%s">създадете свои собствени SSH ключове</a> или решаване на <a href="%s">Общи проблеми</a>, които може да възникнат при използване на SSH.
|
||||
ssh_helper=<strong>Не знаете как?</strong> Проверете упътването на GitHub за <a href="%s">създаване на собствени SSH ключове</a> или погледнете <a href="%s">Общи проблеми</a>, които може да възникнат при използване на SSH.
|
||||
add_new_key=Добавяне на SSH ключ
|
||||
ssh_key_been_used=Съдържанието на публичния ключ е използвано.
|
||||
ssh_key_name_used=Вече съществува публичен ключ с това име.
|
||||
@@ -302,31 +301,31 @@ ssh_key_deletion_desc=При изтриване на този SSH ключ ще
|
||||
ssh_key_deletion_success=SSH ключа беше изтрит успешно!
|
||||
add_on=Добавен на
|
||||
last_used=Последно използван на
|
||||
no_activity=Няма скорошна активност
|
||||
no_activity=Няма скорошна дейност
|
||||
key_state_desc=Този ключ е използван през последните 7 дни
|
||||
token_state_desc=Този токен е използван през последните 7 дни
|
||||
token_state_desc=Този API ключ е използван през последните 7 дни
|
||||
|
||||
manage_social=Управление на свързани профили в социалните мрежи
|
||||
social_desc=Това е списък на свързани профили в социалните мрежи. Премахнете всички, които не разпознавате.
|
||||
unbind=Освобождаване
|
||||
unbind_success=Социалния профил е освободен.
|
||||
|
||||
manage_access_token=Управление на индивидуални токени за достъп
|
||||
generate_new_token=Генериране на нов токен
|
||||
tokens_desc=Генерирани токени, които могат да се използват за достъп до API-то на Gogs.
|
||||
new_token_desc=Всеки токен ще има пълен достъп до Вашия профил.
|
||||
token_name=Име на токена
|
||||
generate_token=Генериране на токен
|
||||
generate_token_succees=Успешно е генериран токен за достъп. Уверете се, че сте го копирали, тъй като няма да можете да го видите отново!
|
||||
manage_access_token=Управление на индивидуални API ключове за достъп
|
||||
generate_new_token=Генериране на нов API ключ
|
||||
tokens_desc=Генерирани API ключове, които могат да се използват за достъп до API на Gogs.
|
||||
new_token_desc=Всеки API ключ ще има пълен достъп до Вашия профил.
|
||||
token_name=Име на API ключ
|
||||
generate_token=Генериране на API ключ
|
||||
generate_token_succees=Успешно е генериран API ключ за достъп. Уверете се, че сте го копирали, тъй като няма да можете да го видите отново!
|
||||
delete_token=Изтрий
|
||||
access_token_deletion=Изтрий индивидуален токен за достъп
|
||||
access_token_deletion_desc=При изтриване на този индивидуален токен за достъп ще се премахнат всички свързани права на приложението. Желаете ли да продължите?
|
||||
delete_token_success=Индивидуалния токен за достъп е изтрит успешно! Не забравяйте да преконфигурирате приложението също.
|
||||
access_token_deletion=Изтрий индивидуален API ключ за достъп
|
||||
access_token_deletion_desc=При изтриване на този индивидуален API ключ за достъп ще се премахнат всички свързани права на приложението. Желаете ли да продължите?
|
||||
delete_token_success=Индивидуалният API ключ за достъп е изтрит успешно! Не забравяйте да преконфигурирате приложението също.
|
||||
|
||||
delete_account=Изтрий собствен профил
|
||||
delete_account=Изтриване на собствения профил
|
||||
delete_prompt=Тази операция ще изтрие Вашия профил завинаги и тя <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие!
|
||||
confirm_delete_account=Потвърди изтриването
|
||||
delete_account_title=Изтрий профил
|
||||
delete_account_title=Изтриване на профил
|
||||
delete_account_desc=Този профил ще бъде окончателно изтрит. Желаете ли да продължите?
|
||||
|
||||
[repo]
|
||||
@@ -342,7 +341,7 @@ fork_repo=Разклони хранилището
|
||||
fork_from=Разклонение от
|
||||
fork_visiblity_helper=Не може да променяте видимостта на разклонено хранилище.
|
||||
repo_desc=Описание
|
||||
repo_lang=Език
|
||||
repo_lang=Програмен език
|
||||
repo_lang_helper=Изберете .gitignore файлове
|
||||
license=Лиценз
|
||||
license_helper=Изберете лицензионен файл
|
||||
@@ -351,35 +350,41 @@ 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=Интервал на отразяване (часове)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=Адрес на огледало
|
||||
mirror_address_desc=Моля включете потребител и парола в адреса ако са нужни.
|
||||
watchers=Наблюдаващи
|
||||
stargazers=Харесващи
|
||||
forks=Разклонения
|
||||
|
||||
form.reach_limit_of_creation=Притежателят е достигнал настроения лимит от %d брой хранилища.
|
||||
form.name_reserved=Името на хранилището '%s' е запазено.
|
||||
form.name_pattern_not_allowed=Име на хранилището от вида '%s' не е позволено.
|
||||
|
||||
need_auth=Изисква удостоверяване
|
||||
need_auth=Изисква потребител и парола
|
||||
migrate_type=Тип мигриране
|
||||
migrate_type_helper=Това хранилище ще бъде <span class="text blue">огледало</span>
|
||||
migrate_repo=Мигрирай хранилище
|
||||
migrate.clone_address=Адрес за клонирай
|
||||
migrate.clone_address=Адрес за клониране
|
||||
migrate.clone_address_desc=Това може да е HTTP/HTTPS/GIT адрес или локален път на сървъра.
|
||||
migrate.permission_denied=Недостатъчни права за импорт на локални хранилища.
|
||||
migrate.invalid_local_path=Невалиден път - не съществува или не е директория.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Грешка при миграция: %v
|
||||
|
||||
mirror_from=огледало от
|
||||
forked_from=разклонено от
|
||||
fork_from_self=Не можете да разклоните хранилище което си е Ваше!
|
||||
copy_link=Копирай
|
||||
copy_link_success=Копирано!
|
||||
copy_link_error=Натиснете ⌘-C или Ctrl-C за да копирате
|
||||
copied=Успешно копиране
|
||||
unwatch=Не следи
|
||||
watch=Следи
|
||||
unwatch=Не наблюдавам
|
||||
watch=Наблюдаван
|
||||
unstar=Не харесвам
|
||||
star=Харесвам
|
||||
fork=Разклонение
|
||||
star=Харесван
|
||||
fork=Разклонения
|
||||
|
||||
no_desc=Няма описание
|
||||
quick_guide=Бърз справочник
|
||||
@@ -388,20 +393,21 @@ create_new_repo_command=Създай ново хранилище чрез ком
|
||||
push_exist_repo=Предай съществуващо хранилище през командния ред
|
||||
repo_is_empty=Това хранилище е празно. Моля проверете по-късно пак!
|
||||
|
||||
code=Код
|
||||
branch=Клон
|
||||
tree=Дърво
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
tree=ИН на ревизия
|
||||
filter_branch_and_tag=Филтър по маркер или клон
|
||||
branches=Клонове
|
||||
tags=Маркери
|
||||
issues=Проблеми
|
||||
issues=Задачи
|
||||
pulls=Заявки за сливане
|
||||
labels=Етикети
|
||||
milestones=Етапи
|
||||
commits=Ревизии
|
||||
releases=Издания
|
||||
file_raw=Суров
|
||||
releases=Версии
|
||||
file_raw=Директен файл
|
||||
file_history=История
|
||||
file_view_raw=Виж суров
|
||||
file_view_raw=Виж директен файл
|
||||
file_permalink=Постоянна връзка
|
||||
|
||||
commits.commits=Ревизии
|
||||
@@ -413,7 +419,7 @@ commits.date=Дата
|
||||
commits.older=По-стари
|
||||
commits.newer=По-нови
|
||||
|
||||
issues.new=Нов проблем
|
||||
issues.new=Нова задача
|
||||
issues.new.labels=Етикети
|
||||
issues.new.no_label=Няма етикет
|
||||
issues.new.clear_labels=Изчисти етикети
|
||||
@@ -425,7 +431,7 @@ issues.new.closed_milestone=Затворени етапи
|
||||
issues.new.assignee=Изпълнител
|
||||
issues.new.clear_assignee=Изчисти изпълнител
|
||||
issues.new.no_assignee=Няма изпълнител
|
||||
issues.create=Докладвай проблем
|
||||
issues.create=Създай задача
|
||||
issues.new_label=Нов етикет
|
||||
issues.new_label_placeholder=Име на етикета...
|
||||
issues.create_label=Създай етикет
|
||||
@@ -438,7 +444,7 @@ issues.filter_milestone_no_select=Липсва избран етап
|
||||
issues.filter_assignee=Изпълнител
|
||||
issues.filter_assginee_no_select=Няма избран изпълнител
|
||||
issues.filter_type=Тип
|
||||
issues.filter_type.all_issues=Всички проблеми
|
||||
issues.filter_type.all_issues=Всички задачи
|
||||
issues.filter_type.assigned_to_you=Възложени на Вас
|
||||
issues.filter_type.created_by_you=Създадени от Вас
|
||||
issues.filter_type.mentioning_you=Споменават лично
|
||||
@@ -465,9 +471,9 @@ issues.reopen_comment_issue=Kоментирай и oтвори отново
|
||||
issues.create_comment=Коментирай
|
||||
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.commit_ref_at=`посочи тази задача от ревизия <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Участник
|
||||
issues.admin=Администратор
|
||||
issues.collaborator=Сътрудник
|
||||
issues.owner=Притежател
|
||||
issues.sign_up_for_free=Регистрирай се безплатно
|
||||
issues.sign_in_require_desc=за да се включите в този разговор. Вече имате профил? <a href="%s">Влезте, за да коментирате</a>
|
||||
@@ -477,15 +483,16 @@ issues.save=Запис
|
||||
issues.label_title=Име на етикета
|
||||
issues.label_color=Цвят на етикет
|
||||
issues.label_count=%d етикети
|
||||
issues.label_open_issues=%d отворени проблема
|
||||
issues.label_open_issues=%d отворени задачи
|
||||
issues.label_edit=Редакция
|
||||
issues.label_delete=Изтрий
|
||||
issues.label_modify=Промяна на етикет
|
||||
issues.label_deletion=Изтрий етикет
|
||||
issues.label_deletion_desc=При изтриване на този етикет ще се премахне информацията за него във всички свързани проблеми. Желаете ли да продължите?
|
||||
issues.label_deletion_desc=При изтриване на този етикет ще се премахне информацията за него във всички свързани задачи. Желаете ли да продължите?
|
||||
issues.label_deletion_success=Етикетът е изтрит успешно!
|
||||
issues.num_participants=%d участника
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Нова заявка за сливане
|
||||
pulls.compare_changes=Сравни промените
|
||||
pulls.compare_changes_desc=Сравнява двата клона и създава заявка за сливане за разликите помежду им.
|
||||
pulls.compare_base=родителска версия
|
||||
@@ -505,9 +512,9 @@ pulls.merged=Обединени
|
||||
pulls.has_merged=Тази заявка за сливане е обединена успешно!
|
||||
pulls.data_broken=Данните от тази заявка за сливане са невалидни поради изтрита информация за някое разклонение.
|
||||
pulls.is_checking=Проверката за конфликт все още е в ход. Моля обновете страницата след малко.
|
||||
pulls.can_auto_merge_desc=Можете да извършвате авто-обединяване на тази заявка за сливане.
|
||||
pulls.cannot_auto_merge_desc=Не можете да извършите авто-обединяване, защото съществуват конфликти между ревизиите.
|
||||
pulls.cannot_auto_merge_helper=Моля, използвайте инструменти на командния ред за да отстраните проблема.
|
||||
pulls.can_auto_merge_desc=Може да се извърши обединяване на тази заявка за сливане.
|
||||
pulls.cannot_auto_merge_desc=Не може да се извърши обединяване, защото съществуват конфликти между ревизиите.
|
||||
pulls.cannot_auto_merge_helper=Моля, използвайте инструменти на командния ред за да разрешите конфликтите.
|
||||
pulls.merge_pull_request=Обедини заявка за сливане
|
||||
pulls.open_unmerged_pull_exists=`Невъзможно повторно отваряне, защото вече съществува заявка за сливане (#%d) от същото хранилище със същата информация за обединяване, която чака да бъде извършена`
|
||||
|
||||
@@ -518,7 +525,7 @@ milestones.closed=Затворен %s
|
||||
milestones.no_due_date=Няма краен срок
|
||||
milestones.open=Отвори
|
||||
milestones.close=Затвори
|
||||
milestones.new_subheader=Създайте етапи за да организирате проблемите.
|
||||
milestones.new_subheader=Създайте етапи за да организирате задачите.
|
||||
milestones.create=Създай етап
|
||||
milestones.title=Заглавие
|
||||
milestones.desc=Описание
|
||||
@@ -532,32 +539,75 @@ milestones.cancel=Отказ
|
||||
milestones.modify=Промяна на етап
|
||||
milestones.edit_success=Промените в етап '%s' са запазени успешно!
|
||||
milestones.deletion=Изтрий етап
|
||||
milestones.deletion_desc=При изтриване на етап ще се премахне информацията за него от всички свързани проблеми. Желаете ли да продължите?
|
||||
milestones.deletion_desc=При изтриване на етап ще се премахне информацията за него от всички свързани задачи. Желаете ли да продължите?
|
||||
milestones.deletion_success=Етапът е изтрит успешно!
|
||||
|
||||
wiki=Уики
|
||||
wiki.welcome=Добре дошли в Уики!
|
||||
wiki.welcome_desc=Уики е място, където заедно можете да документирате проекта си, за да го направите по-добър.
|
||||
wiki.create_first_page=Създай първата страница
|
||||
wiki.page=Страница
|
||||
wiki.filter_page=Филтър страница
|
||||
wiki.new_page=Създай нова страница
|
||||
wiki.default_commit_message=Напишете описание на тази модификация (опционално).
|
||||
wiki.save_page=Запис на страница
|
||||
wiki.last_commit_info=%s редактира тази страница %s
|
||||
wiki.edit_page_button=Редакция
|
||||
wiki.new_page_button=Нова страница
|
||||
wiki.delete_page_button=Изтрий страница
|
||||
wiki.delete_page_notice_1=Това ще изтрие страница <code>"%s"</code>. Моля, бъдете сигурни.
|
||||
wiki.page_already_exists=Страница със същото име вече съществува.
|
||||
wiki.pages=Страници
|
||||
wiki.last_updated=Последна модификация на %s
|
||||
|
||||
settings=Настройки
|
||||
settings.options=Опции
|
||||
settings.collaboration=Сътрудничество
|
||||
settings.collaboration.admin=Admin
|
||||
settings.collaboration.write=Write
|
||||
settings.collaboration.read=Read
|
||||
settings.collaboration.undefined=Undefined
|
||||
settings.hooks=Уеб-куки
|
||||
settings.githooks=Git куки
|
||||
settings.basic_settings=Основни настройки
|
||||
settings.danger_zone=Опасната зона
|
||||
settings.site=Официален сайт
|
||||
settings.update_settings=Обнови настройките
|
||||
settings.update_settings=Запази настройките
|
||||
settings.change_reponame_prompt=Тази промяна ще засегне връзките, които се отнасят до това хранилището.
|
||||
settings.advanced_settings=Разширени настройки
|
||||
settings.wiki_desc=Включва уики за да може потребителите да създават документи
|
||||
settings.use_external_wiki=Използвай външно уики
|
||||
settings.external_wiki_url=URL адрес на външно уики
|
||||
settings.external_wiki_url_desc=Посетителите ще бъдат пренасочени към този URL адрес от връзката за раздел уики.
|
||||
settings.issues_desc=Включва вградена система за проследяване на задачи
|
||||
settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи
|
||||
settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
|
||||
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
|
||||
settings.danger_zone=Опасна зона
|
||||
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
|
||||
settings.convert=Промени към редовно хранилище
|
||||
settings.convert_desc=Можете да промените това огледало към редовно хранилище. Конверсията не може да се отмени.
|
||||
settings.convert_notices_1=- Тази операция ще конвертира огледалото към редовно хранилище и не може да бъде отменена в последствие.
|
||||
settings.convert_confirm=Потвърдете конверсията
|
||||
settings.convert_succeed=Конверсията към редовно хранилище е извършена успешно.
|
||||
settings.transfer=Прехвърли притежание
|
||||
settings.transfer_desc=Прехвърля това хранилище на друг потребител или към организация, в която имате права на администратор.
|
||||
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
|
||||
settings.delete=Изтриване на това хранилище
|
||||
settings.delete_desc=След като изтриете хранилището, няма връщане назад. Моля, бъдете сигурни.
|
||||
settings.transfer_notices_1=- Вие ще загубите достъп, ако новият притежател е индивидуален потребител.
|
||||
settings.transfer_notices_2=- Вие ще запазите достъпа си, ако новият притежател е организация и ако вие сте един от притежателите ѝ.
|
||||
settings.transfer_form_title=Моля въведете следната информация за да потвърдите операцията:
|
||||
settings.wiki_delete=Изтриване на данни на уики
|
||||
settings.wiki_delete_desc=След като изтриете данни за уики, няма връщане назад. Моля, бъдете сигурни.
|
||||
settings.wiki_delete_notices_1=- Това ще изтрие и ще деактивира уики за %s
|
||||
settings.wiki_deletion_success=Данните за уики на това хранилище са изтрити успешно.
|
||||
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_2=- Тази операция ще изтрие всичко от това хранилище, включително Git данни, задачи, коментари и достъпа на сътрудници.
|
||||
settings.delete_notices_fork_1=- All forks will become independent after deletion.
|
||||
settings.deletion_success=Хранилището е изтрито успешно!
|
||||
settings.update_settings_success=Настройките на хранилището са запазени успешно.
|
||||
settings.transfer_owner=Нов притежател
|
||||
settings.make_transfer=Прехвърли
|
||||
@@ -565,14 +615,21 @@ settings.transfer_succeed=Притежанието на хранилището
|
||||
settings.confirm_delete=Потвърди изтриването
|
||||
settings.add_collaborator=Добави нов сътрудник
|
||||
settings.add_collaborator_success=Добавен е нов сътрудник.
|
||||
settings.delete_collaborator=Премахни
|
||||
settings.collaborator_deletion=Премахване на сътрудник
|
||||
settings.collaborator_deletion_desc=Този потребител няма да има достъп на сътрудник до хранилището след изтриването. Желаете ли да продължите?
|
||||
settings.remove_collaborator_success=Сътрудникът е премахнат.
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.user_is_org_member=Потребителят е член на организацията и не може да бъде добавен като сътрудник.
|
||||
settings.search_user_placeholder=Име на потребител...
|
||||
settings.org_not_allowed_to_be_collaborator=Невъзможно добавяне на организация като сътрудник.
|
||||
settings.user_is_org_member=Потребителят вече участва в организацията и не може да бъде добавен като сътрудник.
|
||||
settings.add_webhook=Добави уеб-кука
|
||||
settings.hooks_desc=Уеб-куките много приличат на обикновен HTTP POST тригер. Когато нещо се случи в Gogs, ние ще изпратим уведомление до сървъра, който посочите. Научете повече в <a target="_blank" href="%s">Ръководство за уеб-куки</a>.
|
||||
settings.webhook_deletion=Изтрий уеб-кука
|
||||
settings.webhook_deletion_desc=При изтриване на тази уеб-кука ще се премахне информацията за нея и цялата хронология на нейното изпращане. Желаете ли да продължите?
|
||||
settings.webhook_deletion_success=Уеб-куката е изтрита успешно!
|
||||
settings.webhook.test_delivery=Тестово изпращане
|
||||
settings.webhook.test_delivery_desc=Симулира тестово изпращане за тест на настройките на уеб-куката
|
||||
settings.webhook.test_delivery_success=Тестовата уеб-кука е добавена в опашката за изпращане. Може да отнеме няколко секунди преди да се появи в историята с доставени.
|
||||
settings.webhook.request=Заявка
|
||||
settings.webhook.response=Отговор
|
||||
settings.webhook.headers=Заглавки
|
||||
@@ -582,7 +639,7 @@ settings.githooks_desc=Git куките се изпълняват от Git. Ви
|
||||
settings.githook_edit_desc=Ако куката е неактивна, ще бъде представено примерно съдържание. Ако оставите съдържанието празно, то тази кука ще бъде изключена.
|
||||
settings.githook_name=Име на куката
|
||||
settings.githook_content=Съдържание на куката
|
||||
settings.update_githook=Обнови куката
|
||||
settings.update_githook=Запази куката
|
||||
settings.add_webhook_desc=Gogs ще изпрати <code>POST</code> заявка към указания URL адрес заедно с информация за събитието, което е настъпило. Също можете да укажете в какъв формат желаете да получите данните при задействане на куката (JSON, x-www-form-urlencoded, XML) и др. Допълнително описание можете да намерите в нашето <a target="_blank" href="%s">Ръководство за уеб-куки</a>.
|
||||
settings.payload_url=URL адрес на изпращане
|
||||
settings.content_type=Тип на съдържанието
|
||||
@@ -601,17 +658,18 @@ settings.event_push_desc=Git предаване към хранилището
|
||||
settings.active=Активна
|
||||
settings.active_helper=Подробности относно събитието, което е задействало куката, също ще бъдат изпратени.
|
||||
settings.add_hook_success=Новата уеб-кука е добавена успешно.
|
||||
settings.update_webhook=Обнови уеб-куката
|
||||
settings.update_webhook=Запази уеб-куката
|
||||
settings.update_hook_success=Уеб-куката е запазена успешно.
|
||||
settings.delete_webhook=Изтрий уеб-куката
|
||||
settings.recent_deliveries=Последни изпращания
|
||||
settings.hook_type=Тип на куката
|
||||
settings.add_slack_hook_desc=Добавяне на интеграция със <a href="%s">Slack</a> във Вашето хранилище.
|
||||
settings.slack_token=Токен
|
||||
settings.slack_token=API ключ
|
||||
settings.slack_domain=Домейн
|
||||
settings.slack_channel=Канал
|
||||
settings.deploy_keys=Ключове за внедряване
|
||||
settings.add_deploy_key=Добави ключ за внедряване
|
||||
settings.deploy_key_desc=Този ключ за внедряване има права само за четене. Това не е същото като SSH ключове на персонален потребител.
|
||||
settings.no_deploy_keys=Все още няма настроен никакъв ключ за внедряване.
|
||||
settings.title=Заглавие
|
||||
settings.deploy_key_content=Съдържание
|
||||
@@ -622,56 +680,60 @@ settings.deploy_key_deletion=Изтрий ключ за внедряване
|
||||
settings.deploy_key_deletion_desc=При изтриването на този ключ за внедряване ще се премахнат свързаните права за достъп до това хранилище. Желаете ли да продължите?
|
||||
settings.deploy_key_deletion_success=Ключът за внедряване е изтрит успешно!
|
||||
|
||||
diff.browse_source=Преглед на кода
|
||||
diff.browse_source=Преглед на файлове
|
||||
diff.parent=родител
|
||||
diff.commit=ревизия
|
||||
diff.data_not_available=Няма данни за разлики.
|
||||
diff.show_diff_stats=Покажи статистика за разликите
|
||||
diff.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.view_file=Целия файл
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=Издания
|
||||
release.new_release=Ново издание
|
||||
release.releases=Версии
|
||||
release.new_release=Нова версия
|
||||
release.draft=Чернови
|
||||
release.prerelease=Предварителни
|
||||
release.stable=Стабилни
|
||||
release.edit=редактиране
|
||||
release.ahead=<strong>%d</strong> ревизии на %s след това издание
|
||||
release.ahead=<strong>%d</strong> ревизии на %s след тази версия
|
||||
release.source_code=Изходен код
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=Публикувайте версия на всяка нова итерация.
|
||||
release.edit_subheader=Подробният журнал на промените ще помогне на потребителите да разберат какви подобрения са направени.
|
||||
release.tag_name=Име на маркера
|
||||
release.target=Цел
|
||||
release.tag_helper=Изберете съществуващ маркер или създайте нов маркер по време на публикуване.
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.write=Писане
|
||||
release.title=Заглавие
|
||||
release.content=Съдържание
|
||||
release.write=Редактор
|
||||
release.preview=Преглед
|
||||
release.loading=Зареждане...
|
||||
release.prerelease_desc=Това е предварително издание
|
||||
release.prerelease_helper=Ние ще отбележим, че това издание не е завършено за употреба.
|
||||
release.cancel=Cancel
|
||||
release.publish=Публикувай издание
|
||||
release.prerelease_desc=Това е предварителна версия
|
||||
release.prerelease_helper=Ние ще отбележим, че тази версия не е готова за продукционна употреба.
|
||||
release.cancel=Отказ
|
||||
release.publish=Публикувай версия
|
||||
release.save_draft=Запис на чернова
|
||||
release.edit_release=Редактирай издание
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.tag_name_already_exist=Издание с това име на маркер вече съществува.
|
||||
release.downloads=Downloads
|
||||
release.edit_release=Редактирай версия
|
||||
release.delete_release=Изтриване на тази версия
|
||||
release.deletion=Изтрий версията
|
||||
release.deletion_desc=При изтриване на тази версия ще се премахне и съответния Git маркер. Желаете ли да продължите?
|
||||
release.deletion_success=Версията беше изтрита успешно!
|
||||
release.tag_name_already_exist=Версия с това име на маркер вече съществува.
|
||||
release.downloads=Изтегляния
|
||||
|
||||
[org]
|
||||
org_name_holder=Име на организацията
|
||||
org_full_name_holder=Пълно име на организацията
|
||||
org_name_helper=Добрите имена на организация са кратки и запомнящи се.
|
||||
org_name_helper=Доброто име на организация обикновено е кратко и запомнящо се.
|
||||
create_org=Създай организация
|
||||
repo_updated=Обновено
|
||||
people=Хора
|
||||
repo_updated=Последна модификация
|
||||
people=Участници
|
||||
invite_someone=Поканете някого
|
||||
teams=Екипи
|
||||
lower_members=членове
|
||||
lower_members=участници
|
||||
lower_repositories=хранилища
|
||||
create_new_team=Създай нов екип
|
||||
org_desc=Описание
|
||||
@@ -689,7 +751,7 @@ settings.options=Опции
|
||||
settings.full_name=Пълно име
|
||||
settings.website=Уебсайт
|
||||
settings.location=Локация
|
||||
settings.update_settings=Обнови настройките
|
||||
settings.update_settings=Запази настройките
|
||||
settings.update_setting_success=Настройките на организацията са запазени успешно.
|
||||
settings.change_orgname_prompt=Този промяна ще засегне всички връзки сочещи към организацията.
|
||||
settings.update_avatar_success=Настройките на аватара на организацията са запазени успешно.
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=Изтрий организацията
|
||||
settings.delete_org_desc=Тази организация ще бъде окончателно изтрита. Желаете ли да продължите?
|
||||
settings.hooks_desc=Добави уеб-куки, които ще бъдат използвани от <strong>всички хранилища</strong> в тази организация.
|
||||
|
||||
members.membership_visibility=Видимост:
|
||||
members.public=Публични
|
||||
members.public_helper=направи частен
|
||||
members.private=Частни
|
||||
members.private_helper=направи публичен
|
||||
members.member_role=Роля:
|
||||
members.owner=Притежател
|
||||
members.member=Участник
|
||||
members.conceal=Прикриване
|
||||
members.remove=Премахни
|
||||
members.leave=Напусни
|
||||
members.invite_desc=Започнете да пишете потребителското име, за да поканите член в %s:
|
||||
members.invite_desc=Добави нов участник в %s:
|
||||
members.invite_now=Покани
|
||||
|
||||
teams.join=Присъедини се
|
||||
@@ -724,17 +787,18 @@ teams.admin_access_helper=Този екип ще може да добавя ко
|
||||
teams.no_desc=Този екип няма описание
|
||||
teams.settings=Настройки
|
||||
teams.owners_permission_desc=Притежателите имат пълен достъп до <strong>всички хранилища</strong> и имат <strong>права на администратори</strong> на организацията.
|
||||
teams.members=Членовете на екипа
|
||||
teams.update_settings=Обнови настройките
|
||||
teams.members=Участници в екипа
|
||||
teams.update_settings=Запази настройките
|
||||
teams.delete_team=Изтриване на този екип
|
||||
teams.add_team_member=Добави член на екипа
|
||||
teams.add_team_member=Добави участник в екипа
|
||||
teams.delete_team_title=Изтрий екипа
|
||||
teams.delete_team_desc=Тъй като този екип ще бъдат изтрит, членовете му може да загубят достъп до някои хранилища. Желаете ли да продължите?
|
||||
teams.delete_team_desc=Тъй като този екип ще бъдат изтрит, участниците му може да загубят достъп до някои хранилища. Желаете ли да продължите?
|
||||
teams.delete_team_success=Този екип е бил изтрит успешно.
|
||||
teams.read_permission_desc=Този екип предоставя достъп за <strong>четене</strong>: членове могат да разглеждат и клонират хранилищата на екипа.
|
||||
teams.write_permission_desc=Този екип предоставя достъп за <strong>писане</strong>: членовете могат да четат от и предават към хранилищата на екипа.
|
||||
teams.admin_permission_desc=Този екип предоставя <strong>администраторски</strong> достъп: членовете могат да четат от, да предават към и да добавя нови сътрудници към хранилищата на екипа.
|
||||
teams.read_permission_desc=Този екип предоставя достъп за <strong>четене</strong>: участниците могат да разглеждат и клонират хранилищата на този екип.
|
||||
teams.write_permission_desc=Този екип предоставя достъп за <strong>писане</strong>: участниците могат да четат от и да предават към хранилищата на този екип.
|
||||
teams.admin_permission_desc=Този екип предоставя <strong>администраторски</strong> достъп: участниците могат да четат от, да предават към и да добавя нови сътрудници към хранилищата на този екип.
|
||||
teams.repositories=Хранилища на екипа
|
||||
teams.search_repo_placeholder=Име на хранилище...
|
||||
teams.add_team_repository=Добави хранилище на екипа
|
||||
teams.remove_repo=Премахни
|
||||
teams.add_nonexistent_repo=Хранилището, което се опитвате да добавите не съществува. Моля първо го създайте!
|
||||
@@ -755,7 +819,7 @@ total=Общо: %d
|
||||
dashboard.statistic=Статистика
|
||||
dashboard.operations=Операции
|
||||
dashboard.system_status=Наблюдение на системния статус
|
||||
dashboard.statistic_info=Gogs базата данни има <b>%d</b> потребители, <b>%d</b> организации, <b>%d</b> публични ключове, <b>%d</b> хранилища, <b>%d</b> наблюдавания, <b>%d</b> харесвания, <b>%d</b> действия, <b>%d</b> достъпи, <b>%d</b> проблеми, <b>%d</b> коментари, <b>%d</b> социални регистрации, <b>%d</b> последователи, <b>%d</b> огледала, <b>%d</b> издания, <b>%d</b> източници за вписване, <b>%d</b> уеб-куки, <b>%d</b> етапи, <b>%d</b> етикети, <b>%d</b> задачи на куки, <b>%d</b> екипи, <b>%d</b> задачи при актуализация, <b>%d</b> прикачени файлове.
|
||||
dashboard.statistic_info=Gogs базата данни има <b>%d</b> потребители, <b>%d</b> организации, <b>%d</b> публични ключове, <b>%d</b> хранилища, <b>%d</b> наблюдавания, <b>%d</b> харесвания, <b>%d</b> действия, <b>%d</b> достъпи, <b>%d</b> задачи, <b>%d</b> коментари, <b>%d</b> социални регистрации, <b>%d</b> последователи, <b>%d</b> огледала, <b>%d</b> версии, <b>%d</b> начини на удостоверяване, <b>%d</b> уеб-куки, <b>%d</b> етапи, <b>%d</b> етикети, <b>%d</b> задачи на куки, <b>%d</b> екипи, <b>%d</b> задачи при актуализация, <b>%d</b> прикачени файлове.
|
||||
dashboard.operation_name=Име на операцията
|
||||
dashboard.operation_switch=Превключи
|
||||
dashboard.operation_run=Изпълни
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=Изтрий всички неактивн
|
||||
dashboard.delete_inactivate_accounts_success=Всички неактивни профили са изтрити успешно.
|
||||
dashboard.delete_repo_archives=Изтрий всички архиви на хранилища
|
||||
dashboard.delete_repo_archives_success=Всички архиви на хранилищата са изтрити успешно.
|
||||
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=Изтрий всички записи за хранилища, за които липсват Git файлове
|
||||
dashboard.delete_missing_repos_success=Всички записи за хранилища, за които липсват съответни Git файлове са изтрити успешно.
|
||||
dashboard.git_gc_repos=Почисти изтрити данни в хранилищата
|
||||
dashboard.git_gc_repos_success=Всички хранилища са почистени от изтрити данни успешно.
|
||||
dashboard.resync_all_sshkeys=Презапис на ".ssh/authorized_keys" файл (внимание: не-Gogs ключове ще бъдат загубени)
|
||||
dashboard.resync_all_sshkeys_success=Всички публични ключове са презаписани успешно.
|
||||
dashboard.resync_all_update_hooks=Презапис на всички куки, закачени на актуализация на хранилищата (необходимо, когато се ползва собствен път за конфигурацията)
|
||||
dashboard.resync_all_update_hooks_success=Всички куки, закачени на актуализация на хранилищата, са презаписани успешно.
|
||||
dashboard.reinit_missing_repos=Реинициализира всички записи за хранилища
|
||||
dashboard.reinit_missing_repos_success=Всички записи за хранилища със загубени Git файлове са реинициализирани успешно.
|
||||
|
||||
dashboard.server_uptime=Операционно време
|
||||
dashboard.current_goroutine=Текущи Goroutines
|
||||
@@ -814,56 +880,62 @@ users.created=Създаване
|
||||
users.send_register_notify=Прати уведомление на потребителя при регистрация
|
||||
users.new_success=Новият профил '%s' е добавен успешно.
|
||||
users.edit=Редакция
|
||||
users.auth_source=Източник за удостоверяване
|
||||
users.auth_source=Начин на удостоверяване
|
||||
users.local=Локално
|
||||
users.auth_login_name=Потребителско име за удостоверяване
|
||||
users.auth_login_name=Потребителско име за вход
|
||||
users.password_helper=Оставете празна ако не се променя.
|
||||
users.update_profile_success=Профилът е запазен успешно.
|
||||
users.edit_account=Редактирай профил
|
||||
users.max_repo_creation=Макс. брой хранилища
|
||||
users.max_repo_creation_desc=(Задайте -1 за да се използва глобалния лимит)
|
||||
users.is_activated=Този профил е активиран
|
||||
users.is_admin=Този профил има административни права
|
||||
users.allow_git_hook=Този профил има разрешение да създава Git куки
|
||||
users.allow_import_local=Този профил има права за импорт на локални хранилища
|
||||
users.update_profile=Обнови профила
|
||||
users.update_profile=Запази профила
|
||||
users.delete_account=Изтрий този профил
|
||||
users.still_own_repo=Този профил притежава поне едно хранилище. Първо трябва да изтриете хранилището или да го прехвърлите на друг потребител.
|
||||
users.still_has_org=Този профил е член на поне една организация. Първо трябва да напуснете или изтриете тези организации.
|
||||
users.still_has_org=Този профил участва в поне една организация. Първо трябва да напуснете или изтриете тези организации.
|
||||
users.deletion_success=Профилът е изтрит успешно!
|
||||
|
||||
orgs.org_manage_panel=Управление на организацията
|
||||
orgs.name=Име
|
||||
orgs.teams=Екипи
|
||||
orgs.members=Членове
|
||||
orgs.members=Участници
|
||||
|
||||
repos.repo_manage_panel=Управление на хранилището
|
||||
repos.owner=Притежател
|
||||
repos.name=Име
|
||||
repos.private=Лично
|
||||
repos.private=Частно
|
||||
repos.watches=Наблюдавания
|
||||
repos.stars=Харесвания
|
||||
repos.issues=Проблеми
|
||||
repos.issues=Задачи
|
||||
|
||||
auths.auth_manage_panel=Управление на удостоверявания
|
||||
auths.new=Добави нов източник за удостоверяване
|
||||
auths.new=Добави нов начин на удостоверяване
|
||||
auths.name=Име
|
||||
auths.type=Тип
|
||||
auths.enabled=Активен
|
||||
auths.updated=Обновен
|
||||
auths.enabled=Активно
|
||||
auths.updated=Последна модификация
|
||||
auths.auth_type=Тип на удостоверяване
|
||||
auths.auth_name=Име на удостоверяване
|
||||
auths.security_protocol=Security Protocol
|
||||
auths.domain=Домейн
|
||||
auths.host=Сървър
|
||||
auths.port=Порт
|
||||
auths.bind_dn=Име (DN) за свръзка
|
||||
auths.bind_password=Парола за свръзка
|
||||
auths.bind_password_helper=Внимание: Тази парола се запазва некриптирана. Моля използвайте потребител, който няма административен достъп.
|
||||
auths.user_base=База с потребители
|
||||
auths.user_base=Базов OU за търсене
|
||||
auths.user_dn=Име (DN) на потребител
|
||||
auths.attribute_username=Атрибут за име
|
||||
auths.attribute_username_placeholder=Оставете празно за да използва потребителското име от форма за вписване.
|
||||
auths.attribute_name=Атрибут за име
|
||||
auths.attribute_surname=Атрибут за фамилия
|
||||
auths.attribute_mail=Атрибут за ел. поща
|
||||
auths.filter=Филтър за потребители
|
||||
auths.admin_filter=Филтър за администратори
|
||||
auths.attributes_in_bind=Извличане на атрибути от контекста на име (DN) за свръзка
|
||||
auths.filter=Филтър за потребител
|
||||
auths.admin_filter=Филтър за администратор
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP удостоверяване
|
||||
auths.smtphost=SMTP сървър
|
||||
@@ -871,7 +943,7 @@ auths.smtpport=SMTP порт
|
||||
auths.allowed_domains=Разрешени домейни
|
||||
auths.allowed_domains_helper=Оставете празно за да не се ограничават домейните. За множество домейни използвайте запетая за разделител.
|
||||
auths.enable_tls=Включи TLS криптиране
|
||||
auths.skip_tls_verify=Пропусни проверка на TLS
|
||||
auths.skip_tls_verify=Пропусни проверка на TLS сертификат
|
||||
auths.pam_service_name=Име на PAM услуга
|
||||
auths.enable_auto_register=Включи автоматична регистрация
|
||||
auths.tips=Съвети
|
||||
@@ -879,10 +951,11 @@ auths.edit=Редактирай настройки за удостоверява
|
||||
auths.activated=Това удостоверяване е активно
|
||||
auths.new_success=Новото удостоверяване '%s' е добавено успешно.
|
||||
auths.update_success=Настройките за удостоверяване са запазени успешно.
|
||||
auths.update=Обнови настройки за удостоверяване
|
||||
auths.update=Запази настройки за удостоверяване
|
||||
auths.delete=Изтриване на това удостоверяване
|
||||
auths.delete_auth_title=Изтрий удостоверяването
|
||||
auths.delete_auth_desc=Това удостоверяване ще бъде изтрито. Желаете ли да продължите?
|
||||
auths.still_in_used=Това удостоверяване все още се използва от някои потребители. Моля изтрийте ги или ги конвертирайте до друг тип на влизане първо.
|
||||
auths.deletion_success=Удостоверяването е изтрито успешно!
|
||||
|
||||
config.server_config=Сървърни настройки
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Път към статични файлове
|
||||
config.log_file_root_path=Път към журнал
|
||||
config.script_type=Тип на скрипта
|
||||
config.reverse_auth_user=Потребителско име при обратно удостоверяване
|
||||
|
||||
config.ssh_config=SSH конфигурация
|
||||
config.ssh_enabled=Активен
|
||||
config.ssh_start_builtin_server=Стартирай вграден сървър
|
||||
config.ssh_domain=Домейн
|
||||
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=Тип
|
||||
config.db_host=Сървър
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=Изисквай потвърждение на а
|
||||
config.disable_register=Изключи нови регистрации
|
||||
config.show_registration_button=Покажи бутон за регистрация
|
||||
config.require_sign_in_view=Изисквай вписване за преглед
|
||||
config.enable_cache_avatar=Включи кеширане на аватари
|
||||
config.mail_notify=Уведомяване по ел. поща
|
||||
config.disable_key_size_check=Изключи проверка минимален размер на ключ
|
||||
config.enable_captcha=Включи Captcha
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Изключи HELO
|
||||
config.mailer_name=Име
|
||||
config.mailer_host=Сървър
|
||||
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=Конфигурация на кеша
|
||||
@@ -962,23 +1050,34 @@ monitor.start=Начален час
|
||||
monitor.execute_time=Време за изпълнение
|
||||
|
||||
notices.system_notice_list=Системни известия
|
||||
notices.view_detail_header=Преглед на детайли на съобщение
|
||||
notices.actions=Действия
|
||||
notices.select_all=Избери всички
|
||||
notices.deselect_all=Без избрани
|
||||
notices.inverse_selection=Обърни избора
|
||||
notices.delete_selected=Изтрий избраните
|
||||
notices.delete_all=Изтрий всички съобщения
|
||||
notices.type=Тип
|
||||
notices.type_1=Хранилище
|
||||
notices.desc=Описание
|
||||
notices.op=Oп.
|
||||
notices.delete_success=Системното съобщение е изтрито успешно.
|
||||
notices.delete_success=Системните съобщения са изтрити успешно.
|
||||
|
||||
[action]
|
||||
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/src/%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`отвори проблем <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
create_issue=`отвори задача <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
close_issue=`затвори <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`повторно отвори <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`създаде заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`коментира проблем <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
close_pull_request=`затвори заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
reopen_pull_request=`повторно отвори заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`коментира задача <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
merge_pull_request=`обедини заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=прехвърли хранилище <code>%s</code> към <a href="%s">%s</a>
|
||||
push_tag=предаде маркер <a href="%s/src/%s">%[2]s</a> към <a href="%[1]s">[3]s</a>
|
||||
compare_2_commits=Сравнение между тези 2 ревизии
|
||||
compare_commits=Сравнение между тези %d ревизии
|
||||
|
||||
[tool]
|
||||
ago=преди
|
||||
@@ -1002,7 +1101,7 @@ raw_seconds=секунди
|
||||
raw_minutes=минути
|
||||
|
||||
[dropzone]
|
||||
default_message=Пуснете файлове тук или щракнете за качване.
|
||||
default_message=Тук пуснете файлове с влачене или просто щракнете за избор на файл за качване.
|
||||
invalid_input_type=Невъзможно качване на файловете от този тип.
|
||||
file_too_big=Размер на файла ({{filesize}} MB) надвишава максималния размер ({{maxFilesize}} MB).
|
||||
remove_file=Премахни файл
|
||||
|
||||
1108
conf/locale/locale_cs-CZ.ini
Normal file
1108
conf/locale/locale_cs-CZ.ini
Normal file
File diff suppressed because it is too large
Load Diff
813
conf/locale/locale_de-DE.ini
Executable file → Normal file
813
conf/locale/locale_de-DE.ini
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ user_profile_and_more = User profile and more
|
||||
signed_in_as = Signed in as
|
||||
|
||||
username = Username
|
||||
email = E-mail
|
||||
email = Email
|
||||
password = Password
|
||||
re_type = Re-Type
|
||||
captcha = Captcha
|
||||
@@ -28,6 +28,7 @@ organization = Organization
|
||||
mirror = Mirror
|
||||
new_repo = New Repository
|
||||
new_migrate = New Migration
|
||||
new_mirror = New Mirror
|
||||
new_fork = New Fork Repository
|
||||
new_org = New Organization
|
||||
manage_org = Manage Organizations
|
||||
@@ -37,19 +38,12 @@ settings = Settings
|
||||
your_profile = Your Profile
|
||||
your_settings = Your Settings
|
||||
|
||||
news_feed = News Feed
|
||||
activities = Activities
|
||||
pull_requests = Pull Requests
|
||||
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
|
||||
@@ -64,7 +58,7 @@ db_name = Database Name
|
||||
db_helper = Please use INNODB engine with utf8_general_ci charset for MySQL.
|
||||
ssl_mode = SSL Mode
|
||||
path = Path
|
||||
sqlite_helper = The file path of SQLite3 or TiDB database.
|
||||
sqlite_helper = The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path = SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name = TiDB database name does not allow characters "." and "-".
|
||||
no_admin_and_disable_registration = You cannot disable registration without creating an admin account.
|
||||
@@ -84,14 +78,16 @@ ssh_port_helper = Port number which your SSH server is using, leave it empty to
|
||||
http_port = HTTP Port
|
||||
http_port_helper = Port number which application will listen on.
|
||||
app_url = Application URL
|
||||
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail.
|
||||
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in email.
|
||||
log_root_path = Log Path
|
||||
log_root_path_helper = Directory to write log files to.
|
||||
|
||||
optional_title = Optional Settings
|
||||
email_title = E-mail Service Settings
|
||||
email_title = Email Service Settings
|
||||
smtp_host = SMTP Host
|
||||
smtp_from = From
|
||||
smtp_from_helper = Mail from address, RFC 5322. It can be just an email address, or the "Name" <email@example.com> format.
|
||||
mailer_user = Sender E-mail
|
||||
mailer_user = Sender Email
|
||||
mailer_password = Sender Password
|
||||
register_confirm = Enable Register Confirmation
|
||||
mail_notify = Enable Mail Notification
|
||||
@@ -111,7 +107,7 @@ admin_title = Admin Account Settings
|
||||
admin_name = Username
|
||||
admin_password = Password
|
||||
confirm_password = Confirm Password
|
||||
admin_email = Admin E-mail
|
||||
admin_email = Admin Email
|
||||
install_gogs = Install Gogs
|
||||
test_git_failed = Fail to test 'git' command: %v
|
||||
sqlite3_not_available = Your release version does not support SQLite3, please download the official binary version from %s, NOT the gobuild version.
|
||||
@@ -121,9 +117,10 @@ run_user_not_match = Run user isn't the current user: %s -> %s
|
||||
save_config_failed = Fail to save configuration: %v
|
||||
invalid_admin_setting = Admin account setting is invalid: %v
|
||||
install_success = Welcome! We're glad that you chose Gogs, have fun and take care.
|
||||
invalid_log_root_path = Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder = Username or E-mail
|
||||
uname_holder = Username or email
|
||||
password_holder = Password
|
||||
switch_dashboard_context = Switch Dashboard Context
|
||||
my_repos = My Repositories
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos = In your repositories
|
||||
|
||||
[explore]
|
||||
repos = Repositories
|
||||
users = Users
|
||||
search = Search
|
||||
|
||||
[auth]
|
||||
create_new_account = Create New Account
|
||||
@@ -147,23 +146,26 @@ remember_me = Remember Me
|
||||
forgot_password= Forgot Password
|
||||
forget_password = Forgot password?
|
||||
sign_up_now = Need an account? Sign up now.
|
||||
confirmation_mail_sent_prompt = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the registration process.
|
||||
confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the registration process.
|
||||
active_your_account = Activate Your Account
|
||||
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 e-mail address (<b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below.
|
||||
resend_mail = Click here to resend your activation e-mail
|
||||
email_not_associate = This e-mail address is not associated with any account.
|
||||
send_reset_mail = Click here to (re)send your password reset e-mail
|
||||
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
|
||||
resend_mail = Click here to resend your activation email
|
||||
email_not_associate = This email address is not associated with any account.
|
||||
send_reset_mail = Click here to (re)send your password reset email
|
||||
reset_password = Reset Your Password
|
||||
invalid_code = Sorry, your confirmation code has expired or not valid.
|
||||
reset_password_helper = Click here to reset your password
|
||||
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
|
||||
activate_email = Verify your e-mail address
|
||||
activate_email = Verify your email address
|
||||
reset_password = Reset your password
|
||||
register_success = Register success, Welcome
|
||||
register_success = Registration successful, welcome
|
||||
register_notify = Welcome on board
|
||||
|
||||
[modal]
|
||||
@@ -174,7 +176,7 @@ modify = Modify
|
||||
[form]
|
||||
UserName = Username
|
||||
RepoName = Repository name
|
||||
Email = E-mail address
|
||||
Email = Email address
|
||||
Password = Password
|
||||
Retype = Re-type password
|
||||
SSHTitle = SSH key name
|
||||
@@ -182,7 +184,7 @@ HttpsUrl = HTTPS URL
|
||||
PayloadUrl = Payload URL
|
||||
TeamName = Team name
|
||||
AuthName = Authorization name
|
||||
AdminEmail = Admin E-mail
|
||||
AdminEmail = Admin email
|
||||
|
||||
require_error = ` cannot be empty.`
|
||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
||||
@@ -190,19 +192,18 @@ alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot chara
|
||||
size_error = ` must be size %s.`
|
||||
min_size_error = ` must contain at least %s characters.`
|
||||
max_size_error = ` must contain at most %s characters.`
|
||||
email_error = ` is not a valid e-mail address.`
|
||||
email_error = ` is not a valid email address.`
|
||||
url_error = ` is not a valid URL.`
|
||||
include_error = ` must contain substring '%s'.`
|
||||
unknown_error = Unknown error:
|
||||
captcha_incorrect = Captcha didn't match.
|
||||
password_not_match = Password and confirm password are not same.
|
||||
|
||||
username_been_taken = Username has been already taken.
|
||||
repo_name_been_taken = Repository name has been already taken.
|
||||
org_name_been_taken = Organization name has been already taken.
|
||||
team_name_been_taken = Team name has been already taken.
|
||||
email_been_used = E-mail address has been already used.
|
||||
illegal_team_name = Team name contains illegal characters.
|
||||
username_been_taken = Username has already been taken.
|
||||
repo_name_been_taken = Repository name has already been taken.
|
||||
org_name_been_taken = Organization name has already been taken.
|
||||
team_name_been_taken = Team name has already been taken.
|
||||
email_been_used = Email address has already been used.
|
||||
username_password_incorrect = Username or password is not correct.
|
||||
enterred_invalid_repo_name = Please make sure that the repository name you entered is correct.
|
||||
enterred_invalid_owner_name = Please make sure that the owner name you entered is correct.
|
||||
@@ -216,21 +217,20 @@ auth_failed = Authentication failed: %v
|
||||
|
||||
still_own_repo = Your account still has ownership over at least one repository, you have to delete or transfer them first.
|
||||
still_has_org = Your account still has membership in at least one organization, you have to leave or delete your memberships first.
|
||||
org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first.
|
||||
|
||||
still_own_user = This authentication still is in use by at least one user, please remove them from the authentication and try again.
|
||||
org_still_own_repo = This organization still has ownership of repositories, you must delete or transfer them first.
|
||||
|
||||
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
|
||||
followers = Followers
|
||||
starred = Starred
|
||||
starred = Starred repositories
|
||||
following = Following
|
||||
follow = Follow
|
||||
unfollow = Unfollow
|
||||
|
||||
form.name_reserved = Username '%s' is reserved.
|
||||
form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
|
||||
@@ -246,7 +246,8 @@ delete = Delete Account
|
||||
uid = Uid
|
||||
|
||||
public_profile = Public Profile
|
||||
profile_desc = Your E-mail address is public and will be used for any account related notifications, and any web based operations made via the site.
|
||||
profile_desc = Your email address is public and will be used for any account related notifications, and any web based operations made via the site.
|
||||
password_username_disabled = Non-local type users are not allowed to change their username.
|
||||
full_name = Full Name
|
||||
website = Website
|
||||
location = Location
|
||||
@@ -258,11 +259,10 @@ continue = Continue
|
||||
cancel = Cancel
|
||||
|
||||
enable_custom_avatar = Enable Custom Avatar
|
||||
enable_custom_avatar_helper = Disable fetch from Gravatar
|
||||
choose_new_avatar = Choose new avatar
|
||||
update_avatar = Update Avatar Setting
|
||||
delete_current_avatar = Delete Current Avatar
|
||||
uploaded_avatar_not_a_image = Uploaded file is not a image.
|
||||
no_custom_avatar_available = No custom avatar available, cannot enable it.
|
||||
update_avatar_success = Your avatar setting has been updated successfully.
|
||||
|
||||
change_password = Change Password
|
||||
@@ -271,28 +271,29 @@ new_password = New Password
|
||||
retype_new_password = Retype New Password
|
||||
password_incorrect = Current password is not correct.
|
||||
change_password_success = Your password was successfully changed. You can now sign using this new password.
|
||||
password_change_disabled = Non-local type users are not allowed to change their password.
|
||||
|
||||
emails = E-mail Addresses
|
||||
manage_emails = Manage e-mail addresses
|
||||
email_desc = Your primary e-mail address will be used for notifications and other operations.
|
||||
emails = Email Addresses
|
||||
manage_emails = Manage email addresses
|
||||
email_desc = Your primary email address will be used for notifications and other operations.
|
||||
primary = Primary
|
||||
primary_email = Set as primary
|
||||
delete_email = Delete
|
||||
email_deletion = E-mail Deletion
|
||||
email_deletion_desc = Delete this e-mail address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success = E-mail has been deleted successfully!
|
||||
add_new_email = Add new e-mail address
|
||||
add_email = Add e-mail
|
||||
add_email_confirmation_sent = A new confirmation e-mail has been sent to '%s', please check your inbox within the next %d hours to complete the confirmation process.
|
||||
add_email_success = Your new E-mail address was successfully added.
|
||||
email_deletion = Email Deletion
|
||||
email_deletion_desc = Deleting this email address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success = Email has been deleted successfully!
|
||||
add_new_email = Add new email address
|
||||
add_email = Add email
|
||||
add_email_confirmation_sent = A new confirmation email has been sent to '%s', please check your inbox within the next %d hours to complete the confirmation process.
|
||||
add_email_success = Your new email address was successfully added.
|
||||
|
||||
manage_ssh_keys = Manage SSH Keys
|
||||
add_key = Add Key
|
||||
ssh_desc = This is a list of SSH keys associated with your account. As these keys allow anyone using them to gain access to your repositories, it is highly important that you make sure you recognize them.
|
||||
ssh_helper = <strong>Don't know how?</strong> Check out GitHub's guide to <a href="%s">create your own SSH keys</a> or solve <a href="%s">common problems</a> you might encounter using SSH.
|
||||
add_new_key = Add SSH Key
|
||||
ssh_key_been_used = Public key content has been used.
|
||||
ssh_key_name_used = Public key with same name has already existed.
|
||||
ssh_key_been_used = Public key content has been used.
|
||||
ssh_key_name_used = Public key with same name has already existed.
|
||||
key_name = Key Name
|
||||
key_content = Content
|
||||
add_key_success = New SSH key '%s' has been added successfully!
|
||||
@@ -351,11 +352,16 @@ 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.
|
||||
watchers = Watchers
|
||||
stargazers = Stargazers
|
||||
forks = Forks
|
||||
|
||||
form.reach_limit_of_creation = The owner has reached maximum creation limit of %d repositories.
|
||||
form.name_reserved = Repository name '%s' is reserved.
|
||||
form.name_pattern_not_allowed = Repository name pattern '%s' is not allowed.
|
||||
|
||||
@@ -369,8 +375,9 @@ migrate.permission_denied = You are not allowed to import local repositories.
|
||||
migrate.invalid_local_path = Invalid local path, it does not exist or not a directory.
|
||||
migrate.failed = Migration failed: %v
|
||||
|
||||
mirror_from = mirror of
|
||||
forked_from = forked from
|
||||
fork_from_self = You cannot fork repository you already owned!
|
||||
fork_from_self = You cannot fork a repository you already own!
|
||||
copy_link = Copy
|
||||
copy_link_success = Copied!
|
||||
copy_link_error = Press ⌘-C or Ctrl-C to copy
|
||||
@@ -388,6 +395,7 @@ create_new_repo_command = Create a new repository on the command line
|
||||
push_exist_repo = Push an existing repository from the command line
|
||||
repo_is_empty = This repository is empty, please come back later!
|
||||
|
||||
code = Code
|
||||
branch = Branch
|
||||
tree = Tree
|
||||
filter_branch_and_tag = Filter branch or tag
|
||||
@@ -403,6 +411,7 @@ file_raw = Raw
|
||||
file_history = History
|
||||
file_view_raw = View Raw
|
||||
file_permalink = Permalink
|
||||
file_too_large = This file is too large to be shown
|
||||
|
||||
commits.commits = Commits
|
||||
commits.search = Search commits
|
||||
@@ -467,7 +476,7 @@ issues.closed_at = `closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at = `reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at = `referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster = Poster
|
||||
issues.admin = Admin
|
||||
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>
|
||||
@@ -482,8 +491,9 @@ issues.label_edit = Edit
|
||||
issues.label_delete = Delete
|
||||
issues.label_modify = Label Modification
|
||||
issues.label_deletion = Label Deletion
|
||||
issues.label_deletion_desc = Delete this label will remove its information in all related issues. Do you want to continue?
|
||||
issues.label_deletion_desc = Deleting this label will remove its information in all related issues. Do you want to continue?
|
||||
issues.label_deletion_success = Label has been deleted successfully!
|
||||
issues.num_participants = %d Participants
|
||||
|
||||
pulls.new = New Pull Request
|
||||
pulls.compare_changes = Compare Changes
|
||||
@@ -505,9 +515,9 @@ 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.is_checking = The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc = You can perform auto-merge operation on this pull request.
|
||||
pulls.cannot_auto_merge_desc = You can't perform auto-merge operation because there are conflicts between commits.
|
||||
pulls.cannot_auto_merge_helper = Please use command line tool to solve it.
|
||||
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.cannot_auto_merge_helper = Please merge manually in order to resolve the conflicts.
|
||||
pulls.merge_pull_request = Merge 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.`
|
||||
|
||||
@@ -515,7 +525,7 @@ milestones.new = New Milestone
|
||||
milestones.open_tab = %d Open
|
||||
milestones.close_tab = %d Closed
|
||||
milestones.closed = Closed %s
|
||||
milestones.no_due_date = No due date
|
||||
milestones.no_due_date = No due date
|
||||
milestones.open = Open
|
||||
milestones.close = Close
|
||||
milestones.new_subheader = Create milestones to organize your issues.
|
||||
@@ -527,37 +537,80 @@ milestones.clear = Clear
|
||||
milestones.invalid_due_date_format = Due date format is invalid, must be 'yyyy-mm-dd'.
|
||||
milestones.create_success = Milestone '%s' has been created successfully!
|
||||
milestones.edit = Edit Milestone
|
||||
milestones.edit_subheader = Use better description for milestones so people won't be confused.
|
||||
milestones.edit_subheader = Use a better description for milestones so people won't be confused.
|
||||
milestones.cancel = Cancel
|
||||
milestones.modify = Modify Milestone
|
||||
milestones.edit_success = Changes of milestone '%s' has been saved successfully!
|
||||
milestones.deletion = Milestone Deletion
|
||||
milestones.deletion_desc = Delete this milestone will remove its information in all related issues. Do you want to continue?
|
||||
milestones.deletion_desc = Deleting this milestone will remove its information in all related issues. Do you want to continue?
|
||||
milestones.deletion_success = Milestone has been deleted successfully!
|
||||
|
||||
wiki = Wiki
|
||||
wiki.welcome = Welcome to Wiki!
|
||||
wiki.welcome_desc = Wiki is the place where you would like to document your project together and make it better.
|
||||
wiki.create_first_page = Create the first page
|
||||
wiki.page = Page
|
||||
wiki.filter_page = Filter page
|
||||
wiki.new_page = Create New Page
|
||||
wiki.default_commit_message = Write a note about this update (optional).
|
||||
wiki.save_page = Save Page
|
||||
wiki.last_commit_info = %s edited this page %s
|
||||
wiki.edit_page_button = Edit
|
||||
wiki.new_page_button = New Page
|
||||
wiki.delete_page_button = Delete Page
|
||||
wiki.delete_page_notice_1 = This will delete the page <code>"%s"</code>. Please be certain.
|
||||
wiki.page_already_exists = Wiki page with same name already exists.
|
||||
wiki.pages = Pages
|
||||
wiki.last_updated = Last updated %s
|
||||
|
||||
settings = Settings
|
||||
settings.options = Options
|
||||
settings.collaboration = Collaboration
|
||||
settings.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.danger_zone = Danger Zone
|
||||
settings.site = Official Site
|
||||
settings.update_settings = Update Settings
|
||||
settings.change_reponame_prompt = This change will affect how links relate to the repository.
|
||||
settings.advanced_settings = Advanced Settings
|
||||
settings.wiki_desc = Enable wiki to allow people write documents
|
||||
settings.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.use_external_issue_tracker = Use external issue tracker
|
||||
settings.tracker_url_format = External Issue Tracker URL Format
|
||||
settings.tracker_issue_style = External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric = Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric = Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc = You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc = Enable pull requests to accept public contributions
|
||||
settings.danger_zone = Danger Zone
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
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.transfer = Transfer Ownership
|
||||
settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights.
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
settings.delete = Delete This Repository
|
||||
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
||||
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.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.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 be became independent after deletion.
|
||||
settings.delete_notices_fork_2 = - If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3 = - If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.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
|
||||
settings.make_transfer = Make Transfer
|
||||
@@ -565,14 +618,21 @@ settings.transfer_succeed = Repository ownership has been transferred successful
|
||||
settings.confirm_delete = Confirm Deletion
|
||||
settings.add_collaborator = Add New Collaborator
|
||||
settings.add_collaborator_success = New collaborator has been added.
|
||||
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.remove_collaborator_success = Collaborator has been removed.
|
||||
settings.search_user_placeholder = Search user...
|
||||
settings.org_not_allowed_to_be_collaborator = Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member = User is organization member who cannot be added as a collaborator.
|
||||
settings.add_webhook = Add Webhook
|
||||
settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in Gogs, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.webhook_deletion = Delete Webhook
|
||||
settings.webhook_deletion_desc = Delete this webhook will remove its information and all delivery history. Do you want to continue?
|
||||
settings.webhook_deletion_success = Webhook has been deleted successfully!
|
||||
settings.webhook.test_delivery = Test Delivery
|
||||
settings.webhook.test_delivery_desc = Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success = Test webhook has been added to delivery queue. It may take few seconds before it shows up in the delivery history.
|
||||
settings.webhook.request = Request
|
||||
settings.webhook.response = Response
|
||||
settings.webhook.headers = Headers
|
||||
@@ -612,14 +672,15 @@ settings.slack_domain = Domain
|
||||
settings.slack_channel = Channel
|
||||
settings.deploy_keys = Deploy Keys
|
||||
settings.add_deploy_key = Add Deploy Key
|
||||
settings.no_deploy_keys = You haven't added any 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 same name has already existed.
|
||||
settings.key_name_used = Deploy key with the same name already exists.
|
||||
settings.add_key_success = New deploy key '%s' has been added successfully!
|
||||
settings.deploy_key_deletion = Delete Deploy Key
|
||||
settings.deploy_key_deletion_desc = Delete this deploy key will remove all related accesses for this repository. Do you want to continue?
|
||||
settings.deploy_key_deletion_desc = Deleting this deploy key will remove all related accesses for this repository. Do you want to continue?
|
||||
settings.deploy_key_deletion_success = Deploy key has been deleted successfully!
|
||||
|
||||
diff.browse_source = Browse Source
|
||||
@@ -627,9 +688,13 @@ diff.parent = parent
|
||||
diff.commit = commit
|
||||
diff.data_not_available = Diff Data Not Available.
|
||||
diff.show_diff_stats = Show Diff Stats
|
||||
diff.show_split_view = Split View
|
||||
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
|
||||
@@ -650,16 +715,16 @@ release.write = Write
|
||||
release.preview = Preview
|
||||
release.loading = Loading...
|
||||
release.prerelease_desc = This is a pre-release
|
||||
release.prerelease_helper = We’ll point out that this release is not production-ready.
|
||||
release.prerelease_helper = We'll point out that this release is not production-ready.
|
||||
release.cancel = Cancel
|
||||
release.publish = Publish Release
|
||||
release.save_draft = Save Draft
|
||||
release.edit_release = Edit Release
|
||||
release.delete_release = Delete This Release
|
||||
release.deletion = Release Deletion
|
||||
release.deletion_desc = Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_desc = Deleting this release will delete the corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success = Release has been deleted successfully!
|
||||
release.tag_name_already_exist = Release with this tag name has already existed.
|
||||
release.tag_name_already_exist = Release with this tag name already exists.
|
||||
release.downloads = Downloads
|
||||
|
||||
[org]
|
||||
@@ -701,16 +766,17 @@ settings.delete_org_title = Organization Deletion
|
||||
settings.delete_org_desc = This organization is going to be deleted permanently, do you want to continue?
|
||||
settings.hooks_desc = Add webhooks that will be triggered for <strong>all repositories</strong> under this organization.
|
||||
|
||||
members.membership_visibility = Membership Visibility:
|
||||
members.public = Public
|
||||
members.public_helper = make private
|
||||
members.private = Private
|
||||
members.private_helper = make public
|
||||
members.member_role = Member Role:
|
||||
members.owner = Owner
|
||||
members.member = Member
|
||||
members.conceal = Conceal
|
||||
members.remove = Remove
|
||||
members.leave = Leave
|
||||
members.invite_desc = Start typing a username to invite a new member to %s:
|
||||
members.invite_desc = Add a new member to %s:
|
||||
members.invite_now = Invite Now
|
||||
|
||||
teams.join = Join
|
||||
@@ -735,6 +801,7 @@ teams.read_permission_desc = This team grants <strong>Read</strong> access: memb
|
||||
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
||||
teams.admin_permission_desc = This team grants <strong>Admin</strong> access: members can read from, push to, and add collaborators to the team's repositories.
|
||||
teams.repositories = Team Repositories
|
||||
teams.search_repo_placeholder = Search repository...
|
||||
teams.add_team_repository = Add Team Repository
|
||||
teams.remove_repo = Remove
|
||||
teams.add_nonexistent_repo = The repository you're trying to add does not exist, please create it first.
|
||||
@@ -773,6 +840,8 @@ dashboard.resync_all_sshkeys = Rewrite '.ssh/authorized_keys' file (caution: non
|
||||
dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks = Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success = All repositories' update hook have been rewritten successfully.
|
||||
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.server_uptime = Server Uptime
|
||||
dashboard.current_goroutine = Current Goroutines
|
||||
@@ -795,7 +864,7 @@ dashboard.mspan_structures_obtained = MSpan Structures Obtained
|
||||
dashboard.mcache_structures_usage = MCache Structures Usage
|
||||
dashboard.mcache_structures_obtained = MCache Structures Obtained
|
||||
dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained
|
||||
dashboard.gc_metadata_obtained = GC Metadada Obtained
|
||||
dashboard.gc_metadata_obtained = GC Metadata Obtained
|
||||
dashboard.other_system_allocation_obtained = Other System Allocation Obtained
|
||||
dashboard.next_gc_recycle = Next GC Recycle
|
||||
dashboard.last_gc_time = Since Last GC Time
|
||||
@@ -820,7 +889,10 @@ users.auth_login_name = Authentication Login Name
|
||||
users.password_helper = Leave it empty to remain unchanged.
|
||||
users.update_profile_success = Account profile has been updated successfully.
|
||||
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
|
||||
@@ -851,6 +923,7 @@ auths.enabled = Enabled
|
||||
auths.updated = Updated
|
||||
auths.auth_type = Authentication Type
|
||||
auths.auth_name = Authentication Name
|
||||
auths.security_protocol = Security Protocol
|
||||
auths.domain = Domain
|
||||
auths.host = Host
|
||||
auths.port = Port
|
||||
@@ -859,9 +932,12 @@ auths.bind_password = Bind Password
|
||||
auths.bind_password_helper = Warning: This password is stored in plain text. Do not use a high privileged account.
|
||||
auths.user_base = User Search Base
|
||||
auths.user_dn = User DN
|
||||
auths.attribute_username = Username attribute
|
||||
auths.attribute_username_placeholder = Leave empty to use sign-in form field value for user name.
|
||||
auths.attribute_name = First name attribute
|
||||
auths.attribute_surname = Surname attribute
|
||||
auths.attribute_mail = E-mail attribute
|
||||
auths.attribute_mail = Email attribute
|
||||
auths.attributes_in_bind = Fetch attributes in Bind DN context
|
||||
auths.filter = User Filter
|
||||
auths.admin_filter = Admin Filter
|
||||
auths.ms_ad_sa = Ms Ad SA
|
||||
@@ -876,13 +952,14 @@ 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
|
||||
auths.delete = Delete This Authentication
|
||||
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!
|
||||
|
||||
config.server_config = Server Configuration
|
||||
@@ -899,6 +976,19 @@ config.static_file_root_path = Static File Root Path
|
||||
config.log_file_root_path = Log File Root Path
|
||||
config.script_type = Script Type
|
||||
config.reverse_auth_user = Reverse Authentication User
|
||||
|
||||
config.ssh_config = SSH Configuration
|
||||
config.ssh_enabled = Enabled
|
||||
config.ssh_start_builtin_server = 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.db_config = Database Configuration
|
||||
config.db_type = Type
|
||||
config.db_host = Host
|
||||
@@ -909,11 +999,10 @@ config.db_ssl_mode_helper = (for "postgres" only)
|
||||
config.db_path = Path
|
||||
config.db_path_helper = (for "sqlite3" and "tidb")
|
||||
config.service_config = Service Configuration
|
||||
config.register_email_confirm = Require E-mail Confirmation
|
||||
config.register_email_confirm = Require Email Confirmation
|
||||
config.disable_register = Disable Registration
|
||||
config.show_registration_button = Show Register Button
|
||||
config.require_sign_in_view = Require Sign In View
|
||||
config.enable_cache_avatar = Enable Cache Avatar
|
||||
config.mail_notify = Mail Notification
|
||||
config.disable_key_size_check = Disable Minimum Key Size Check
|
||||
config.enable_captcha = Enable Captcha
|
||||
@@ -929,6 +1018,9 @@ config.mailer_disable_helo = Disable HELO
|
||||
config.mailer_name = Name
|
||||
config.mailer_host = Host
|
||||
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
|
||||
@@ -962,23 +1054,34 @@ monitor.start = Start Time
|
||||
monitor.execute_time = Execution Time
|
||||
|
||||
notices.system_notice_list = System Notices
|
||||
notices.view_detail_header = View Notice Detail
|
||||
notices.actions = Actions
|
||||
notices.select_all = Select All
|
||||
notices.deselect_all = Deselect All
|
||||
notices.inverse_selection = Inverse Selection
|
||||
notices.delete_selected = Delete Selected
|
||||
notices.delete_all = Delete All Notices
|
||||
notices.type = Type
|
||||
notices.type_1 = Repository
|
||||
notices.desc = Description
|
||||
notices.op = Op.
|
||||
notices.delete_success = System notice has been deleted successfully.
|
||||
notices.delete_success = System notices have been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo = created repository <a href="%s">%s</a>
|
||||
rename_repo = renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
commit_repo = pushed to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a>
|
||||
create_issue = `opened issue <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>`
|
||||
create_pull_request = `created 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>`
|
||||
comment_issue = `commented on issue <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 = transfered repository <code>%s</code> to <a href="%s">%s</a>
|
||||
push_tag = pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits = View comparison for these 2 commits
|
||||
compare_commits = View comparison for these %d commits
|
||||
|
||||
[tool]
|
||||
ago = ago
|
||||
@@ -1004,5 +1107,5 @@ raw_minutes = minutes
|
||||
[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).
|
||||
file_too_big = File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
|
||||
remove_file = Remove file
|
||||
|
||||
417
conf/locale/locale_es-ES.ini
Executable file → Normal file
417
conf/locale/locale_es-ES.ini
Executable file → Normal file
@@ -6,9 +6,9 @@ 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
|
||||
website=Página web
|
||||
version=Versión
|
||||
page=Página
|
||||
template=Plantilla
|
||||
@@ -27,8 +27,9 @@ repository=Repositorio
|
||||
organization=Organización
|
||||
mirror=Mirror
|
||||
new_repo=Nuevo repositorio
|
||||
new_migrate=Nueva Migración
|
||||
new_fork=Nuevo Fork del Repositorio
|
||||
new_migrate=Nueva migración
|
||||
new_mirror=Nueva réplica
|
||||
new_fork=Nuevo fork del repositorio
|
||||
new_org=Nueva organización
|
||||
manage_org=Administrar organizaciones
|
||||
admin_panel=Panel de administración
|
||||
@@ -37,23 +38,16 @@ settings=Configuraciones
|
||||
your_profile=Tu perfil
|
||||
your_settings=Tu configuración
|
||||
|
||||
news_feed=Feed de noticias
|
||||
activities=Actividad
|
||||
pull_requests=Pull Requests
|
||||
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
|
||||
@@ -64,14 +58,14 @@ db_name=Nombre de la base de datos
|
||||
db_helper=Por favor utilice el motor INNODB con la configuración de caracteres utf8_general_ci para MySQL.
|
||||
ssl_mode=Modo SSL
|
||||
path=Ruta
|
||||
sqlite_helper=Ruta del archivo con la base de datos SQLite3 o TiDB.
|
||||
sqlite_helper=Ruta al archivo de base de datos SQLite3 o TiDB. <br>Por favor, usa una ruta absoluta cuando inicies como servicio.
|
||||
err_empty_db_path=La ruta a la base de datos SQLite3 o TiDB no puede estar vacía.
|
||||
err_invalid_tidb_name=El nombre de la base de datos TiDB no puede contener los caracteres "." ni "-".
|
||||
no_admin_and_disable_registration=No puede deshabilitar el registro sin crear una cuenta de administrador.
|
||||
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.
|
||||
@@ -85,9 +79,11 @@ http_port=Puerto HTTP
|
||||
http_port_helper=Puerto en el que escuchará la aplicación.
|
||||
app_url=URL de la aplicación
|
||||
app_url_helper=Esto afecta a las URLs para clonar por HTTP/HTTPS y a algunos correos electrónicos.
|
||||
log_root_path=Ruta del registro
|
||||
log_root_path_helper=Directorio donde almacenar los registros.
|
||||
|
||||
optional_title=Configuración Opcional
|
||||
email_title=Configuración del Servicio de Correo
|
||||
optional_title=Configuración opcional
|
||||
email_title=Configuración del servicio de correo
|
||||
smtp_host=SMTP Host
|
||||
smtp_from=Desde
|
||||
smtp_from_helper=Remitente del email, RFC 5322. Puede ser solamente una dirección de correo electrónico, o estar en el formato "Nombre" <email@example.com>.
|
||||
@@ -95,10 +91,10 @@ mailer_user=Remitente del Correo Electrónico
|
||||
mailer_password=Contraseña del Remitente
|
||||
register_confirm=Habilitar la Confirmación en el Registro
|
||||
mail_notify=Habilitar las Notificaciones de Correo
|
||||
server_service_title=Configuración de Servidor y Otros Servicios
|
||||
server_service_title=Configuración del servidor y otros servicios
|
||||
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=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.
|
||||
disable_registration=Desactivar Auto-Registro
|
||||
disable_registration_popup=Desactivar auto-registro del usuario, solo el administrador podrá crear cuentas nuevas.
|
||||
@@ -107,7 +103,7 @@ enable_captcha_popup=Requiere validar la captcha para el auto-registro de usuari
|
||||
require_sign_in_view=Activar el Inicio de Sesión obligatorio para Ver Páginas
|
||||
require_sign_in_view_popup=Solo los usuarios logados pueden ver páginas, los visitantes anónimos solo podrán ver las páginas de login/registro.
|
||||
admin_setting_desc=No es necesario crear una cuenta de administrador ahora mismo, el usuario que tenga ID=1 obtendrá privilegios de administrador automáticamente.
|
||||
admin_title=Configuración de la Cuenta de Administrador
|
||||
admin_title=Configuración de la cuenta de administrador
|
||||
admin_name=Nombre de usuario
|
||||
admin_password=Contraseña
|
||||
confirm_password=Confirmar Contraseña
|
||||
@@ -121,24 +117,27 @@ run_user_not_match=El usuario que está ejecutando la aplicación no es el usuar
|
||||
save_config_failed=Error al guardar la configuración: %v
|
||||
invalid_admin_setting=La configuración de la cuenta de administración es inválida: %v
|
||||
install_success=Bienvenido! Estamos encantados de que hayas escogido Gogs, diviértete y cuídate.
|
||||
invalid_log_root_path=La ruta para los registros es inválida: %v
|
||||
|
||||
[home]
|
||||
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
|
||||
collaborative_repos=Repositorios Colaborativos
|
||||
my_orgs=Mis Organizaciones
|
||||
my_mirrors=Mis Mirrors
|
||||
my_repos=Mis repositorios
|
||||
collaborative_repos=Repositorios colaborativos
|
||||
my_orgs=Mis organizaciones
|
||||
my_mirrors=Mis réplicas
|
||||
view_home=Ver %s
|
||||
|
||||
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.
|
||||
@@ -158,6 +157,7 @@ reset_password=Restablecer su contraseña
|
||||
invalid_code=Lo sentimos, su código de confirmación ha expirado o no es valido.
|
||||
reset_password_helper=Haga Clic aquí para restablecer su contraseña
|
||||
password_too_short=La longitud de la contraseña no puede ser menor a 6.
|
||||
non_local_account=Cuentas que no son locales no pueden cambiar las contraseñas a través de Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=Por favor, active su cuenta
|
||||
@@ -192,7 +192,7 @@ min_size_error=` debe contener al menos %s caracteres.`
|
||||
max_size_error=` debe contener como máximo %s caracteres.`
|
||||
email_error=` no es una dirección de correo válida.`
|
||||
url_error=` no es una URL válida.`
|
||||
include_error='debe contener la subcadena '%s'.'
|
||||
include_error=` debe contener la subcadena '%s'.`
|
||||
unknown_error=Error desconocido:
|
||||
captcha_incorrect=El captcha no es válido.
|
||||
password_not_match=La contraseña de confirmación no coincide.
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=Ya existe un repositorio con este nombre.
|
||||
org_name_been_taken=Ya existe una organización con este nombre.
|
||||
team_name_been_taken=Ya existe un equipo con este nombre.
|
||||
email_been_used=Esta dirección de correo electrónico ya está en uso.
|
||||
illegal_team_name=El nombre del equipo contiene caracteres inválidos.
|
||||
username_password_incorrect=Nombre de usuario o contraseña incorrectos.
|
||||
enterred_invalid_repo_name=Por favor, asegúrate de que has introducido correctamente el nombre del repositorio.
|
||||
enterred_invalid_owner_name=Por favor, asegúrate de que has introducido correctamente el nombre del propietario.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=Tu cuenta es la propietaria de uno o más repositorios, tienes qu
|
||||
still_has_org=Tu cuenta es miembro de una o más organizaciones, tienes que abandonarlas o eliminarlas primero.
|
||||
org_still_own_repo=Esta organización es dueña de uno o más repositorios, tienes que eliminarlos o transferirlos primero.
|
||||
|
||||
still_own_user=Esta autenticación está en uso por algunos usuarios, debes moverlos y antes de eliminarla.
|
||||
|
||||
target_branch_not_exist=La rama de destino no existe
|
||||
|
||||
[user]
|
||||
change_avatar=Cambia tu avatar en gravatar.com
|
||||
change_custom_avatar=Cambia tu avatar en la configuración
|
||||
join_on=Registrado en
|
||||
change_avatar=Change your avatar
|
||||
join_on=Registrado el
|
||||
repositories=Repositorios
|
||||
activity=Actividad pública
|
||||
followers=Seguidores
|
||||
starred=Destacados
|
||||
following=Siguiendo
|
||||
follow=Seguir
|
||||
unfollow=Dejar de seguir
|
||||
|
||||
form.name_reserved=El usuario '%s' está reservado.
|
||||
form.name_pattern_not_allowed=El patrón de nombre de usuario '%s' no está permitido.
|
||||
@@ -242,27 +240,27 @@ ssh_keys=Claves SSH
|
||||
social=Redes Sociales
|
||||
applications=Aplicaciones
|
||||
orgs=Organizaciones
|
||||
delete=Eliminar Cuenta
|
||||
delete=Eliminar cuenta
|
||||
uid=UUID
|
||||
|
||||
public_profile=Perfil Público
|
||||
public_profile=Perfil público
|
||||
profile_desc=Tu correo electrónico es público y será usado para todas las notificaciones relacionadas con cualquier cuenta y cualquier operación hecha a través de la web.
|
||||
full_name=Nombre Completo
|
||||
website=Página Web
|
||||
password_username_disabled=Los usuarios que no son locales no tienen permitido cambiar su nombre de usuario.
|
||||
full_name=Nombre completo
|
||||
website=Página web
|
||||
location=Localización
|
||||
update_profile=Actualizar Perfil
|
||||
update_profile=Actualizar perfil
|
||||
update_profile_success=Tu perfil se ha actualizado correctamente.
|
||||
change_username=Nombre de usuario modificado
|
||||
change_username_prompt=Este cambio afectará a los enlaces que hacen referencia a su cuenta.
|
||||
continue=Continuar
|
||||
cancel=Cancelar
|
||||
|
||||
enable_custom_avatar=Activar Avatar Personalizado
|
||||
enable_custom_avatar_helper=Activa esto para desactivar los avatares de Gravatar
|
||||
enable_custom_avatar=Activar avatar personalizado
|
||||
choose_new_avatar=Selecciona nuevo avatar
|
||||
update_avatar=Actualizar Configuración del Avatar
|
||||
update_avatar=Actualizar configuración del avatar
|
||||
delete_current_avatar=Eliminar avatar
|
||||
uploaded_avatar_not_a_image=El archivo enviado no es una imagen.
|
||||
no_custom_avatar_available=No hay ningún avatar personalizado disponible, no se puede habilitar.
|
||||
update_avatar_success=La configuración de tu avatar se ha actualizado correctamente.
|
||||
|
||||
change_password=Cambiar contraseña
|
||||
@@ -271,6 +269,7 @@ new_password=Nueva contraseña
|
||||
retype_new_password=Confirmar nueva contraseña
|
||||
password_incorrect=Contraseña actual incorrecta.
|
||||
change_password_success=La contraseña se ha modificado correctamente. Ya puedes iniciar sesión con tu nueva contraseña.
|
||||
password_change_disabled=Los usuarios que no son locales no tienen permitido cambiar su contraseña.
|
||||
|
||||
emails=Direcciones de correo electrónico
|
||||
manage_emails=Gestionar direcciones de correo electrónico
|
||||
@@ -278,8 +277,8 @@ email_desc=Tu dirección de correo principal se utilizará para las notificacion
|
||||
primary=Principal
|
||||
primary_email=Marcar como principal
|
||||
delete_email=Eliminar
|
||||
email_deletion=Eliminación de Correo Electrónico
|
||||
email_deletion_desc=Al eliminar esta dirección de correo electrónico se eliminará toda la información asociada a esta dirección de correo electrónico. ¿Deseas continuar?
|
||||
email_deletion=Eliminar correo electrónico
|
||||
email_deletion_desc=Al eliminar esta dirección de correo electrónico se eliminará toda la información asociada a esta. ¿Deseas continuar?
|
||||
email_deletion_success=¡El correo electrónico ha sido eliminado correctamente!
|
||||
add_new_email=Añadir nueva dirección de correo electrónico
|
||||
add_email=Añadir correo electrónico
|
||||
@@ -331,10 +330,10 @@ delete_account_desc=Esta cuenta se va a eliminar permanentemente, ¿quieres cont
|
||||
|
||||
[repo]
|
||||
owner=Propietario
|
||||
repo_name=Nombre del Repositorio
|
||||
repo_name=Nombre del repositorio
|
||||
repo_name_helper=Los grandes nombres de repositorios son cortos, memorables y <strong>únicos</strong>.
|
||||
visibility=Visibilidad
|
||||
visiblity_helper=Este repositorio es <span class="ui red text">Privado</span>
|
||||
visiblity_helper=Este repositorio es <span class="ui red text">privado</span>
|
||||
visiblity_helper_forced=El administrador web ha obligado a todos los repositorios nuevos a ser <span class="ui red text"> privados</span>
|
||||
visiblity_fork_helper=(Este cambio afectará a todos los forks)
|
||||
clone_helper=¿Necesitas ayuda con el clone? ¡Consulta la <a target="_blank" href="%s">Ayuda</a>!
|
||||
@@ -349,45 +348,52 @@ license_helper=Selecciona un fichero de licencia
|
||||
readme=Readme
|
||||
readme_helper=Seleccione una plantilla de archivo readme
|
||||
auto_init=Inicializar los archivos seleccionados y plantillas de este repositorio
|
||||
create_repo=Crear Repositorio
|
||||
create_repo=Crear repositorio
|
||||
default_branch=Rama por defecto
|
||||
mirror_interval=Intervalo de mirror(en horas)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
mirror_prune=Prune
|
||||
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
|
||||
mirror_interval=Intervalo de la réplica (en horas)
|
||||
mirror_address=Dirección de la réplica
|
||||
mirror_address_desc=Por favor, incluya las credenciales de usuario necesarias en la dirección.
|
||||
watchers=Seguidores
|
||||
stargazers=Fans
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=El propietario ha alcanzado el límite máximo de %d repositorios creados.
|
||||
form.name_reserved=El nombre del repositorio '%s' está reservado.
|
||||
form.name_pattern_not_allowed=El patrón del nombre del repositorio '%s' no está permitido.
|
||||
|
||||
need_auth=Requiere Autorización
|
||||
migrate_type=Tipo de Migración
|
||||
migrate_type_helper=Este repositorio será un <span class="text blue">mirror</span>
|
||||
need_auth=Requiere autorización
|
||||
migrate_type=Tipo de migración
|
||||
migrate_type_helper=Este repositorio será una <span class="text blue">réplica</span>
|
||||
migrate_repo=Migrar Repositorio
|
||||
migrate.clone_address=Clonar Dirección
|
||||
migrate.clone_address=Clonar dirección
|
||||
migrate.clone_address_desc=Puede ser una URL HTTP/HTTPS/GIT o una ruta local del servidor.
|
||||
migrate.permission_denied=No te está permitido importar repositorios locales.
|
||||
migrate.invalid_local_path=Rutal local inválida, no existe o no es un directorio.
|
||||
migrate.failed=Migration failed: %v
|
||||
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_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
|
||||
push_exist_repo=Hacer Push de un repositorio existente desde línea de comandos
|
||||
repo_is_empty=Este repositorio está vacío, por favor, ¡vuelva más tarde!
|
||||
|
||||
code=Código
|
||||
branch=Rama
|
||||
tree=Árbol
|
||||
filter_branch_and_tag=Filtrar por rama o etiqueta
|
||||
@@ -413,7 +419,7 @@ commits.date=Fecha
|
||||
commits.older=Anterior
|
||||
commits.newer=Posterior
|
||||
|
||||
issues.new=Nueva Incidencia
|
||||
issues.new=Nueva incidencia
|
||||
issues.new.labels=Etiquetas
|
||||
issues.new.no_label=Sin etiquetas
|
||||
issues.new.clear_labels=Limpiar etiquetas
|
||||
@@ -457,17 +463,17 @@ 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.no_content=Aun no existe contenido.
|
||||
issues.no_content=Aún no existe contenido.
|
||||
issues.close_issue=Cerrar
|
||||
issues.close_comment_issue=Comentar y cerrar
|
||||
issues.reopen_issue=Reabrir
|
||||
issues.reopen_comment_issue=Comentar y reabrir
|
||||
issues.create_comment=Comentar
|
||||
issues.closed_at=`cerrada <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`reabierta <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.closed_at=`cerró <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`reabrió <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`mencionada esta incidencia en un commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Autor
|
||||
issues.admin=Administrador
|
||||
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>
|
||||
@@ -484,9 +490,10 @@ issues.label_modify=Edición de Etiqueta
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.compare_changes=Comparar Cambios
|
||||
pulls.new=Nuevo Pull Request
|
||||
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
|
||||
@@ -500,16 +507,16 @@ pulls.merged_title_desc=fusionados %[1]d commits de <code>%[2]s</code> en <code>
|
||||
pulls.tab_conversation=Conversación
|
||||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Archivos modificados
|
||||
pulls.reopen_to_merge=Por favor reabra este pull request para proceder con la operación de fusionado.
|
||||
pulls.reopen_to_merge=Por favor reabra este Pull Request para proceder con la operación de fusionado.
|
||||
pulls.merged=Fuisionado
|
||||
pulls.has_merged=¡Este pull request se ha completado con éxito!
|
||||
pulls.data_broken=Los datos de este pull request ya no están disponibles porque se ha eliminado la información del fork.
|
||||
pulls.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=Puede realizar la operación auto-fusionado en este pull request.
|
||||
pulls.cannot_auto_merge_desc=No puede realizar la operación de auto-fusionado porque existen conflictos entre los commits.
|
||||
pulls.cannot_auto_merge_helper=Por favor use la línea de comandos para resolverlo.
|
||||
pulls.is_checking=Se está procediendo a la búsqueda de conflictos, por favor actualice la página en unos momentos.
|
||||
pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente.
|
||||
pulls.cannot_auto_merge_desc=Este Pull Request no puede ser fusionado automáticamente porque hay conflictos.
|
||||
pulls.cannot_auto_merge_helper=Por favor, fusiona manualmente para resolver los conflictos.
|
||||
pulls.merge_pull_request=Fusionar 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.`
|
||||
pulls.open_unmerged_pull_exists=`Usted no puede realizar la operación de reapertura porque en estos momentos existe una solicitud de pull request (#%d) para el mismo repositorio con la misma información que se encuentra a la espera de aprobación`
|
||||
|
||||
milestones.new=Nuevo Milestone
|
||||
milestones.open_tab=%d abiertas
|
||||
@@ -532,47 +539,97 @@ milestones.cancel=Cancelar
|
||||
milestones.modify=Modificar Milestone
|
||||
milestones.edit_success=¡Los cambios al milestone '%s' se han guardado con éxito!
|
||||
milestones.deletion=Borrar milestone
|
||||
milestones.deletion_desc=El borrado de este milestone eliminará su información y las incidencias asociadas. ¿Desea continuar?
|
||||
milestones.deletion_desc=Eliminar este Milestone eliminará su información y las incidencias asociadas. ¿Desea continuar?
|
||||
milestones.deletion_success=¡El milestone ha sido eliminado con éxito!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=¡Bienvenido a la Wiki!
|
||||
wiki.welcome_desc=La Wiki es el lugar donde os gustaría documentar juntos vuestro proyecto y hacerlo mejor.
|
||||
wiki.create_first_page=Crear la primera página
|
||||
wiki.page=Página
|
||||
wiki.filter_page=Filtrar página
|
||||
wiki.new_page=Crear nueva página
|
||||
wiki.default_commit_message=Escribe una nota sobre esta actualización (opcional).
|
||||
wiki.save_page=Guardar página
|
||||
wiki.last_commit_info=%s editó esta página %s
|
||||
wiki.edit_page_button=Editar
|
||||
wiki.new_page_button=Nueva página
|
||||
wiki.delete_page_button=Eliminar página
|
||||
wiki.delete_page_notice_1=Esto eliminará la página <code>"%s"</code>. Por favor, asegúrate de que es lo que quieres.
|
||||
wiki.page_already_exists=Ya existe una página con el mismo nombre.
|
||||
wiki.pages=Páginas
|
||||
wiki.last_updated=Última actualización %s
|
||||
|
||||
settings=Configuración
|
||||
settings.options=Opciones
|
||||
settings.collaboration=Colaboración
|
||||
settings.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.danger_zone=Zona de Peligro
|
||||
settings.site=Sitio Oficial
|
||||
settings.update_settings=Actualizar Configuración
|
||||
settings.site=Sitio oficial
|
||||
settings.update_settings=Actualizar configuración
|
||||
settings.change_reponame_prompt=Este cambio afectará a los enlaces al repositorio.
|
||||
settings.transfer=Transferir la Propiedad
|
||||
settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración.
|
||||
settings.advanced_settings=Ajustes avanzados
|
||||
settings.wiki_desc=Habilitar la Wiki para que los colaboradores documenten
|
||||
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.use_external_issue_tracker=Usar tracker externo de incidencias
|
||||
settings.tracker_url_format=Formato URL del tracker de incidencias externo
|
||||
settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias:
|
||||
settings.tracker_issue_style.numeric=Numérico <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alfanumérico <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=Puedes usar las plantillas <code>{user} {repo} {index}</code> para el nombre de usuario, nombre del repositorio e índice de la incidencia.
|
||||
settings.pulls_desc=Habilitar Pull Requests para aceptar contribuciones públicas
|
||||
settings.danger_zone=Zona de Peligro
|
||||
settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con el mismo nombre.
|
||||
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.convert=Convertir en un repositorio normal
|
||||
settings.convert_desc=Puedes convertir este repositorio en un repositorio normal. Este cambio no se puede deshacer.
|
||||
settings.convert_notices_1=- Esta operación convertirá este repositorio espejo en un repositorio normal y no podrá deshacerse.
|
||||
settings.convert_confirm=Confirmar conversión
|
||||
settings.convert_succeed=El repositorio ha sido convertido en normal satisfactoriamente.
|
||||
settings.transfer=Transferir la propiedad
|
||||
settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración.
|
||||
settings.transfer_notices_1=- Perderá el permiso de acceso si el nuevo propietario es otro usuario.
|
||||
settings.transfer_notices_2=- Conservará el privilegio de acceso si el nuevo propietario es una organización y usted es uno de los propietarios de dicha organización.
|
||||
settings.transfer_form_title=Por favor introduzca esta información para confirmar la operación:
|
||||
settings.wiki_delete=Eliminar datos de la wiki
|
||||
settings.wiki_delete_desc=Una vez borrados los datos de la wiki no habrá vuelta atrás. Por favor, asegúrate de que es lo que quieres.
|
||||
settings.wiki_delete_notices_1=- Esto eliminará y deshabilitará la wiki para %s
|
||||
settings.wiki_deletion_success=Los datos de la wiki del repositorio han sido borrados correctamente.
|
||||
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
|
||||
settings.make_transfer=Transferir
|
||||
settings.transfer_succeed=La propiedad del repositorio ha sido transferida exitosamente.
|
||||
settings.confirm_delete=Confirmar Eliminación
|
||||
settings.add_collaborator=Añadir Nuevo Colaborador
|
||||
settings.add_collaborator_success=Se ha añadido el nuevo colaborador.
|
||||
settings.remove_collaborator_success=Se ha eliminado el colaborador.
|
||||
settings.confirm_delete=Confirmar eliminación
|
||||
settings.add_collaborator=Añadir nuevo colaborador
|
||||
settings.add_collaborator_success=El nuevo colaborador ha sido añadido.
|
||||
settings.delete_collaborator=Eliminar
|
||||
settings.collaborator_deletion=Eliminar colaborador
|
||||
settings.collaborator_deletion_desc=Este usuario no podrá colaborar en este repositorio tras eliminarlo. ¿Desea continuar?
|
||||
settings.remove_collaborator_success=El colaborador ha sido eliminado.
|
||||
settings.search_user_placeholder=Buscar usuario...
|
||||
settings.org_not_allowed_to_be_collaborator=Las organizaciones no tiene permitido ser añadidas como colaboradores.
|
||||
settings.user_is_org_member=El usuario es miembro de la organización, no puede ser añadido como colaborador.
|
||||
settings.add_webhook=Añadir Webhook
|
||||
settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificaciones cuando sucedan ciertos eventos en Gogs. Cuando sucedan los eventos especificados, enviaremos una petición POST a cada una de las URLs indicadas. Para obtener más información, consulta nuestra <a target="_blank" href="%s">Guía de Webhooks</a>.
|
||||
settings.webhook_deletion=Eliminar Webhook
|
||||
settings.webhook_deletion_desc=Al borrar este webhook se eliminará su información y todo su historial. ¿Desea continuar?
|
||||
settings.webhook_deletion_success=¡Webhook eliminado con éxito!
|
||||
settings.webhook.test_delivery=Test de entrega
|
||||
settings.webhook.test_delivery_desc=Enviar un falso evento Push de entrega para probar tus ajustes de webhook
|
||||
settings.webhook.test_delivery_success=Probar que los webhook han sido añadidos a la cola de entrega. Esto puede tomar algunos segundos antes de aparecer en el historial de entregas.
|
||||
settings.webhook.request=Petición
|
||||
settings.webhook.response=Respuesta
|
||||
settings.webhook.headers=Encabezado
|
||||
@@ -585,7 +642,7 @@ settings.githook_content=Contenido del Hook
|
||||
settings.update_githook=Actualizar Hook
|
||||
settings.add_webhook_desc=Enviaremos una petición <code>POST</code> a la siguiente URL con los detalles de cualquier evento suscrito. También puedes especificar qué formato de datos te gustaría recibir (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). Puedes encontrar más información en la <a target="_blank" href="%s">Guía de Webhooks</a>.
|
||||
settings.payload_url=URL de Payload
|
||||
settings.content_type=Tipo de Contenido
|
||||
settings.content_type=Tipo de contenido
|
||||
settings.secret=Secreto
|
||||
settings.slack_username=Nombre de usuario
|
||||
settings.slack_icon_url=URL de icono
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=Dominio
|
||||
settings.slack_channel=Canal
|
||||
settings.deploy_keys=Claves de Despliegue
|
||||
settings.add_deploy_key=Añadir Clave de Despliegue
|
||||
settings.deploy_key_desc=La clave de desarrollo tiene sólo acceso de lectura. No es igual que las claves SSH de las cuentas personales.
|
||||
settings.no_deploy_keys=No has añadido ninguna clave de despliegue.
|
||||
settings.title=Título
|
||||
settings.deploy_key_content=Contenido
|
||||
@@ -626,10 +684,14 @@ diff.browse_source=Explorar el Código
|
||||
diff.parent=padre
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Los datos del Diff no están disponibles.
|
||||
diff.show_diff_stats=Mostrar Estadísticas de Diff
|
||||
diff.show_diff_stats=Mostrar estadísticas de diff
|
||||
diff.show_split_view=Dividir vista
|
||||
diff.show_unified_view=Unificar vista
|
||||
diff.stats_desc=Se han <strong>modificado %d ficheros</strong> con <strong>%d adiciones</strong> y <strong>%d borrados</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Ver Fichero
|
||||
diff.view_file=Ver fichero
|
||||
diff.file_supressed=El diff del archivo ha sido suprimido porque es demasiado grande
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=Releases
|
||||
release.new_release=Nueva Release
|
||||
@@ -639,32 +701,32 @@ release.stable=Estable
|
||||
release.edit=editar
|
||||
release.ahead=<strong>%d</strong> commits en %s desde esta release
|
||||
release.source_code=Código Fuente
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=Publicar releases del proyecto.
|
||||
release.edit_subheader=Un registro de cambios detallado ayudará a los usuarios a comprender lo que se ha mejorado.
|
||||
release.tag_name=Nombre de la etiqueta
|
||||
release.target=Destino
|
||||
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.
|
||||
release.cancel=Cancelar
|
||||
release.publish=Publicar Release
|
||||
release.save_draft=Guardar Borrador
|
||||
release.save_draft=Guardar borrador
|
||||
release.edit_release=Editar Release
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=Borrar este Release
|
||||
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.downloads=Descargas
|
||||
|
||||
[org]
|
||||
org_name_holder=Nombre de la Organización
|
||||
org_full_name_holder=Nombre de la organización
|
||||
org_name_holder=Nombre de la organización
|
||||
org_full_name_holder=Nombre completo de la organización
|
||||
org_name_helper=Los grandes nombres de organizaciones son cortos y memorables.
|
||||
create_org=Crear Organización
|
||||
repo_updated=Actualizado
|
||||
@@ -673,9 +735,9 @@ invite_someone=Invitar a alguien
|
||||
teams=Equipos
|
||||
lower_members=miembros
|
||||
lower_repositories=repositorios
|
||||
create_new_team=Crear un Nuevo Equipo
|
||||
create_new_team=Crear un nuevo equipo
|
||||
org_desc=Descripción
|
||||
team_name=Nombre del Equipo
|
||||
team_name=Nombre del equipo
|
||||
team_desc=Descripción
|
||||
team_name_helper=Utiliza este nombre para mencionar a este equipo en las conversaciones.
|
||||
team_desc_helper=¿En qué consiste este equipo?
|
||||
@@ -686,31 +748,32 @@ form.name_pattern_not_allowed=El patrón de nombre de la organización '%s' no e
|
||||
|
||||
settings=Configuración
|
||||
settings.options=Opciones
|
||||
settings.full_name=Nombre Completo
|
||||
settings.website=Página Web
|
||||
settings.full_name=Nombre completo
|
||||
settings.website=Página web
|
||||
settings.location=Localización
|
||||
settings.update_settings=Actualizar Configuración
|
||||
settings.update_setting_success=La configuración de la Organización se ha actualizado correctamente.
|
||||
settings.update_settings=Actualizar configuración
|
||||
settings.update_setting_success=La configuración de la organización se ha actualizado correctamente.
|
||||
settings.change_orgname_prompt=Este cambio afectará a los enlaces que hacen referencia a la organización.
|
||||
settings.update_avatar_success=La configuración de avatar de la organización ha sido actualizada con éxito.
|
||||
settings.delete=Eliminar Organización
|
||||
settings.delete_account=Eliminar esta Organización
|
||||
settings.delete=Eliminar organización
|
||||
settings.delete_account=Eliminar esta organización
|
||||
settings.delete_prompt=Esta operación eliminará esta organización de manera permanente, y ¡<strong>NO PUEDE</strong> deshacerse!
|
||||
settings.confirm_delete_account=Confirmar Eliminación
|
||||
settings.delete_org_title=Eliminación de la Organización
|
||||
settings.confirm_delete_account=Confirmar eliminación
|
||||
settings.delete_org_title=Eliminación de la organización
|
||||
settings.delete_org_desc=Esta organización se va a eliminar permanentemente, ¿quieres continuar?
|
||||
settings.hooks_desc=Añadir webhooks que serán ejecutados para <strong>todos los repositorios</strong> de esta organización.
|
||||
|
||||
members.membership_visibility=Visibilidad de Membresía:
|
||||
members.public=Público
|
||||
members.public_helper=convertir en privado
|
||||
members.private=Privado
|
||||
members.private_helper=convertir en público
|
||||
members.member_role=Rol del miembro:
|
||||
members.owner=Propietario
|
||||
members.member=Miembro
|
||||
members.conceal=Ocultar
|
||||
members.remove=Eliminar
|
||||
members.leave=Abandonar
|
||||
members.invite_desc=Comienza a teclear un nombre de usuario para invitar a un nuevo miembro a %s:
|
||||
members.invite_desc=Añadir un miembro nuevo a %s:
|
||||
members.invite_now=Invitar
|
||||
|
||||
teams.join=Unirse
|
||||
@@ -719,23 +782,24 @@ teams.read_access=Acceso de Lectura
|
||||
teams.read_access_helper=Este equipo podrá ver y clonar sus repositorios.
|
||||
teams.write_access=Acceso de Escritura
|
||||
teams.write_access_helper=Este equipo podrá leer sus repositorios, así como hacer push en ellos.
|
||||
teams.admin_access=Acceso de Administrador
|
||||
teams.admin_access=Acceso de administrador
|
||||
teams.admin_access_helper=Este equipo podrá hacer push/pull en sus repositorios, así como añadir colaboradores a ellos.
|
||||
teams.no_desc=Este equipo no tiene descripción
|
||||
teams.settings=Configuración
|
||||
teams.owners_permission_desc=Los propietarios tienen acceso completo a <strong>todos los repositorios</strong> y tienen <strong>derechos de administración</strong> en la organización.
|
||||
teams.members=Miembros del Equipo
|
||||
teams.update_settings=Actualizar Configuración
|
||||
teams.delete_team=Borrar este Equipo
|
||||
teams.add_team_member=Añadir Miembro al Equipo
|
||||
teams.delete_team_title=Eliminar Equipo
|
||||
teams.members=Miembros del equipo
|
||||
teams.update_settings=Actualizar configuración
|
||||
teams.delete_team=Eliminar este equipo
|
||||
teams.add_team_member=Añadir miembro al equipo
|
||||
teams.delete_team_title=Eliminar equipo
|
||||
teams.delete_team_desc=Este equipo va a ser eliminado, ¿seguro que quieres continuar? Los miembros de este equipo pueden perder acceso a algunos repositorios.
|
||||
teams.delete_team_success=El Equipo se ha eliminado correctamente.
|
||||
teams.delete_team_success=El equipo ha sido eliminado correctamente.
|
||||
teams.read_permission_desc=Este equipo tiene permisos de <strong>Lectura</strong>: sus miembros pueden ver y clonar los repositorios del equipo.
|
||||
teams.write_permission_desc=Este equipo tiene permisos de <strong>Escritura</strong>: sus miembros pueden leer y hacer push a los repositorios del equipo.
|
||||
teams.admin_permission_desc=Este equipo tiene permisos de <strong>Administración</strong>: sus miembros pueden leer, hacer push y añadir colaboradores a los repositorios del equipo.
|
||||
teams.repositories=Repositorios del Equipo
|
||||
teams.add_team_repository=Añadir Repositorio al Equipo
|
||||
teams.repositories=Repositorios del equipo
|
||||
teams.search_repo_placeholder=Buscar repositorio...
|
||||
teams.add_team_repository=Añadir repositorio al equipo
|
||||
teams.remove_repo=Eliminar
|
||||
teams.add_nonexistent_repo=El repositorio que estás intentando añadir no existe, por favor, créalo primero.
|
||||
|
||||
@@ -746,7 +810,7 @@ organizations=Organizaciones
|
||||
repositories=Repositorios
|
||||
authentication=Autenticaciones
|
||||
config=Configuración
|
||||
notices=Avisos del Sistema
|
||||
notices=Notificaciones del sistema
|
||||
monitor=Monitorización
|
||||
first_page=Primera
|
||||
last_page=Última
|
||||
@@ -756,7 +820,7 @@ dashboard.statistic=Estadísticas
|
||||
dashboard.operations=Operaciones
|
||||
dashboard.system_status=Estado del Monitor del Sistema
|
||||
dashboard.statistic_info=La base de datos de Gogs contiene <b>%d</b> usuarios, <b>%d</b> organizaciones, <b>%d</b> claves públicas, <b>%d</b> repositorios, <b>%d</b> vigilados, <b>%d</b> destacados, <b>%d</b> acciones, <b>%d</b> accesos, <b>%d</b> incidencias, <b>%d</b> comentarios, <b>%d</b> cuentas de redes sociales, <b>%d</b> seguidores, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> fuentes de login, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> etiquetas, <b>%d</b> hooks, <b>%d</b> equipos, <b>%d</b> tareas actualizadas, <b>%d</b> adjuntos.
|
||||
dashboard.operation_name=Nombre de la Operación
|
||||
dashboard.operation_name=Nombre de la operación
|
||||
dashboard.operation_switch=Interruptor
|
||||
dashboard.operation_run=Ejecutar
|
||||
dashboard.clean_unbind_oauth=Limpiar solicitudes de OAuth sin confirmar
|
||||
@@ -765,24 +829,26 @@ dashboard.delete_inactivate_accounts=Eliminar todas las cuentas inactivas
|
||||
dashboard.delete_inactivate_accounts_success=Todas las cuentas inactivas se han eliminado correctamente.
|
||||
dashboard.delete_repo_archives=Eliminar todos los archivos de repositorios
|
||||
dashboard.delete_repo_archives_success=Todos los archivos de repositorios se han eliminado correctamente.
|
||||
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=Borrar todos los registros de los repositorios para los que ya no se dispone de los archivos Git
|
||||
dashboard.delete_missing_repos_success=Todos los registros de repositorios para los que ya no se dispone de los archivos Git se han eliminado correctamente.
|
||||
dashboard.git_gc_repos=Ejecutar la recolección de basura en los repositorios
|
||||
dashboard.git_gc_repos_success=Todos los repositorios han ejecutado correctamente el recolector de basuras.
|
||||
dashboard.resync_all_sshkeys=Reescribir el fichero '.ssh/authorized_keys'(atención: se perderán las claves que no pertenezcan a Gogs)
|
||||
dashboard.resync_all_sshkeys_success=Todas las claves públicas se han reescrito correctamente.
|
||||
dashboard.resync_all_update_hooks=Reescribir todos los hooks de actualización de los repositorios (necesario cuando se modifica la ruta de configuración personalizada)
|
||||
dashboard.resync_all_update_hooks_success=Todos los hooks de actualización de los repositorios se han reescrito correctamente.
|
||||
dashboard.reinit_missing_repos=Reinicializar todos los registros del repositorio que tienen archivos Git eliminados
|
||||
dashboard.reinit_missing_repos_success=Todos los registros del repositorio con archivos Git eliminados han sido reinicializados con éxito.
|
||||
|
||||
dashboard.server_uptime=Uptime del Servidor
|
||||
dashboard.current_goroutine=Gorutinas Actuales
|
||||
dashboard.current_memory_usage=Uso de Memoria Actual
|
||||
dashboard.server_uptime=Tiempo de actividad del servidor
|
||||
dashboard.current_goroutine=Gorutinas actuales
|
||||
dashboard.current_memory_usage=Uso de memoria actual
|
||||
dashboard.total_memory_allocated=Total de Memoria Reservada
|
||||
dashboard.memory_obtained=Memoria Obtenida
|
||||
dashboard.pointer_lookup_times=Tiempos de Búsqueda de Punteros
|
||||
dashboard.pointer_lookup_times=Tiempos de búsqueda de punteros
|
||||
dashboard.memory_allocate_times=Tiempos de Reserva de Memoria
|
||||
dashboard.memory_free_times=Tiempos de Liberado de Memoria
|
||||
dashboard.current_heap_usage=Uso de Heap Actual
|
||||
dashboard.current_heap_usage=Uso de Heap actual
|
||||
dashboard.heap_memory_obtained=Memoria de Heap Obtenida
|
||||
dashboard.heap_memory_idle=Memoria de Heap Inactiva
|
||||
dashboard.heap_memory_in_use=Memoria de Heap en Uso
|
||||
@@ -816,10 +882,12 @@ users.new_success=La cuenta '%s' ha sido creada con éxito.
|
||||
users.edit=Editar
|
||||
users.auth_source=Fuente de Autenticación
|
||||
users.local=Local
|
||||
users.auth_login_name=Nombre de Inicio de Sesión de Autenticación
|
||||
users.auth_login_name=Nombre de Inicio de sesión de autenticación
|
||||
users.password_helper=Deje el campo vacío si no desea cambiar la contraseña.
|
||||
users.update_profile_success=El perfil de la cuenta se ha actualizado correctamente.
|
||||
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.is_admin=Esta cuenta tiene permisos de administrador
|
||||
users.allow_git_hook=Esta cuenta tiene permisos para crear hooks de Git
|
||||
@@ -843,34 +911,38 @@ repos.watches=Vigilantes
|
||||
repos.stars=Estrellas
|
||||
repos.issues=Incidencias
|
||||
|
||||
auths.auth_manage_panel=Panel de Administración de Autenticación
|
||||
auths.new=Añadir Nuevo Origen
|
||||
auths.auth_manage_panel=Panel de administración de autenticación
|
||||
auths.new=Añadir nuevo origen
|
||||
auths.name=Nombre
|
||||
auths.type=Tipo
|
||||
auths.enabled=Activo
|
||||
auths.updated=Actualizado
|
||||
auths.auth_type=Tipo de Autenticación
|
||||
auths.auth_name=Nombre de Autenticación
|
||||
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
|
||||
auths.bind_dn=Bind DN
|
||||
auths.bind_password=Contraseña Bind
|
||||
auths.bind_password_helper=Advertencia: La contraseña se almacena como texto plano. No utilice una cuenta con privilegios elevados.
|
||||
auths.user_base=Base de Búsqueda de Usuarios
|
||||
auths.user_base=Base de búsqueda de usuarios
|
||||
auths.user_dn=DN de Usuario
|
||||
auths.attribute_username=Atributo de nombre de usuario
|
||||
auths.attribute_username_placeholder=Dejar vacío para usar el campo de inicio de sesión como nombre de usuario.
|
||||
auths.attribute_name=Atributo nombre
|
||||
auths.attribute_surname=Atributo apellido
|
||||
auths.attribute_mail=Atributo correo electrónico
|
||||
auths.filter=Filtro de Usuario
|
||||
auths.admin_filter=Filtro de Aministrador
|
||||
auths.attributes_in_bind=Buscar atributos en el contexto del Bind DN
|
||||
auths.filter=Filtro de usuario
|
||||
auths.admin_filter=Filtro de aministrador
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=Tipo de Autenticación SMTP
|
||||
auths.smtp_auth=Tipo de autenticación SMTP
|
||||
auths.smtphost=SMTP Host
|
||||
auths.smtpport=Puerto SMTP
|
||||
auths.allowed_domains=Dominios Permitidos
|
||||
auths.allowed_domains_helper=Deje el campo vacío si no desea restringir ningún dominio. Para restringir más de uno, separe los dominios con una coma ','.
|
||||
auths.enable_tls=Habilitar Cifrado TLS
|
||||
auths.enable_tls=Habilitar cifrado TLS
|
||||
auths.skip_tls_verify=Omitir la verificación TLS
|
||||
auths.pam_service_name=Nombre del Servicio PAM
|
||||
auths.enable_auto_register=Hablilitar Auto-Registro
|
||||
@@ -879,13 +951,14 @@ auths.edit=Editar la Configuración de Autenticación
|
||||
auths.activated=Esta autenticación ha sido activada
|
||||
auths.new_success=¡La autenticación '%s' ha sido añadida con éxito!
|
||||
auths.update_success=La configuración de autenticación ha sido actualizada con éxito.
|
||||
auths.update=Actualizar la Configuración de Autenticación
|
||||
auths.update=Actualizar la configuración de autenticación
|
||||
auths.delete=Eliminar Autenticación
|
||||
auths.delete_auth_title=Borrado de Autenticación
|
||||
auths.delete_auth_title=Borrado de autenticación
|
||||
auths.delete_auth_desc=Esta autenticación será eliminada. ¿Deseas continuar?
|
||||
auths.still_in_used=Este método de autentificación aún es utilizado por algunos usuarios, por favor elimine o convierta estos usuarios a otro tipo de autentificación.
|
||||
auths.deletion_success=¡La autenticación ha sido eliminada con éxito!
|
||||
|
||||
config.server_config=Configuración del Servidor
|
||||
config.server_config=Configuración del servidor
|
||||
config.app_name=Nombre de la Aplicación
|
||||
config.app_ver=Versión de la Aplicación
|
||||
config.app_url=URL de la Aplicación
|
||||
@@ -893,27 +966,39 @@ config.domain=Dominio
|
||||
config.offline_mode=Modo Sin Conexión
|
||||
config.disable_router_log=Deshabilitar Log del Router
|
||||
config.run_user=Ejecutada como Usuario
|
||||
config.run_mode=Modo de Ejecución
|
||||
config.run_mode=Modo de ejecución
|
||||
config.repo_root_path=Ruta del Repositorio
|
||||
config.static_file_root_path=Ruta de los Ficheros Estáticos
|
||||
config.log_file_root_path=Ruta de los Ficheros de Log
|
||||
config.script_type=Tipo de Script
|
||||
config.reverse_auth_user=Autenticación Inversa de Usuario
|
||||
|
||||
config.ssh_config=Configuración SSH
|
||||
config.ssh_enabled=Habilitado
|
||||
config.ssh_start_builtin_server=Iniciar servidor integrado
|
||||
config.ssh_domain=Dominio
|
||||
config.ssh_port=Puerto
|
||||
config.ssh_listen_port=Puerto de escucha
|
||||
config.ssh_root_path=Ruta raíz
|
||||
config.ssh_key_test_path=Ruta de la clave de prueba
|
||||
config.ssh_keygen_path=Ruta del generador de claves ('ssh-keygen')
|
||||
config.ssh_minimum_key_size_check=Tamaño mínimo de la clave de verificación
|
||||
config.ssh_minimum_key_sizes=Tamaños de clave mínimos
|
||||
|
||||
config.db_config=Configuración de la Base de Datos
|
||||
config.db_type=Tipo
|
||||
config.db_host=Host
|
||||
config.db_name=Nombre
|
||||
config.db_user=Usuario
|
||||
config.db_ssl_mode=Modo SSL
|
||||
config.db_ssl_mode_helper=(solo para "postgres")
|
||||
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.service_config=Configuración del servicio
|
||||
config.register_email_confirm=Solicitar Confirmación por Correo Electrónico
|
||||
config.disable_register=Deshabilitar el Registro
|
||||
config.show_registration_button=Mostrar Botón de Registro
|
||||
config.require_sign_in_view=Solicitar la Vista de Inicio de Sesión
|
||||
config.enable_cache_avatar=Activar la Caché de Avatar
|
||||
config.mail_notify=Notificación por Correo Electrónico
|
||||
config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo de Clave
|
||||
config.enable_captcha=Activar Captcha
|
||||
@@ -923,12 +1008,15 @@ 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 Mailer
|
||||
config.mailer_config=Configuración del servidor de correo
|
||||
config.mailer_enabled=Activado
|
||||
config.mailer_disable_helo=Desactivar HELO
|
||||
config.mailer_name=Nombre
|
||||
config.mailer_host=Host
|
||||
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é
|
||||
@@ -953,32 +1041,43 @@ config.log_mode=Modo del Log
|
||||
monitor.cron=Tareas de Cron
|
||||
monitor.name=Nombre
|
||||
monitor.schedule=Agenda
|
||||
monitor.next=Próxima Vez
|
||||
monitor.previous=Vez Anterior
|
||||
monitor.next=Siguiente
|
||||
monitor.previous=Anterior
|
||||
monitor.execute_times=Ejecuciones
|
||||
monitor.process=Procesos en Ejecución
|
||||
monitor.process=Procesos en ejecución
|
||||
monitor.desc=Descripción
|
||||
monitor.start=Hora de Inicio
|
||||
monitor.execute_time=Tiempo de ejecución
|
||||
|
||||
notices.system_notice_list=Notificaciones del Sistema
|
||||
notices.view_detail_header=Ver detalles de la notificación
|
||||
notices.actions=Acciones
|
||||
notices.select_all=Sleccionar todo
|
||||
notices.deselect_all=Deseleccionar todo
|
||||
notices.inverse_selection=Selección inversa
|
||||
notices.delete_selected=Eliminar seleccionado
|
||||
notices.delete_all=Eliminar todas las notificaciones
|
||||
notices.type=Tipo
|
||||
notices.type_1=Repositorio
|
||||
notices.desc=Descripción
|
||||
notices.op=Op.
|
||||
notices.delete_success=La notificación del sistema se ha eliminado correctamente.
|
||||
notices.delete_success=Las notificaciones del sistema han sido eliminadas satisfactoriamente.
|
||||
|
||||
[action]
|
||||
create_repo=repositorio creado <a href="%s">%s</a>
|
||||
create_repo=creó el repositorio <a href="%s">%s</a>
|
||||
rename_repo=repositorio renombrado de <code>%[1]s</code> a <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=hizo push a <a href="%[1]s/src/%[2]s">%[3]s</a> en <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`incidencia abierta <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`cerró la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reabrió la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`creado pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
close_pull_request=`cerró el pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
reopen_pull_request=`reabrió el pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`comentó en la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`fusionado pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=transfirió el repositorio <code>%s</code> a <a href="%s">%s</a>
|
||||
push_tag=hizo push del tag <a href="%s/src/%s">%[2]s</a> a <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Ver la comparación de estos 2 commits
|
||||
compare_commits=Ver comparación de estos %d commits
|
||||
|
||||
[tool]
|
||||
ago=hace
|
||||
@@ -991,12 +1090,12 @@ now=ahora
|
||||
1w=%s 1 semana
|
||||
1mon=%s 1 mes
|
||||
1y=%s 1 año
|
||||
seconds=%[2]d %[1]s segundos
|
||||
minutes=%s %d minutos
|
||||
hours=%s %d horas
|
||||
days=%s %d días
|
||||
weeks=%s %d semanas
|
||||
months=%s %d meses
|
||||
seconds=%[2]s %[1]d segundos
|
||||
minutes=%[2]s %[1]d minutos
|
||||
hours=%[2]s %[1]d horas
|
||||
days=%[2]s %[1]d días
|
||||
weeks=%[2]s %[1]d semanas
|
||||
months=%[2]s %[1]d meses
|
||||
years=%s %d años
|
||||
raw_seconds=segundos
|
||||
raw_minutes=minutos
|
||||
|
||||
1108
conf/locale/locale_fi-FI.ini
Normal file
1108
conf/locale/locale_fi-FI.ini
Normal file
File diff suppressed because it is too large
Load Diff
517
conf/locale/locale_fr-FR.ini
Executable file → Normal file
517
conf/locale/locale_fr-FR.ini
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
521
conf/locale/locale_it-IT.ini
Executable file → Normal file
521
conf/locale/locale_it-IT.ini
Executable file → Normal file
@@ -15,7 +15,7 @@ template=Template
|
||||
language=Lingua
|
||||
create_new=Crea...
|
||||
user_profile_and_more=Profilo utente e altro
|
||||
signed_in_as=Signed in as
|
||||
signed_in_as=Accesso effettuato come
|
||||
|
||||
username=Nome utente
|
||||
email=E-mail
|
||||
@@ -28,28 +28,22 @@ organization=Organizzazione
|
||||
mirror=Mirror
|
||||
new_repo=Nuovo Repository
|
||||
new_migrate=Nuova Migrazione
|
||||
new_mirror=Nuovo Mirror
|
||||
new_fork=Nuovo Fork Repository
|
||||
new_org=Nuova organizzazione
|
||||
manage_org=Gestisci le organizzazioni
|
||||
admin_panel=Pannello di amministrazione
|
||||
account_settings=Impostazioni dell'account
|
||||
settings=Impostazioni
|
||||
your_profile=Profilo
|
||||
your_profile=Il tuo profilo
|
||||
your_settings=Impostazioni
|
||||
|
||||
news_feed=Notizie
|
||||
pull_requests=Pull Requests
|
||||
activities=Attivitá
|
||||
pull_requests=Pull Request
|
||||
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
|
||||
@@ -64,9 +58,9 @@ db_name=Nome del database
|
||||
db_helper=Utilizza il motore INNODB con codifica utf8_general_ci per MySQL.
|
||||
ssl_mode=Modalità SSL
|
||||
path=Percorso
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database.
|
||||
err_empty_db_path=SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name=TiDB database name does not allow characters "." and "-".
|
||||
sqlite_helper=Il 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.
|
||||
err_empty_admin_password=La password dell'amministratore non puo' essere vuota.
|
||||
|
||||
@@ -78,13 +72,15 @@ 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=Port number which your SSH server is using, leave it empty to disable SSH feature.
|
||||
ssh_port_helper=Numero di porta utilizzato dal server SSH, lasciare vuoto per disabilitare l'integrazione SSH.
|
||||
http_port=Porta HTTP
|
||||
http_port_helper=Porta di ascolto dell'applicazione.
|
||||
app_url=URL Applicazione
|
||||
app_url_helper=Questo influisce sugli URL per il clonaggio via HTTP/HTTPS e da qualche parte nella posta elettronica.
|
||||
log_root_path=Percorso dei log
|
||||
log_root_path_helper=Directory in cui scrivere i file di log.
|
||||
|
||||
optional_title=Impostazioni Facoltative
|
||||
email_title=Impostazioni E-mail
|
||||
@@ -98,12 +94,12 @@ mail_notify=Abilita Notifiche via Email
|
||||
server_service_title=Impostazioni del Server e Altri Servizi
|
||||
offline_mode=Abilita Modalità Offline
|
||||
offline_mode_popup=Disabilita il CDN anche in modalità produttiva, tutte le risorse saranno servite localmente.
|
||||
disable_gravatar=Disable Gravatar Service
|
||||
disable_gravatar_popup=Disable Gravatar and custom sources, all avatars are uploaded by users or default.
|
||||
disable_gravatar=Disattiva il servizio Gravatar
|
||||
disable_gravatar_popup=Disabilita Gravatar e sorgenti customizzate, tutti gli avatar vengono caricati dagli utenti o come predefinito.
|
||||
disable_registration=Disabilita Registrazione Manuale
|
||||
disable_registration_popup=Disabilita la registrazione manuale degli utenti, solo gli amministratori possono creare account.
|
||||
enable_captcha=Abilita Captcha
|
||||
enable_captcha_popup=Require validate captcha for user self-registration.
|
||||
enable_captcha_popup=Richiedi convalida captcha per i nuovi utenti.
|
||||
require_sign_in_view=Abilita Richiesta di Accesso per Vedere le Pagine
|
||||
require_sign_in_view_popup=Solo gli utenti loggati possono vedere le pagine, i visitatori potranno vedere solo le pagine di accesso e registrazione.
|
||||
admin_setting_desc=Non devi per forza creare un account admin proprio adesso, ma comunque l'utente ID=1 otterrà l'accesso da amministratore automaticamente.
|
||||
@@ -111,7 +107,7 @@ admin_title=Impostazioni Account Amministratore
|
||||
admin_name=Nome utente
|
||||
admin_password=Password
|
||||
confirm_password=Conferma Password
|
||||
admin_email=Admin E-mail
|
||||
admin_email=E-mail dell'Admin
|
||||
install_gogs=Installare Gogs
|
||||
test_git_failed=Fallito il test del comando git: %v
|
||||
sqlite3_not_available=Questa versione non supporta SQLite3, si prega di scaricare la versione binaria ufficiale da %s, NON la versione gobuild.
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=Run user non è l'utente corrente: %s -> %s
|
||||
save_config_failed=Fallito il salvataggio della configurazione: %v
|
||||
invalid_admin_setting=Impostazioni account Admin non valide: %v
|
||||
install_success=Benvenuto! Siamo felici che tu abbia scelto Gogs, buon divertimento.
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Nome Utente o E-mail
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=Nei tuoi repository
|
||||
|
||||
[explore]
|
||||
repos=Repository
|
||||
users=Utenti
|
||||
search=Cerca
|
||||
|
||||
[auth]
|
||||
create_new_account=Crea un nuovo Account
|
||||
@@ -158,13 +157,14 @@ 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
|
||||
activate_email=Verifica il tuo indirizzo e-mail
|
||||
reset_password=Reimposta la tua password
|
||||
register_success=Registrazione completata con successo, Benvenuto
|
||||
register_notify=Welcome on board
|
||||
register_notify=Benvenuti a bordo
|
||||
|
||||
[modal]
|
||||
yes=Sì
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=Il nome del Repository è già utilizzato.
|
||||
org_name_been_taken=Il nome dell'Organizzazione è già utlizzato.
|
||||
team_name_been_taken=Il nome del Team è già utilizzato.
|
||||
email_been_used=L'indirizzo E-mail è già utilizzato.
|
||||
illegal_team_name=Il nome del Team contiene caratteri non validi.
|
||||
username_password_incorrect=Nome utente o password incorretti.
|
||||
enterred_invalid_repo_name=Si prega di assicurarsi che il nome del repository inserito sia corretto.
|
||||
enterred_invalid_owner_name=Si prega di assicurarsi che il nome del proprietario inserito sia corretto.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=Il tuo account possiede ancora almeno un repository, dovete prima
|
||||
still_has_org=Il tuo account è ancora associato ad almeno un'organizzazione, disassociarsi prima.
|
||||
org_still_own_repo=Questa organizzazione ha ancora la proprietà del repository, dovete cancellarla o trasferirli prima.
|
||||
|
||||
still_own_user=Questa autenticazione è ancora in uso da almeno un utente, per favore rimuovili dall'autenticazione e riprova.
|
||||
|
||||
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
|
||||
followers=Seguaci
|
||||
starred=Votate
|
||||
following=Seguiti
|
||||
follow=Segui
|
||||
unfollow=Non seguire più
|
||||
|
||||
form.name_reserved=L'username '%s' è riservato.
|
||||
form.name_pattern_not_allowed=La struttura del nome utente '%s' non è consentita.
|
||||
@@ -247,22 +245,22 @@ uid=Uid
|
||||
|
||||
public_profile=Profilo pubblico
|
||||
profile_desc=Il tuo indirizzo e-mail è pubblico e sarà usato per ogni notifica inerente al tuo account, e per qualsiasi operazione web effettuata attraverso il sito.
|
||||
password_username_disabled=Gli utenti non locali non possono cambiare il proprio nome utente.
|
||||
full_name=Nome Completo
|
||||
website=Sito web
|
||||
location=Posizione
|
||||
update_profile=Aggiorna Profilo
|
||||
update_profile_success=Il tuo profilo è stato aggiornato con successo.
|
||||
change_username=Username Cambiato
|
||||
change_username_prompt=This change will affect the way how links relate to your account.
|
||||
change_username_prompt=Questa modifica influenzerà il modo in cui i link si riferiscono al tuo account.
|
||||
continue=Continua
|
||||
cancel=Annulla
|
||||
|
||||
enable_custom_avatar=Abilita avatar personalizzato
|
||||
enable_custom_avatar_helper=Seleziona per disabilitare il fetch da Gravatar
|
||||
choose_new_avatar=Scegli un nuovo avatar
|
||||
update_avatar=Aggiorna le impostazioni avatar
|
||||
delete_current_avatar=Elimina Avatar attuale
|
||||
uploaded_avatar_not_a_image=Il file caricato non è un'immagine.
|
||||
no_custom_avatar_available=Nessun avatar personalizzato disponibile, impossibile abilitarlo.
|
||||
update_avatar_success=Le tue impostazioni avatar sono state aggiornate con successo.
|
||||
|
||||
change_password=Cambia Password
|
||||
@@ -271,6 +269,7 @@ new_password=Nuova Password
|
||||
retype_new_password=Re-inserisci la password
|
||||
password_incorrect=La Password attuale non è corretta.
|
||||
change_password_success=La tua password è stata cambiata con successo. Ora puoi accedere usando la nuova password.
|
||||
password_change_disabled=Gli utenti non locali non possono cambiare la propria password.
|
||||
|
||||
emails=Indirizzi e-mail
|
||||
manage_emails=Gestisci indirizzi email
|
||||
@@ -278,9 +277,9 @@ email_desc=Il tuo indirizzo e-mail primario sarà usato per le notifiche e altre
|
||||
primary=Primario
|
||||
primary_email=Imposta come primario
|
||||
delete_email=Elimina
|
||||
email_deletion=E-mail Deletion
|
||||
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success=E-mail has been deleted successfully!
|
||||
email_deletion=Eliminazione e-mail
|
||||
email_deletion_desc=La procedura di rimozione indirizzo email eliminerà tutte le informazioni correlate dal tuo account. Si desidera continuare?
|
||||
email_deletion_success=Indirizzo e-mail eliminato con successo!
|
||||
add_new_email=Aggiungi un nuovo indirizzo E-mail
|
||||
add_email=Aggiungi E-mail
|
||||
add_email_confirmation_sent=Una nuova email di conferma è stata inviata a '%s', per favore controlla la tua posta in arrivo nelle prossime %d ore per completare il processo di registrazione.
|
||||
@@ -291,14 +290,14 @@ add_key=Aggiungi Chiave
|
||||
ssh_desc=Questa è una lista di chiavi SSH associate al tuo account. Poiché queste chiavi consentono a chiunque di ottenere accesso alle tue repository, è molto importante che tu le riconosca.
|
||||
ssh_helper=<strong>Non sai come?</strong> Controlla la guida di GitHub sul <a href="%s">creare le tue chiavi SSH</a> o sul risolvere <a href="%s">problemi frequenti</a> che potresti incontrare usando SSH.
|
||||
add_new_key=Aggiungi Chiave SSH
|
||||
ssh_key_been_used=Public key content has been used.
|
||||
ssh_key_name_used=Public key with same name has already existed.
|
||||
ssh_key_been_used=È stato utilizzato il contenuto della chiave pubblica.
|
||||
ssh_key_name_used=Chiave pubblica con lo stesso nome esiste già.
|
||||
key_name=Nome della Chiave
|
||||
key_content=Contenuto
|
||||
add_key_success=New SSH key '%s' has been added successfully!
|
||||
add_key_success=La nuova chiave SSH '%s' è stata aggiunta con successo!
|
||||
delete_key=Elimina
|
||||
ssh_key_deletion=SSH Key Deletion
|
||||
ssh_key_deletion_desc=Delete this SSH key will remove all related accesses for your account. Do you want to continue?
|
||||
ssh_key_deletion=Eliminazione chiave SSH
|
||||
ssh_key_deletion_desc=Cancellare la chiave SSH rimuoverà tutti i relativi accessi per il tuo account. Vuoi continuare?
|
||||
ssh_key_deletion_success=La chiave SSH e' stata cancellata con successo!
|
||||
add_on=Aggiunto il
|
||||
last_used=Ultimo accesso il
|
||||
@@ -313,15 +312,15 @@ unbind_success=Account sociale disassociato.
|
||||
|
||||
manage_access_token=Gestisci i Token di Accesso Personale
|
||||
generate_new_token=Genera Nuovo Token
|
||||
tokens_desc=Tokens you have generated that can be used to access the Gogs APIs.
|
||||
tokens_desc=I Token che hai generato e che possono essere utilizzati per accedere alle API Gogs.
|
||||
new_token_desc=Da questo momento, ogni token avrà pieno accesso al tuo account.
|
||||
token_name=Nome Token
|
||||
generate_token=Genera Token
|
||||
generate_token_succees=Nuovo token di accesso generato con successo! Assicurarsi di copiare il nuovo token di accesso personale ora: non sarà possibile visualizzarlo nuovamente!
|
||||
delete_token=Elimina
|
||||
access_token_deletion=Personal Access Token Deletion
|
||||
access_token_deletion_desc=Delete this personal access token will remove all related accesses of application. Do you want to continue?
|
||||
delete_token_success=Personal access token has been removed successfully! Don't forget to update your application as well.
|
||||
access_token_deletion=Eliminazione Token di accesso personale
|
||||
access_token_deletion_desc=Eliminare questo token di accesso personale rimuoverà tutti i relativi accessi di applicazione. Si desidera continuare?
|
||||
delete_token_success=Il token di accesso personale è stato eliminato! Non dimenticare di aggiornare anche l'applicazione.
|
||||
|
||||
delete_account=Elimina Account
|
||||
delete_prompt=L'operazione eliminerà permanentemente l'account e <strong>NON POTRÀ</strong> essere annullata!
|
||||
@@ -334,9 +333,9 @@ owner=Proprietario
|
||||
repo_name=Nome Repository
|
||||
repo_name_helper=I migliori nomi dei repository sono brevi, facili da memorizzare e <strong>univoci</strong>.
|
||||
visibility=Visibilità
|
||||
visiblity_helper=This repository is <span class="ui red text">Private</span>
|
||||
visiblity_helper_forced=Site admin has forced all new repositories to be <span class="ui red text">Private</span>
|
||||
visiblity_fork_helper=(Change of this value will affect all forks)
|
||||
visiblity_helper=Questo repository è <span class="ui red text"> privato</span>
|
||||
visiblity_helper_forced=L'amministratore del sito ha deciso che tutti i nuovi repository devono essere <span class="ui red text">privati</span>
|
||||
visiblity_fork_helper=(La modifica di questo valore avrà effetto su tutti i fork)
|
||||
clone_helper=Hai bisogno di aiuto per la clonazione? Visita <a target="_blank" href="%s">Aiuto</a>!
|
||||
fork_repo=Forka Repository
|
||||
fork_from=Forka da
|
||||
@@ -348,32 +347,38 @@ license=Licenza
|
||||
license_helper=Selezionare un file di licenza
|
||||
readme=Readme
|
||||
readme_helper=Seleziona un template per il readme
|
||||
auto_init=Initialize this repository with selected files and template
|
||||
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)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=Indirizzo del mirror
|
||||
mirror_address_desc=Si prega di includere nell'indirizzo le credenziali utente necessarie.
|
||||
watchers=Osservatori
|
||||
stargazers=Fan
|
||||
forks=Fork
|
||||
|
||||
form.reach_limit_of_creation=Il proprietario ha raggiunto il limite massimo di %d repository creati.
|
||||
form.name_reserved=Il nome repository %s è riservato.
|
||||
form.name_pattern_not_allowed=La struttura del nome del repository %s non è consentita.
|
||||
|
||||
need_auth=Richiesta di autorizzazione
|
||||
migrate_type=Tipo di migrazione
|
||||
migrate_type_helper=This repository will be a <span class="text blue">mirror</span>
|
||||
migrate_type_helper=Questo repository sarà un <span class="text blue">mirror</span>
|
||||
migrate_repo=Migra Repository
|
||||
migrate.clone_address=Duplica Indirizzo
|
||||
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL or local server path.
|
||||
migrate.permission_denied=You are not allowed to import local repositories.
|
||||
migrate.clone_address_desc=Può essere un URL HTTP/HTTPS/GIT o il percorso del server locale.
|
||||
migrate.permission_denied=Non è consentito importare repository locali.
|
||||
migrate.invalid_local_path=Percorso locale non valido, non esiste o non è una cartella.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Migrazione non riuscita: %v
|
||||
|
||||
mirror_from=mirror da
|
||||
forked_from=forkato da
|
||||
fork_from_self=Non puoi forkare il tuo stesso repository!
|
||||
copy_link=Copia
|
||||
copy_link_success=Copiato!
|
||||
copy_link_error=Press ⌘-C or Ctrl-C to copy
|
||||
copy_link_error=Premere ⌘-C o Ctrl-C per copiare
|
||||
copied=OK copiato
|
||||
unwatch=Non seguire più
|
||||
watch=Segui
|
||||
@@ -386,11 +391,12 @@ quick_guide=Guida rapida
|
||||
clone_this_repo=Clona questo repository
|
||||
create_new_repo_command=Crea nuovo repository da riga di comando
|
||||
push_exist_repo=Push un repo esistente dalla riga di comando
|
||||
repo_is_empty=This repository is empty, please come back later!
|
||||
repo_is_empty=Questo repository è vuoto, si prega di tornare più tardi!
|
||||
|
||||
code=Codice
|
||||
branch=Ramo (Branch)
|
||||
tree=Albero (Tree)
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filtra per branch o tag
|
||||
branches=Rami (Branch)
|
||||
tags=Tag
|
||||
issues=Problemi
|
||||
@@ -418,62 +424,62 @@ issues.new.labels=Etichette
|
||||
issues.new.no_label=Nessuna etichetta
|
||||
issues.new.clear_labels=Pulisci le etichette
|
||||
issues.new.milestone=Traguardo
|
||||
issues.new.no_milestone=No Milestone
|
||||
issues.new.clear_milestone=Clear milestone
|
||||
issues.new.open_milestone=Open Milestones
|
||||
issues.new.closed_milestone=Closed Milestones
|
||||
issues.new.no_milestone=Nessuna milestone
|
||||
issues.new.clear_milestone=Milestone pulita
|
||||
issues.new.open_milestone=Apri Milestone
|
||||
issues.new.closed_milestone=Milestone chiuse
|
||||
issues.new.assignee=Assegnatario
|
||||
issues.new.clear_assignee=Clear assignee
|
||||
issues.new.no_assignee=No assignee
|
||||
issues.create=Create Issue
|
||||
issues.new.clear_assignee=Cancella l'assegnatario
|
||||
issues.new.no_assignee=Nessun assegnatario
|
||||
issues.create=Crea Problema
|
||||
issues.new_label=Nuova etichetta
|
||||
issues.new_label_placeholder=Nome dell'etichetta...
|
||||
issues.create_label=Create Label
|
||||
issues.create_label=Crea Etichetta
|
||||
issues.open_tab=%d Aperti
|
||||
issues.close_tab=%d Chiusi
|
||||
issues.filter_label=Etichetta
|
||||
issues.filter_label_no_select=Nessuna etichetta selezionata
|
||||
issues.filter_milestone=Traguardo
|
||||
issues.filter_milestone_no_select=No selected milestone
|
||||
issues.filter_milestone_no_select=Nessuna Milestone selezionata
|
||||
issues.filter_assignee=Assegnatario
|
||||
issues.filter_assginee_no_select=No selected Assignee
|
||||
issues.filter_assginee_no_select=Nessun Assegnatario selezionato
|
||||
issues.filter_type=Tipo
|
||||
issues.filter_type.all_issues=Tutti i problemi
|
||||
issues.filter_type.assigned_to_you=Assegnati a te
|
||||
issues.filter_type.created_by_you=Creati da te
|
||||
issues.filter_type.mentioning_you=Che ti riguardano
|
||||
issues.filter_sort=Ordina
|
||||
issues.filter_sort.latest=Newest
|
||||
issues.filter_sort.oldest=Oldest
|
||||
issues.filter_sort.recentupdate=Recently updated
|
||||
issues.filter_sort.leastupdate=Least recently updated
|
||||
issues.filter_sort.mostcomment=Most commented
|
||||
issues.filter_sort.leastcomment=Least commented
|
||||
issues.opened_by=opened %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=opened %[1]s by %[2]s
|
||||
issues.filter_sort.latest=Più recenti
|
||||
issues.filter_sort.oldest=Più vecchi
|
||||
issues.filter_sort.recentupdate=Aggiornati di recente
|
||||
issues.filter_sort.leastupdate=Aggiornati tempo fa
|
||||
issues.filter_sort.mostcomment=I più commentati
|
||||
issues.filter_sort.leastcomment=I meno commentati
|
||||
issues.opened_by=aperto %[1]s da <a href="/%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=aperto %[1]s da %[2]s
|
||||
issues.previous=Pagina precedente
|
||||
issues.next=Pagina successiva
|
||||
issues.open_title=Open
|
||||
issues.closed_title=Closed
|
||||
issues.num_comments=%d comments
|
||||
issues.open_title=Aperto
|
||||
issues.closed_title=Chiuso
|
||||
issues.num_comments=%d commenti
|
||||
issues.commented_at=`commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.no_content=There is no content yet.
|
||||
issues.no_content=Non ci sono ancora contenuti.
|
||||
issues.close_issue=Chiudi
|
||||
issues.close_comment_issue=Comment and close
|
||||
issues.reopen_issue=Reopen
|
||||
issues.reopen_comment_issue=Comment and reopen
|
||||
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=Poster
|
||||
issues.admin=Amministratore
|
||||
issues.poster=Autore
|
||||
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.edit=Edit
|
||||
issues.cancel=Cancel
|
||||
issues.save=Save
|
||||
issues.sign_in_require_desc=per partecipare a questa conversazione. Possiedi già un account?<a href="%s">Fai il login per commentare</a>
|
||||
issues.edit=Modifica
|
||||
issues.cancel=Annulla
|
||||
issues.save=Salva
|
||||
issues.label_title=Nome etichetta
|
||||
issues.label_color=Colore etichetta
|
||||
issues.label_count=%d etichette
|
||||
@@ -484,80 +490,124 @@ issues.label_modify=Modifica Etichetta
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.compare_changes=Compare Changes
|
||||
pulls.compare_changes_desc=Compare two branches and make a pull request for changes.
|
||||
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=compare
|
||||
pulls.filter_branch=Filter branch
|
||||
pulls.no_results=No results found.
|
||||
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.compare_compare=confronta
|
||||
pulls.filter_branch=Filtra branch
|
||||
pulls.no_results=Nessun risultato trovato.
|
||||
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.tab_conversation=Conversation
|
||||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Files changed
|
||||
pulls.reopen_to_merge=Please reopen this pull request to perform merge operation.
|
||||
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.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=You can perform auto-merge operation on this pull request.
|
||||
pulls.cannot_auto_merge_desc=You can't perform auto-merge operation because there are conflicts between commits.
|
||||
pulls.cannot_auto_merge_helper=Please use command line tool to solve it.
|
||||
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=Unito
|
||||
pulls.has_merged=Questa pull reqeust è stata mergiata con successo!
|
||||
pulls.data_broken=I dati di questa pull request si sono rotti causa dell'eliminazione delle informazioni di fork.
|
||||
pulls.is_checking=Il controllo dei conflitti è ancora in corso, per favore aggiorna pagina tra qualche istante.
|
||||
pulls.can_auto_merge_desc=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=New 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.create=Create Milestone
|
||||
milestones.title=Title
|
||||
milestones.desc=Description
|
||||
milestones.due_date=Due Date (optional)
|
||||
milestones.clear=Clear
|
||||
milestones.invalid_due_date_format=Due date format is invalid, must be 'yyyy-mm-dd'.
|
||||
milestones.create_success=Milestone '%s' has been created successfully!
|
||||
milestones.edit=Edit Milestone
|
||||
milestones.edit_subheader=Use better description for milestones so people won't be confused.
|
||||
milestones.cancel=Cancel
|
||||
milestones.modify=Modify Milestone
|
||||
milestones.edit_success=Changes of milestone '%s' has been saved successfully!
|
||||
milestones.deletion=Milestone Deletion
|
||||
milestones.deletion_desc=Delete this milestone will remove its information in all related issues. Do you want to continue?
|
||||
milestones.deletion_success=Milestone has been deleted successfully!
|
||||
milestones.new=Nuova Milestone
|
||||
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=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
|
||||
milestones.edit_subheader=Scrivi una descrizione della Milestone, così la gente non si confonderà.
|
||||
milestones.cancel=Annulla
|
||||
milestones.modify=Modifica Milestone
|
||||
milestones.edit_success=Le modifiche alla milestone '%s' sono state salvate con successo!
|
||||
milestones.deletion=Cancellazione Milestone
|
||||
milestones.deletion_desc=L'eliminazione di questa Milestone rimuoverà le sue informazioni in tutti i problemi correlati. Si desidera continuare?
|
||||
milestones.deletion_success=La milestone è stata cancellata con successo!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Benvenuto nel Wiki!
|
||||
wiki.welcome_desc=Wiki è il posto dove puoi documentare collaborativamente il tuo progetto così da renderlo migliore.
|
||||
wiki.create_first_page=Crea la prima pagina
|
||||
wiki.page=Pagina
|
||||
wiki.filter_page=Filtra pagina
|
||||
wiki.new_page=Crea nuova pagina
|
||||
wiki.default_commit_message=Scrivere una nota su questo aggiornamento (opzionale).
|
||||
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=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
|
||||
|
||||
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.danger_zone=Zona Pericolosa
|
||||
settings.site=Sito Ufficiale
|
||||
settings.update_settings=Aggiorna Impostazioni
|
||||
settings.change_reponame_prompt=This change will affect how links relate to the repository.
|
||||
settings.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.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=Abilita l'issue tracker builtin leggero
|
||||
settings.use_external_issue_tracker=Utilizza gestore di problemi esterno
|
||||
settings.tracker_url_format=Formato URL Gestore Problemi Esterno
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc=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=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=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.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
|
||||
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.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.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 be became independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.transfer_form_title=Per favore inserisci le informazioni seguenti per confermare l'operazione:
|
||||
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=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=- 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
|
||||
settings.make_transfer=Trasferisci
|
||||
@@ -565,16 +615,23 @@ 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=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=Search user...
|
||||
settings.search_user_placeholder=Cerca utente...
|
||||
settings.org_not_allowed_to_be_collaborator=Un'organizzazione non può essere aggiunta come collaboratore.
|
||||
settings.user_is_org_member=L'utente è un membro dell'organizzazione che non può essere aggiunto come collaboratore.
|
||||
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=Delete Webhook
|
||||
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.request=Request
|
||||
settings.webhook.response=Response
|
||||
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=Richiesta
|
||||
settings.webhook.response=Risposta
|
||||
settings.webhook.headers=Headers
|
||||
settings.webhook.payload=Payload
|
||||
settings.webhook.body=Body
|
||||
@@ -587,17 +644,17 @@ settings.add_webhook_desc=Gogs manderà una richiesta <code>POST</code> all'URL
|
||||
settings.payload_url=Payload URL
|
||||
settings.content_type=Content Type
|
||||
settings.secret=Secret
|
||||
settings.slack_username=Username
|
||||
settings.slack_icon_url=Icon URL
|
||||
settings.slack_color=Color
|
||||
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_create=Create
|
||||
settings.event_create_desc=Branch, or tag created
|
||||
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, o tag creato
|
||||
settings.event_push=Push
|
||||
settings.event_push_desc=Git push to a repository
|
||||
settings.event_push_desc=Git push in un repository
|
||||
settings.active=Attivo
|
||||
settings.active_helper=Anche i dettagli riguardanti l'evento che ha innescato l'hook saranno inviati.
|
||||
settings.add_hook_success=Il nuovo webhook è stato aggiunto.
|
||||
@@ -611,25 +668,30 @@ settings.slack_token=Token
|
||||
settings.slack_domain=Dominio
|
||||
settings.slack_channel=Canale
|
||||
settings.deploy_keys=Dispiega Chiavi
|
||||
settings.add_deploy_key=Add Deploy Key
|
||||
settings.no_deploy_keys=You haven't added any deploy key.
|
||||
settings.title=Title
|
||||
settings.deploy_key_content=Content
|
||||
settings.key_been_used=Deploy key content has been used.
|
||||
settings.key_name_used=Deploy key with same name has already existed.
|
||||
settings.add_key_success=New deploy key '%s' has been added successfully!
|
||||
settings.deploy_key_deletion=Delete Deploy Key
|
||||
settings.deploy_key_deletion_desc=Delete this deploy key will remove all related accesses for this repository. Do you want to continue?
|
||||
settings.deploy_key_deletion_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=Visualizzazione separata
|
||||
diff.show_unified_view=Visualizzazione unificata
|
||||
diff.stats_desc=<strong>%d ha cambiato i file</strong> con <strong>%d aggiunte</strong> e <strong>%d eliminazioni</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Vedi File
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=Rilasci
|
||||
release.new_release=Nuovo Rilascio
|
||||
@@ -644,27 +706,27 @@ 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=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=Cancela questa Release
|
||||
release.deletion=Eliminazione Release
|
||||
release.deletion_desc=Eliminando questa release cancellarai anche i tag Git corrispondenti. Vuoi continuare?
|
||||
release.deletion_success=La release è stata eliminata con successo!
|
||||
release.tag_name_already_exist=Un rilascio con questo tag esiste già.
|
||||
release.downloads=Downloads
|
||||
release.downloads=Download
|
||||
|
||||
[org]
|
||||
org_name_holder=Nome dell'Organizzazione
|
||||
org_full_name_holder=Organization Full Name
|
||||
org_full_name_holder=Nome completo dell'organizzazione
|
||||
org_name_helper=Le migliori organizzazioni hanno nomi brevi e memorabili.
|
||||
create_org=Crea Organizzazione
|
||||
repo_updated=Aggiornato
|
||||
@@ -691,7 +753,7 @@ settings.website=Sito Web
|
||||
settings.location=Residenza
|
||||
settings.update_settings=Aggiorna Impostazioni
|
||||
settings.update_setting_success=Impostazioni dell'organizzazione aggiornate con successo.
|
||||
settings.change_orgname_prompt=This change will affect how links relate to the organization.
|
||||
settings.change_orgname_prompt=Questa operazione modificherà il modo in cui i links sono in relazione con l'organizzazione.
|
||||
settings.update_avatar_success=Organization avatar setting has been updated successfully.
|
||||
settings.delete=Elimina organizzazione
|
||||
settings.delete_account=Elimina questa organizzazione
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=Eliminazione Organizzazione
|
||||
settings.delete_org_desc=Questa organizzazione sta per essere eliminato in modo permanente, vuoi continuare?
|
||||
settings.hooks_desc=Aggiungi i webhooks che verranno attivati per <strong>tutti i repository</strong> sotto questa organizzazione.
|
||||
|
||||
members.membership_visibility=Membership Visibility:
|
||||
members.public=Pubblico
|
||||
members.public_helper=rendi privato
|
||||
members.private=Privato
|
||||
members.private_helper=rendi pubblico
|
||||
members.member_role=Ruolo del membro:
|
||||
members.owner=Proprietario
|
||||
members.member=Membro
|
||||
members.conceal=Nascondere
|
||||
members.remove=Rimuovere
|
||||
members.leave=Abbandona
|
||||
members.invite_desc=Digita un nome utente per invitare un nuovo membro a %s:
|
||||
members.invite_desc=Aggiungi un nuovo membro a %s:
|
||||
members.invite_now=Invita ora
|
||||
|
||||
teams.join=Iscriviti
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=Questo Team concede accesso di <strong>Lettura</stron
|
||||
teams.write_permission_desc=Questo Team concede accesso di <strong>Scrittura</strong>: i membri possono leggere e pushare i repository del Team.
|
||||
teams.admin_permission_desc=Questo Team concede accesso di <strong>Amministratore</strong>: i membri possono leggere i, pushare a, e aggiungere collaboratori ai repository del Team.
|
||||
teams.repositories=Repository di Squadra
|
||||
teams.search_repo_placeholder=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.
|
||||
@@ -748,9 +812,9 @@ authentication=Autenticazioni
|
||||
config=Configurazione
|
||||
notices=Avvisi di sistema
|
||||
monitor=Monitoraggio
|
||||
first_page=First
|
||||
last_page=Last
|
||||
total=Total: %d
|
||||
first_page=Prima
|
||||
last_page=Ultima
|
||||
total=Totale: %d
|
||||
|
||||
dashboard.statistic=Statistiche
|
||||
dashboard.operations=Operazioni
|
||||
@@ -773,6 +837,8 @@ dashboard.resync_all_sshkeys=Riscrivi il file '.ssh/authorized_keys' (attenzione
|
||||
dashboard.resync_all_sshkeys_success=Tutte le chiavi pubbliche riscritte con successo.
|
||||
dashboard.resync_all_update_hooks=Riscrivere tutti gli update hook dei repository (necessario quando il percorso di configurazione personalizzata viene modificato)
|
||||
dashboard.resync_all_update_hooks_success=Tutti gli update hook dei repository riscritti con successo.
|
||||
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.server_uptime=Tempo in Attività del Server
|
||||
dashboard.current_goroutine=Goroutine Correnti
|
||||
@@ -812,7 +878,7 @@ users.admin=Amministratore
|
||||
users.repos=Repo
|
||||
users.created=Creato
|
||||
users.send_register_notify=Send Registration Notification To User
|
||||
users.new_success=New account '%s' has been created successfully.
|
||||
users.new_success=Il nuovo account '%s' è stato creato correttamente.
|
||||
users.edit=Modifica
|
||||
users.auth_source=Authentication Source
|
||||
users.local=Locale
|
||||
@@ -820,15 +886,17 @@ 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=Limite massimo per la creazione di Repository
|
||||
users.max_repo_creation_desc=(Inserire -1 per usare il limite globale di default)
|
||||
users.is_activated=Questo account è attivato
|
||||
users.is_admin=Questo account ha permessi di amministratore
|
||||
users.allow_git_hook=Questo account ha il permesso di creare hooks di Git
|
||||
users.allow_import_local=This account has permissions to import local repositories
|
||||
users.allow_import_local=Questo account dispone delle autorizzazioni per importare repository locali
|
||||
users.update_profile=Aggiornare Profilo Account
|
||||
users.delete_account=Elimina Questo Account
|
||||
users.still_own_repo=Questo account possiede ancora almeno un repository, devi prima cancellarli o trasferirli.
|
||||
users.still_has_org=Questo account appartiene ancora ad almeno un'organizzazione, è necessario prima abbandonarle o eliminale.
|
||||
users.deletion_success=Account has been deleted successfully!
|
||||
users.deletion_success=Account eliminato correttamente!
|
||||
|
||||
orgs.org_manage_panel=Pannello Gestione Organizzazioni
|
||||
orgs.name=Nome
|
||||
@@ -844,45 +912,50 @@ 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.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.filter=User Filter
|
||||
auths.admin_filter=Admin Filter
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
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=Allowed Domains
|
||||
auths.allowed_domains=Domini consentiti
|
||||
auths.allowed_domains_helper=Leave it empty to not restrict any domains. Multiple domains should be separated by comma ','.
|
||||
auths.enable_tls=Abilitare Crittografia TLS
|
||||
auths.skip_tls_verify=Skip TLS Verify
|
||||
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.
|
||||
auths.deletion_success=Authentication has been deleted successfully!
|
||||
|
||||
config.server_config=Configurazione Server
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Percorso Root del File Statico
|
||||
config.log_file_root_path=Percorso Root del File di Log
|
||||
config.script_type=Tipo di Script
|
||||
config.reverse_auth_user=Autenticazione Utente Inversa
|
||||
|
||||
config.ssh_config=Configurazione SSH
|
||||
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=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
|
||||
config.db_host=Host
|
||||
@@ -907,20 +993,19 @@ config.db_user=Utente
|
||||
config.db_ssl_mode=Modalità SSL
|
||||
config.db_ssl_mode_helper=(solo per "postgres")
|
||||
config.db_path=Percorso
|
||||
config.db_path_helper=(for "sqlite3" and "tidb")
|
||||
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.enable_cache_avatar=Abilitare Cache dell'Avatar
|
||||
config.mail_notify=Email di Notifica
|
||||
config.disable_key_size_check=Disable Minimum Key Size Check
|
||||
config.enable_captcha=Enable Captcha
|
||||
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
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Disattiva HELO
|
||||
config.mailer_name=Nome
|
||||
config.mailer_host=Host
|
||||
config.mailer_user=Utente
|
||||
config.send_test_mail=Invia email di test
|
||||
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
|
||||
@@ -962,23 +1050,34 @@ monitor.start=Orario Avvio
|
||||
monitor.execute_time=Tempo di Esecuzione
|
||||
|
||||
notices.system_notice_list=Avvisi di Sistema
|
||||
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=Elimina tutti gli avvisi
|
||||
notices.type=Tipo
|
||||
notices.type_1=Repository
|
||||
notices.desc=Descrizione
|
||||
notices.op=Op.
|
||||
notices.delete_success=Avviso di sistema cancellato con successo.
|
||||
notices.delete_success=Gli avvisi di sistema sono stati successivamente eliminati.
|
||||
|
||||
[action]
|
||||
create_repo=ha creato il repository <a href="%s">%s</a>
|
||||
rename_repo=renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
rename_repo=repository rinominato da <code>%[1]s</code> a <a href="%[2]s">[3]s</a>
|
||||
commit_repo=ha pushato nel <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`ha aperto il problema <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>`
|
||||
create_pull_request=`creata 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>`
|
||||
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_2_commits=Vedi confronto per questi 2 commit
|
||||
compare_commits=Visualizza comparazione tra questi %d commit
|
||||
|
||||
[tool]
|
||||
ago=fa
|
||||
@@ -1002,8 +1101,8 @@ raw_seconds=secondi
|
||||
raw_minutes=minuti
|
||||
|
||||
[dropzone]
|
||||
default_message=Drop files here or click to upload.
|
||||
invalid_input_type=You can't upload files of this type.
|
||||
file_too_big=File size({{filesize}} MB) exceeds maximum size({{maxFilesize}} MB).
|
||||
remove_file=Remove file
|
||||
default_message=Trascina i file qui o clicca per caricare.
|
||||
invalid_input_type=Non è possibile caricare file di questo tipo.
|
||||
file_too_big=La dimensione del file ({{filesize}} MB) supera la dimensione massima ({{maxFilesize}} MB).
|
||||
remove_file=Rimuovi file
|
||||
|
||||
|
||||
299
conf/locale/locale_ja-JP.ini
Executable file → Normal file
299
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,39 +21,33 @@ username=ユーザ名
|
||||
email=E-mail
|
||||
password=パスワード
|
||||
re_type=再入力
|
||||
captcha=キャプチャ
|
||||
captcha=CAPTCHA
|
||||
|
||||
repository=リポジトリ
|
||||
organization=組織
|
||||
mirror=ミラー
|
||||
new_repo=新しいリポジトリ
|
||||
new_migrate=新しい移行
|
||||
new_mirror=新しいミラー
|
||||
new_fork=新しいフォークのリポジトリ
|
||||
new_org=新しい組織
|
||||
manage_org=組織を管理
|
||||
admin_panel=管理者パネル
|
||||
account_settings=アカウント設定
|
||||
settings=設定
|
||||
your_profile=あなたのプロファイル
|
||||
your_settings=あなたの設定
|
||||
your_profile=プロフィール
|
||||
your_settings=設定
|
||||
|
||||
news_feed=ニュースのフィード
|
||||
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=データベースの種類
|
||||
@@ -61,13 +55,13 @@ 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=SQLite3 または TiDB のデータベースのファイル パス。
|
||||
sqlite_helper=SQLite3かTiDBのデータベースのファイルパス。<br>サービスとして開始する際には絶対パスを利用してください。
|
||||
err_empty_db_path=SQLite3 または TiDB データベースのパスを空にすることはできません。
|
||||
err_invalid_tidb_name=TiDB データベース名は文字"."と"-"を許可しない。
|
||||
no_admin_and_disable_registration=You cannot disable registration without creating an admin account.
|
||||
no_admin_and_disable_registration=管理者アカウントを作成せずに登録を無効にすることはできません。
|
||||
err_empty_admin_password=管理者パスワードは空白にできません。
|
||||
|
||||
general_title=Gogs の全般設定
|
||||
@@ -78,16 +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_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>。
|
||||
@@ -96,10 +92,10 @@ mailer_password=送信者のパスワード
|
||||
register_confirm=登録の確認を有効にする
|
||||
mail_notify=メール通知を有効にする
|
||||
server_service_title=サーバーとその他のサービスの設定
|
||||
offline_mode=オフラインモード有効化
|
||||
offline_mode_popup=プロダクション モードでCDN を無効にし、すべてのリソースファイルをローカルで提供します 。
|
||||
offline_mode=オフラインモードを有効にする
|
||||
offline_mode_popup=プロダクションモードでは、CDNを使用せずにローカルからリソースファイルを使用します。
|
||||
disable_gravatar=Gravatarのサービスを無効にします
|
||||
disable_gravatar_popup=Disable Gravatar and custom sources, all avatars are uploaded by users or default.
|
||||
disable_gravatar_popup=Gravatarとカスタムソースを無効にして、全てのアバターをユーザーによってアップロードされたものかデフォルトなものにします。
|
||||
disable_registration=自己登録を無効にする
|
||||
disable_registration_popup=自己登録を無効にし、管理者のみがアカウント作成できる
|
||||
enable_captcha=Captchaを有効にする
|
||||
@@ -121,34 +117,37 @@ run_user_not_match=実行ユーザーは、現在のユーザーではない: %s
|
||||
save_config_failed=構成の保存に失敗した: %v
|
||||
invalid_admin_setting=管理者アカウントの設定が無効です: %v
|
||||
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
|
||||
invalid_log_root_path=ログのルートパスがむこうです: %v
|
||||
|
||||
[home]
|
||||
uname_holder=ユーザー名またはEメール
|
||||
password_holder=パスワード
|
||||
switch_dashboard_context=ダッシュ ボードのコンテキストを切替
|
||||
my_repos=私のリポジトリ
|
||||
my_repos=自分のリポジトリ
|
||||
collaborative_repos=共同リポジトリ
|
||||
my_orgs=私の組織
|
||||
my_mirrors=私のミラー
|
||||
my_orgs=自分の組織
|
||||
my_mirrors=自分のミラー
|
||||
view_home=ビュー %s
|
||||
|
||||
issues.in_your_repos=あなたのリポジトリ
|
||||
|
||||
[explore]
|
||||
repos=リポジトリ
|
||||
users=ユーザ
|
||||
search=検索
|
||||
|
||||
[auth]
|
||||
create_new_account=新規アカウントを作成
|
||||
register_hepler_msg=すでにアカウントをお持ちですか?今すぐログイン !
|
||||
social_register_hepler_msg=すでにアカウントをお持ちですか?今すぐバインド !
|
||||
disable_register_prompt=申し訳ありませんが、登録が無効になっています。サイト管理者に問い合わせてください。
|
||||
register_hepler_msg=既にアカウントをお持ちですか?今すぐログインしましょう!
|
||||
social_register_hepler_msg=既にアカウントをお持ちですか?連携しましょう!
|
||||
disable_register_prompt=申し訳ありませんが、現在登録は受け付けておりません。サイトの管理者にお問い合わせください。
|
||||
disable_register_mail=申し訳ありませんが、登録メールの確認機能が無効になっています。
|
||||
remember_me=ログイン状態を保持する
|
||||
remember_me=ログインしたままにする
|
||||
forgot_password=パスワードを忘れた
|
||||
forget_password=パスワードを忘れた?
|
||||
sign_up_now=アカウントが必要ですか?今すぐサインアップ
|
||||
forget_password=パスワードを忘れましたか?
|
||||
sign_up_now=アカウントが必要ですか?今すぐ登録しましょう!
|
||||
confirmation_mail_sent_prompt=新しい確認メールを <b>%s</b> に送りました。登録を完了させるために、%d時間以内にあなたのメールボックスを確認してください。
|
||||
active_your_account=アカウントをアクティブ
|
||||
active_your_account=アカウントを有効化
|
||||
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
|
||||
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
|
||||
resend_mail=アクティベーションメールを再送信するにはここをクリック
|
||||
@@ -158,13 +157,14 @@ reset_password=パスワードリセット
|
||||
invalid_code=申し訳ありませんが、確認用コードが期限切れまたは無効です。
|
||||
reset_password_helper=パスワードをリセットするにはここをクリック
|
||||
password_too_short=6文字未満のパスワードは設定できません。
|
||||
non_local_account=Non-local accounts cannot change passwords through Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=あなたのアカウントを有効にしてください。
|
||||
activate_email=電子メール アドレスを確認します。
|
||||
reset_password=パスワードをリセットします.
|
||||
register_success=ようこそ、登録成功
|
||||
register_notify=Welcome on board
|
||||
register_notify=ボードへようこそ
|
||||
|
||||
[modal]
|
||||
yes=はい
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=リポジトリ名は既に使用されています。
|
||||
org_name_been_taken=組織名は既に使用されています。
|
||||
team_name_been_taken=チーム名は既に使用されています。
|
||||
email_been_used=電子メール アドレスは既に使用されています。
|
||||
illegal_team_name=チーム名に無効な文字が含まれています。
|
||||
username_password_incorrect=ユーザー名またはパスワードが正しくありません。
|
||||
enterred_invalid_repo_name=入力したリポジトリの名前が正しいかどうかを確認してください。
|
||||
enterred_invalid_owner_name=入力された所有者名が正しいかどうかを確認してください。
|
||||
@@ -218,19 +217,18 @@ still_own_repo=アカウント所有のリポジトリがあり、リポジト
|
||||
still_has_org=アカウントはまだ組織のメンバーであり、組織から退出するか削除する必要があります。
|
||||
org_still_own_repo=この組織はまだリポジトリの所有しています、リポジトリを削除または転送する必要があります。
|
||||
|
||||
still_own_user=この認証はまだ一部のユーザーによって使用されています。一部のユーザを移動させてから、もう一度削除してください。
|
||||
|
||||
target_branch_not_exist=ターゲットブランチが存在しない
|
||||
|
||||
[user]
|
||||
change_avatar=gravatar.com で自分のアバターを変更
|
||||
change_custom_avatar=設定で自分のアバターを変更
|
||||
change_avatar=アバターを変更
|
||||
join_on=参加しました
|
||||
repositories=リポジトリ
|
||||
activity=パブリック・アクティビティ
|
||||
followers=フォロワー
|
||||
starred=スター
|
||||
following=フォロー
|
||||
follow=フォロー
|
||||
unfollow=フォロー解除
|
||||
|
||||
form.name_reserved=ユーザー名 '%s' は予約されています。
|
||||
form.name_pattern_not_allowed=ユーザ名のパターン '%s' は許可されていません。
|
||||
@@ -247,6 +245,7 @@ uid=Uid
|
||||
|
||||
public_profile=パブリック プロフィール
|
||||
profile_desc=あなたのメールアドレスは公開され、任意のアカウント関連の通知に使用されます。また、Webベースの操作はサイトを介して行います。
|
||||
password_username_disabled=ローカルユーザ以外はユーザ名を変更できません。
|
||||
full_name=フルネーム
|
||||
website=WEBサイト
|
||||
location=ロケーション
|
||||
@@ -258,11 +257,10 @@ continue=続行
|
||||
cancel=キャンセル
|
||||
|
||||
enable_custom_avatar=カスタムのアバターを有効にする
|
||||
enable_custom_avatar_helper=Gravatarからのフェッチを無効にするのを、有効にします
|
||||
choose_new_avatar=新しいアバターを選択
|
||||
update_avatar=アバターの設定を更新
|
||||
delete_current_avatar=現在のアバターを削除
|
||||
uploaded_avatar_not_a_image=アップロードされたファイルは画像ではない。
|
||||
no_custom_avatar_available=利用可能なカスタム アバターがないため、有効にできません。
|
||||
update_avatar_success=あなたのアバターの設定が更新されました。
|
||||
|
||||
change_password=パスワードを変更
|
||||
@@ -271,6 +269,7 @@ new_password=新しいパスワード
|
||||
retype_new_password=新しいパスワードを再入力します。
|
||||
password_incorrect=現在のパスワードが正しくありません。
|
||||
change_password_success=パスワードが正常に変更されました。今すぐ新しいパスワード経由でサインインすることができます。
|
||||
password_change_disabled=ローカルユーザ以外はパスワードを変更できません。
|
||||
|
||||
emails=E-mail アドレス
|
||||
manage_emails=E-mail アドレスを管理
|
||||
@@ -311,7 +310,7 @@ social_desc=これは関連付けられたソーシャルアカウントのリ
|
||||
unbind=バインド解除
|
||||
unbind_success=SNSアカウントがバインドされていない。
|
||||
|
||||
manage_access_token=個人のアクセス トークンを管理
|
||||
manage_access_token=パーソナルアクセス トークンを管理
|
||||
generate_new_token=新しいトークンを生成
|
||||
tokens_desc=生成したトークンを利用して Gogs の API にアクセスすることができます。
|
||||
new_token_desc=今のところ、全てのトークンはあなたのアカウントにフルアクセスできます。
|
||||
@@ -324,7 +323,7 @@ access_token_deletion_desc=パーソナルアクセストークンを削除す
|
||||
delete_token_success=パーソナルアクセストークンは正常に削除されました!同時にあなたのアプリケーションを更新することを忘れないでください。
|
||||
|
||||
delete_account=アカウントを削除
|
||||
delete_prompt=この操作はあなたのアカウントを完全に削除し、復旧<strong>できない</strong> !
|
||||
delete_prompt=この操作をするとアカウントが完全に削除され、<strong>二度と元に戻すことができなくなります</strong> !
|
||||
confirm_delete_account=削除の確認
|
||||
delete_account_title=アカウントの削除
|
||||
delete_account_desc=このアカウントは永久に削除しようとしている、継続しますか?
|
||||
@@ -332,15 +331,15 @@ delete_account_desc=このアカウントは永久に削除しようとしてい
|
||||
[repo]
|
||||
owner=オーナー
|
||||
repo_name=リポジトリ名
|
||||
repo_name_helper=偉大なリポジトリ名は短い。思い出に残り、そして<strong>一意</strong>だ。
|
||||
visibility=ビジビリティ
|
||||
repo_name_helper=短くて分かりやすく<strong>重複しない</strong>リポジトリ名を決めてください。
|
||||
visibility=公開/非公開
|
||||
visiblity_helper=このリポジトリは<span class="ui red text">プライベート</span>です。
|
||||
visiblity_helper_forced=サイト管理者は、強制的にすべての新しいリポジトリを<span class="ui red text"> プライベート</span> にしています。
|
||||
visiblity_fork_helper=(この値の変更はすべてのフォークに適用されます)
|
||||
clone_helper=クローニングのヘルプが必要ですか?<a target="_blank"href="%s"> ヘルプ</a> を参照してください!
|
||||
fork_repo=フォークのリポジトリ
|
||||
clone_helper=クローンに関してお困りであれば<a target="_blank"href="%s"> ヘルプ</a> を参照しましょう。
|
||||
fork_repo=リポジトリをフォーク
|
||||
fork_from=フォーク元
|
||||
fork_visiblity_helper=フォークされたリポジトリは可視状態を変更できません
|
||||
fork_visiblity_helper=フォークされたリポジトリの可視状態は変更できません。
|
||||
repo_desc=説明
|
||||
repo_lang=言語
|
||||
repo_lang_helper=.gitignoreファイルを選択
|
||||
@@ -351,13 +350,18 @@ 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=ミラー 間隔(時)
|
||||
watchers=Watchers
|
||||
mirror_address=ミラー アドレス
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
watchers=ウォッチャー
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
forks=フォーク
|
||||
|
||||
form.name_reserved=リポジトリ名 '%s' は予約されています。
|
||||
form.name_pattern_not_allowed=リポジトリ名のパターン '%s' は許可されていません。
|
||||
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' は使用できません。
|
||||
|
||||
need_auth=認証が必要
|
||||
migrate_type=マイグレーションの種類
|
||||
@@ -365,10 +369,11 @@ migrate_type_helper=このリポジトリは、<span class="text blue"> ミラ
|
||||
migrate_repo=リポジトリを移行
|
||||
migrate.clone_address=クローンアドレス
|
||||
migrate.clone_address_desc=これは、HTTP/HTTPS/GIT URL またはローカル サーバー パスを設定できます。
|
||||
migrate.permission_denied=You are not allowed to import local repositories.
|
||||
migrate.permission_denied=ローカル リポジトリをインポートすることはできません。
|
||||
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=移行に失敗しました: %v
|
||||
|
||||
mirror_from=同期ミラー
|
||||
forked_from=フォーク元
|
||||
fork_from_self=すでにあなたの所有しているリポジトリはフォークできません
|
||||
copy_link=コピー
|
||||
@@ -388,9 +393,10 @@ create_new_repo_command=コマンドラインで新しいリポジトリを作
|
||||
push_exist_repo=コマンド ・ ラインから既存のリポジトリをプッシュ
|
||||
repo_is_empty=このリポジトリは空です、後で戻って来て下さい!
|
||||
|
||||
code=コード
|
||||
branch=ブランチ
|
||||
tree=ツリー
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=ブランチまたはタグをフィルタリング
|
||||
branches=ブランチ
|
||||
tags=タグ
|
||||
issues=課題
|
||||
@@ -399,9 +405,9 @@ labels=ラベル
|
||||
milestones=マイルストーン
|
||||
commits=コミット
|
||||
releases=リリース
|
||||
file_raw=生データ
|
||||
file_raw=Raw
|
||||
file_history=履歴
|
||||
file_view_raw=生データを見る
|
||||
file_view_raw=Rawデータを見る
|
||||
file_permalink=パーマリンク
|
||||
|
||||
commits.commits=コミット
|
||||
@@ -439,14 +445,14 @@ 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=最新
|
||||
issues.filter_sort.oldest=最も古い
|
||||
issues.filter_sort.recentupdate=最近更新された
|
||||
issues.filter_sort.leastupdate=Least recently updated
|
||||
issues.filter_sort.leastupdate=つい最近更新
|
||||
issues.filter_sort.mostcomment=一番多いコメント
|
||||
issues.filter_sort.leastcomment=一番少ないコメント
|
||||
issues.opened_by=opened %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
@@ -456,10 +462,10 @@ issues.next=次ページ
|
||||
issues.open_title=オープン
|
||||
issues.closed_title=クローズ
|
||||
issues.num_comments=%d コメント
|
||||
issues.commented_at=`commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commented_at=`コメント <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.no_content=まだコンテンツがありません
|
||||
issues.close_issue=閉じる
|
||||
issues.close_comment_issue=コメントと閉じる
|
||||
issues.close_comment_issue=コメントしてクローズ
|
||||
issues.reopen_issue=Reopen
|
||||
issues.reopen_comment_issue=コメントと再開
|
||||
issues.create_comment=コメント
|
||||
@@ -467,7 +473,7 @@ issues.closed_at=`closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=ポスター
|
||||
issues.admin=アドミン
|
||||
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>
|
||||
@@ -484,8 +490,9 @@ issues.label_modify=ラベルの変更
|
||||
issues.label_deletion=ラベルの削除
|
||||
issues.label_deletion_desc=ラベルを削除すると、関連するすべての問題の情報が削除されます。続行しますか。
|
||||
issues.label_deletion_success=ラベルは正常に削除されました。
|
||||
issues.num_participants=%d Participants
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=新しいプルリクエスト
|
||||
pulls.compare_changes=変更を比較
|
||||
pulls.compare_changes_desc=2つのブランチを比較し、プルリクエストを作成します。
|
||||
pulls.compare_base=ベース
|
||||
@@ -505,9 +512,9 @@ pulls.merged=マージされた
|
||||
pulls.has_merged=このプルプルリクエストは正常にマージされました!
|
||||
pulls.data_broken=Data of this pull request has been broken due to deletion of fork information.
|
||||
pulls.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=You can perform auto-merge operation on this pull request.
|
||||
pulls.cannot_auto_merge_desc=You can't perform auto-merge operation because there are conflicts between commits.
|
||||
pulls.cannot_auto_merge_helper=それを解決するためにコマンド ライン ツールを使用してください。
|
||||
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.cannot_auto_merge_helper=競合を解決するためには、手動でマージする必要があります。
|
||||
pulls.merge_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.`
|
||||
|
||||
@@ -535,44 +542,94 @@ milestones.deletion=マイルス トーンの削除
|
||||
milestones.deletion_desc=このマイルス トーンを削除すると、関連課題に該当情報が削除されます。続行しますか。
|
||||
milestones.deletion_success=マイルス トーンは正常に削除されました。
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Wiki へようこそ!
|
||||
wiki.welcome_desc=Wikiとは、あなたのプロジェクトを文書化し、複数人で一緒に編集する場所です。
|
||||
wiki.create_first_page=最初のページを作成する。
|
||||
wiki.page=ページ
|
||||
wiki.filter_page=フィルターページ
|
||||
wiki.new_page=新しいページを作成
|
||||
wiki.default_commit_message=このアップデートについてメモを書く(オプション)
|
||||
wiki.save_page=ページを保存
|
||||
wiki.last_commit_info=%s このページを編集 %s
|
||||
wiki.edit_page_button=編集
|
||||
wiki.new_page_button=新規ページ
|
||||
wiki.delete_page_button=Delete Page
|
||||
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
|
||||
wiki.page_already_exists=既に同じ名前のWiki ページが存在します。
|
||||
wiki.pages=ページ
|
||||
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.danger_zone=危険地帯
|
||||
settings.site=公式サイト
|
||||
settings.update_settings=設定の更新
|
||||
settings.change_reponame_prompt=この変更はリンクがリポジトリに関連付ける方法に影響します。
|
||||
settings.advanced_settings=拡張設定
|
||||
settings.wiki_desc=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.use_external_issue_tracker=外部課題トラッキングシステムを使用
|
||||
settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc=Enable pull requests to accept public contributions
|
||||
settings.danger_zone=危険地帯
|
||||
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_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.transfer=オーナー移転
|
||||
settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。
|
||||
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
|
||||
settings.delete=このリポジトリを削除
|
||||
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
|
||||
settings.transfer_notices_1=-新しい所有者が個人ユーザーの場合、あなたがアクセスできなくなります。
|
||||
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=操作を確認するために、以下の情報を入力してください。
|
||||
settings.delete_notices_1=- This operation <strong>CANNOT</strong> be undone.
|
||||
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.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 be became independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.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
|
||||
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=共同編集者が削除されました。
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.search_user_placeholder=Search users
|
||||
settings.org_not_allowed_to_be_collaborator=組織を共同編集者として追加することはできません。
|
||||
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
|
||||
settings.add_webhook=Webhook を追加
|
||||
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
|
||||
settings.webhook_deletion=Webhook を削除
|
||||
settings.webhook_deletion_desc=このwebhookを削除すると、すべての情報と配信履歴が削除されます。続行しますか?
|
||||
settings.webhook_deletion_success=Webhook が正常に削除されました。
|
||||
settings.webhook.test_delivery=テスト配信
|
||||
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=リクエスト
|
||||
settings.webhook.response=レスポンス
|
||||
settings.webhook.headers=ヘッダ
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=ドメイン
|
||||
settings.slack_channel=チャンネル
|
||||
settings.deploy_keys=デプロイキー
|
||||
settings.add_deploy_key=デプロイキーを追加
|
||||
settings.deploy_key_desc=個人アカウントのSSHキーとは異なり、デプロイキーは読み取り専用アクセスとなります。
|
||||
settings.no_deploy_keys=でプロキーは1つも追加されていません。
|
||||
settings.title=タイトル
|
||||
settings.deploy_key_content=コンテント
|
||||
@@ -627,9 +685,13 @@ diff.parent=親
|
||||
diff.commit=コミット
|
||||
diff.data_not_available=差分データは利用できません。
|
||||
diff.show_diff_stats=差分情報を表示
|
||||
diff.show_split_view=分割表示
|
||||
diff.show_unified_view=Unified View
|
||||
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
|
||||
diff.bin=BIN
|
||||
diff.view_file=ファイルの表示
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=リリース
|
||||
release.new_release=新しいリリース
|
||||
@@ -640,25 +702,25 @@ release.edit=編集
|
||||
release.ahead=このリリース以降 %s へ <strong>%d</strong> コミット
|
||||
release.source_code=ソース コード
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.edit_subheader=詳細な変更ログは、ユーザーに何が改善されたかの理解を助けることができます。
|
||||
release.tag_name=タグ名
|
||||
release.target=ターゲット
|
||||
release.tag_helper=既存のタグを選択するか、新しいタグを作成し発行します。
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=タイトル
|
||||
release.content=コンテント
|
||||
release.write=書込み
|
||||
release.preview=プレビュー
|
||||
release.loading=読み込み中…
|
||||
release.prerelease_desc=これはリリース前のものです
|
||||
release.prerelease_helper=このリリースは非プロダクション利用として識別します。
|
||||
release.cancel=Cancel
|
||||
release.cancel=キャンセル
|
||||
release.publish=リリースを発行
|
||||
release.save_draft=下書きを保存
|
||||
release.edit_release=リリースを編集
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=このリリースを削除
|
||||
release.deletion=リリースの削除
|
||||
release.deletion_desc=このリリースを削除すると、対応するGitのタグも削除されます。よろしいですか?
|
||||
release.deletion_success=リリースが正常に削除されました。
|
||||
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
|
||||
release.downloads=Downloads
|
||||
|
||||
@@ -667,7 +729,7 @@ org_name_holder=組織名
|
||||
org_full_name_holder=組織のフルネーム
|
||||
org_name_helper=偉大な組織の名は短く覚えやすいです。
|
||||
create_org=組織を作成
|
||||
repo_updated=更新した
|
||||
repo_updated=最終更新
|
||||
people=人々
|
||||
invite_someone=誰かを招待
|
||||
teams=チーム
|
||||
@@ -692,25 +754,26 @@ settings.location=ロケーション
|
||||
settings.update_settings=設定の更新
|
||||
settings.update_setting_success=組織の設定が更新されました。
|
||||
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.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 を追加します。
|
||||
|
||||
members.membership_visibility=Membership Visibility:
|
||||
members.public=パブリック
|
||||
members.public_helper=プライベートにする
|
||||
members.private=プライベート
|
||||
members.private_helper=公開する
|
||||
members.member_role=メンバーの役割:
|
||||
members.owner=オーナー
|
||||
members.member=メンバー
|
||||
members.conceal=隠す
|
||||
members.remove=削除
|
||||
members.leave=退出
|
||||
members.invite_desc=%s に招待する新しいメンバーをユーザ名を入力してください:
|
||||
members.invite_desc=%s に新しいメンバーを追加
|
||||
members.invite_now=今すぐ招待
|
||||
|
||||
teams.join=参加
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=このチームは<strong>読み取り</strong>権限
|
||||
teams.write_permission_desc=このチームは<strong>書き込み</strong>権限を持ち: メンバーはリポジトリの表示及リポジトリへのプッシュができます。
|
||||
teams.admin_permission_desc=このチームは<strong>管理者</strong>の権限を持ち: メンバーはチームのリポジトリに対して、読み取り、プッシュや共同編集者の追加ができます。
|
||||
teams.repositories=チームのリポジトリ
|
||||
teams.search_repo_placeholder=リポジトリを検索
|
||||
teams.add_team_repository=チームのリポジトリを追加
|
||||
teams.remove_repo=削除(Remove)
|
||||
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。まずはじめに作成してください。
|
||||
@@ -765,7 +829,7 @@ dashboard.delete_inactivate_accounts=非アクティブのアカウントをす
|
||||
dashboard.delete_inactivate_accounts_success=すべての非アクティブアカウントは正常に削除されました。
|
||||
dashboard.delete_repo_archives=リポジトリのすべてのアーカイブを削除
|
||||
dashboard.delete_repo_archives_success=リポジトリのすべてのアーカイブが正常に削除されました。
|
||||
dashboard.delete_missing_repos=Delete all repository records that lost Git files
|
||||
dashboard.delete_missing_repos=Gitファイルが失われたリポジトリのすべてのレコードを削除
|
||||
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
|
||||
dashboard.git_gc_repos=リポジトリでのガベージコレクションを実行します。
|
||||
dashboard.git_gc_repos_success=すべてのリポジトリは正常にガベージ コレクションを行いました。
|
||||
@@ -773,6 +837,8 @@ dashboard.resync_all_sshkeys='.ssh/ authorized_keys' ファイルを再生成し
|
||||
dashboard.resync_all_sshkeys_success=すべての公開鍵が正常に書き換えられました。
|
||||
dashboard.resync_all_update_hooks=リポジトリの update フックをすべて再更新する(カスタムの設定パスが変更されたときに必要)
|
||||
dashboard.resync_all_update_hooks_success=リポジトリの update フックがすべて正常に再更新されました。
|
||||
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.server_uptime=サーバーの稼働時間
|
||||
dashboard.current_goroutine=現在のGoroutine
|
||||
@@ -812,7 +878,7 @@ users.admin=アドミン
|
||||
users.repos=リポジトリ
|
||||
users.created=作成されました
|
||||
users.send_register_notify=登録通知をユーザーに送信
|
||||
users.new_success=New account '%s' has been created successfully.
|
||||
users.new_success=新規アカウント '%s' が正常に作成されました。
|
||||
users.edit=編集
|
||||
users.auth_source=認証ソース
|
||||
users.local=ローカル
|
||||
@@ -820,6 +886,8 @@ users.auth_login_name=認証ログイン名
|
||||
users.password_helper=それをそのまま空のままにします。
|
||||
users.update_profile_success=アカウントのプロファイルが更新されました。
|
||||
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.is_admin=このアカウントには管理者の権限を持つ
|
||||
users.allow_git_hook=このアカウントには Git のフックを作成する権限を持つ
|
||||
@@ -848,9 +916,10 @@ auths.new=新しいソースを追加
|
||||
auths.name=名前
|
||||
auths.type=タイプ
|
||||
auths.enabled=Enabled
|
||||
auths.updated=Updated
|
||||
auths.updated=更新しました
|
||||
auths.auth_type=認証タイプ
|
||||
auths.auth_name=認証名
|
||||
auths.security_protocol=Security Protocol
|
||||
auths.domain=ドメイン
|
||||
auths.host=ホスト
|
||||
auths.port=ポート
|
||||
@@ -859,9 +928,12 @@ auths.bind_password=バインド パスワード
|
||||
auths.bind_password_helper=警告: このパスワードは暗号化されずに格納されます。特権を持つアカウントに使用しないでください。
|
||||
auths.user_base=ユーザ検索ベース
|
||||
auths.user_dn=User DN
|
||||
auths.attribute_username=Username attribute
|
||||
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
|
||||
auths.attribute_name=名前属性
|
||||
auths.attribute_surname=名字属性
|
||||
auths.attribute_mail=Eメール属性
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=User フィルター
|
||||
auths.admin_filter=Admin フィルター
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -883,6 +955,7 @@ auths.update=認証設定を更新
|
||||
auths.delete=この認証を削除
|
||||
auths.delete_auth_title=認証削除
|
||||
auths.delete_auth_desc=認証を削除します、継続しますか?
|
||||
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=認証が正常に削除されました。
|
||||
|
||||
config.server_config=サーバーの構成
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=静的ファイルのルートパス
|
||||
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_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.db_config=データベースの構成
|
||||
config.db_type=タイプ
|
||||
config.db_host=ホスト
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=電子メールの確認を必要
|
||||
config.disable_register=登録を無効にする
|
||||
config.show_registration_button=登録ボタンを表示します。
|
||||
config.require_sign_in_view=サインインを要求
|
||||
config.enable_cache_avatar=アバターのキャッシュを有効にします。
|
||||
config.mail_notify=メール通知
|
||||
config.disable_key_size_check=最小キー サイズ チェックを無効にします
|
||||
config.enable_captcha=Captchaを有効にする
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=HELOコマンド無効
|
||||
config.mailer_name=名前
|
||||
config.mailer_host=ホスト
|
||||
config.mailer_user=ユーザ
|
||||
config.send_test_mail=Send Test Email
|
||||
config.test_mail_failed=Fail to send test email to '%s': %v
|
||||
config.test_mail_sent=Test email has been sent to '%s'.
|
||||
config.oauth_config=OAuth 構成
|
||||
config.oauth_enabled=Enabled
|
||||
config.cache_config=キャッシュの構成
|
||||
@@ -938,7 +1026,7 @@ config.cache_conn=キャッシュ接続
|
||||
config.session_config=セッションの構成
|
||||
config.session_provider=セッション プロバイダー
|
||||
config.provider_config=プロバイダーの構成
|
||||
config.cookie_name=クッキー名
|
||||
config.cookie_name=クッキーの名前
|
||||
config.enable_set_cookie=クッキーの設定を有効にする
|
||||
config.gc_interval_time=GC 間隔
|
||||
config.session_life_time=セッションのライフタイム
|
||||
@@ -962,6 +1050,13 @@ monitor.start=開始日時
|
||||
monitor.execute_time=実行時間:
|
||||
|
||||
notices.system_notice_list=システム通知
|
||||
notices.view_detail_header=お知らせの詳細を表示
|
||||
notices.actions=アクション
|
||||
notices.select_all=全て選択
|
||||
notices.deselect_all=すべて選択解除
|
||||
notices.inverse_selection=反転
|
||||
notices.delete_selected=選択項目を削除
|
||||
notices.delete_all=すべての通知を削除
|
||||
notices.type=タイプ
|
||||
notices.type_1=リポジトリ
|
||||
notices.desc=説明
|
||||
@@ -969,16 +1064,20 @@ 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>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_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>`
|
||||
comment_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> のコメント`
|
||||
merge_pull_request=`プルリクエスト <a href="%s/pulls/%s"> %s[2]s</a>をマージしました`
|
||||
transfer_repo=リポジトリ <code>%s</code> を <a href="%s">%s</a> へ転送しました
|
||||
push_tag=<a href="%[1]s">%[3]s</a> に タグ <a href="%[1]s/src/%[2]s">%[2]s</a> をプッシュしました
|
||||
compare_2_commits=これら 2 のコミットの比較を閲覧する
|
||||
compare_commits=これらの %d コミットの比較を表示
|
||||
|
||||
[tool]
|
||||
ago=前
|
||||
@@ -992,7 +1091,7 @@ now=今
|
||||
1mon=1 ヶ月 %s
|
||||
1y=1 年間 %s
|
||||
seconds=%d 秒 %s
|
||||
minutes=%d 分の %s
|
||||
minutes=%d分%s
|
||||
hours=%d 時間 %s
|
||||
days=%d 日 %s
|
||||
weeks=%d 週間 %s
|
||||
|
||||
203
conf/locale/locale_lv-LV.ini
Executable file → Normal file
203
conf/locale/locale_lv-LV.ini
Executable file → Normal file
@@ -28,6 +28,7 @@ organization=Organizācija
|
||||
mirror=Spogulis
|
||||
new_repo=Jauns repozitorijs
|
||||
new_migrate=Jauna migrācija
|
||||
new_mirror=Jauns spogulis
|
||||
new_fork=Jauns atdalītais repozitorijs
|
||||
new_org=Jauna organizācija
|
||||
manage_org=Pārvaldīt organizācijas
|
||||
@@ -37,19 +38,12 @@ settings=Iestatījumi
|
||||
your_profile=Tavs profils
|
||||
your_settings=Tavi iestatījumi
|
||||
|
||||
news_feed=Jaunumu plūsma
|
||||
activities=Aktivitāte
|
||||
pull_requests=Izmaiņu pieprasījumi
|
||||
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
|
||||
@@ -64,7 +58,7 @@ db_name=Datu bāzes nosaukums
|
||||
db_helper=Nepieciešams izmantot MySQL INNODB dzini ar rakstzīmju kopu utf8_general_ci.
|
||||
ssl_mode=SSL režīms
|
||||
path=Ceļš
|
||||
sqlite_helper=SQLite3 vai TiDB datu bāzes faila atrašanās vieta.
|
||||
sqlite_helper=SQLite3 vai TiDB datu bāzēs faila ceļš.<br>Izmantojiet absolūto ceļu, startējot kā servisu.
|
||||
err_empty_db_path=Nepieciešams norādīt SQLite3 vai TiDB datu bāzes atrašanās vietu.
|
||||
err_invalid_tidb_name=TiDB datu bāzes nosaukums nevar saturēt simbolus "." un "-".
|
||||
no_admin_and_disable_registration=Reģistrāciju nevar atslēgt, kamēr nav izveidots administratora konts.
|
||||
@@ -85,6 +79,8 @@ http_port=HTTP ports
|
||||
http_port_helper=Porta numurs pēc kura lietojumprogrammai būs iespējams pieslēgties.
|
||||
app_url=Lietotnes URL
|
||||
app_url_helper=Tas ietekmē HTTP/HTTPS klonēšanas URL un e-pasta saturā izsūtītās saites.
|
||||
log_root_path=Žurnalizēšanas direktorija
|
||||
log_root_path_helper=Direktorija, kurā tiks glabāti žurnāla faili.
|
||||
|
||||
optional_title=Neobligātie iestatījumi
|
||||
email_title=E-pasta pakalpojuma iestatījumi
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s
|
||||
save_config_failed=Neizdevās saglabāt konfigurāciju: %v
|
||||
invalid_admin_setting=Nekorekts admin konta iestatījums: %v
|
||||
install_success=Laipni lūdzam! Mēs priecājamies, ka Jūs izvēlaties Gogs, patīkamu lietošanu!
|
||||
invalid_log_root_path=Norādītā žurnalizēšanas direktorija ir kļūdaina: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Lietotājvārds vai e-pasts
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=Jūsu repozitorijos
|
||||
|
||||
[explore]
|
||||
repos=Repozitoriji
|
||||
users=Lietotāji
|
||||
search=Meklēt
|
||||
|
||||
[auth]
|
||||
create_new_account=Izveidot jaunu kontu
|
||||
@@ -158,13 +157,14 @@ reset_password=Atjaunot savu paroli
|
||||
invalid_code=Atvainojiet, Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs.
|
||||
reset_password_helper=Nospiediet šeit, lai atjaunotu paroli
|
||||
password_too_short=Paroles garums nedrīkst būt mazāks par 6.
|
||||
non_local_account=Non-local accounts cannot change passwords through Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=Lūdzu, aktivizējiet savu kontu
|
||||
activate_email=Apstipriniet savu e-pasta adresi
|
||||
reset_password=Atiestatīt savu paroli
|
||||
register_success=Reģistrācija notikusi veiksmīgi
|
||||
register_notify=Welcome on board
|
||||
register_notify=Laipni lūgti uz klāja
|
||||
|
||||
[modal]
|
||||
yes=Jā
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=Repozitorija vārds ir jau aizņemts.
|
||||
org_name_been_taken=Organizācijas nosaukums ir jau aizņemts.
|
||||
team_name_been_taken=Komandas nosaukums ir jau aizņemts.
|
||||
email_been_used=E-pasta adrese jau tiek izmantota.
|
||||
illegal_team_name=Grupas nosaukums satur neatļautas rakstzīmes.
|
||||
username_password_incorrect=Lietotājvārds vai parole nav pareiza.
|
||||
enterred_invalid_repo_name=Lūdzu, pārliecinieties, vai ievadītā repozitorija nosaukums ir pareizs.
|
||||
enterred_invalid_owner_name=Lūdzu, pārliecinieties, vai ievadītā īpašnieka vārds ir pareizs.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=Jūsu esat vismaz viena repozitorija īpašnieks, tos sākumā ir
|
||||
still_has_org=Jūsu esat vismaz vienas organizācijas biedrs, sākumā nepieciešams pamest vai izdzēst šo organizāciju.
|
||||
org_still_own_repo=Šī organizācija ir vismaz viena repozitorija īpašnieks, tos sākumā ir nepieciešams izdzēst vai nomainīt to īpašnieku.
|
||||
|
||||
still_own_user=Šo autentifikāciju joprojām izmanto vismaz viens lietotājs, nepieciešams šiem lietotājiem nomainīt autentifikācijas veidu vai tos izdzēst.
|
||||
|
||||
target_branch_not_exist=Mērķa atzars neeksistē
|
||||
|
||||
[user]
|
||||
change_avatar=Mainīt savu profila attēlu vietnē gravatar.com
|
||||
change_custom_avatar=Mainīt savu profila attēlu iestatījumos
|
||||
change_avatar=Change your avatar
|
||||
join_on=Pievienojās
|
||||
repositories=Repozitoriji
|
||||
activity=Publiskā aktivitāte
|
||||
followers=Sekotāji
|
||||
starred=Atzīmēti ar zvaigznīti
|
||||
following=Seko
|
||||
follow=Sekot
|
||||
unfollow=Nesekot
|
||||
|
||||
form.name_reserved=Lietotāja vārds '%s' jau ir aizņemts.
|
||||
form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
|
||||
@@ -247,6 +245,7 @@ uid=Lietotāja ID
|
||||
|
||||
public_profile=Publiskais profils
|
||||
profile_desc=Jūsu e-pasta adrese ir publiska un tiks izmantota, lai nosūtītju Jums paziņojumus, kas saistīti ar Jūsu kontu vai darbībām veiktām caur šo mājas lapu.
|
||||
password_username_disabled=Ne-lokālie lietotāji nevar mainīt savus lietotājvārdus.
|
||||
full_name=Pilns vārds
|
||||
website=Mājas lapa
|
||||
location=Atrašanās vieta
|
||||
@@ -258,11 +257,10 @@ continue=Turpināt
|
||||
cancel=Atcelt
|
||||
|
||||
enable_custom_avatar=Iespējot maināmu profila attēlu
|
||||
enable_custom_avatar_helper=Iespējojiet šo, lai atslēgtu profilu attēlu ņemšanu no gravatar.com
|
||||
choose_new_avatar=Izvēlēties jaunu profila attēlu
|
||||
update_avatar=Saglabāt profila bildi
|
||||
delete_current_avatar=Dzēst pašreizējo profila bildi
|
||||
uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls.
|
||||
no_custom_avatar_available=Nav iespējams mainīt profila bildi.
|
||||
update_avatar_success=Jūsu profila bilde tika veiksmīgi saglabāta.
|
||||
|
||||
change_password=Mainīt paroli
|
||||
@@ -271,6 +269,7 @@ new_password=Jauna parole
|
||||
retype_new_password=Ievadīt paroli atkāroti
|
||||
password_incorrect=Ievadīta nepareiza pašreizējā parole.
|
||||
change_password_success=Parole tika veiksmīgi nomainīta. Tagad jūs varat pieraksītites, izmantojot jauno paroli.
|
||||
password_change_disabled=Ne-lokālie lietotāji nevar mainīt savas paroles.
|
||||
|
||||
emails=E-pasta adreses
|
||||
manage_emails=Pārvaldīt e-pasta adreses
|
||||
@@ -351,11 +350,16 @@ readme_helper=Izvēlieties faila LasiMani sagatavi
|
||||
auto_init=Inicializēt šo repozitoriju ar izvēlētajiem failiem un sagatavi
|
||||
create_repo=Izveidot repozitoriju
|
||||
default_branch=Noklusējuma atzars
|
||||
mirror_prune=Prune
|
||||
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
|
||||
mirror_interval=Spoguļošanas intervāls (stundās)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=Spoguļa adrese
|
||||
mirror_address_desc=Lūdzu iekļaujiet adresē nepieciešamo lietotājvārdu/paroli.
|
||||
watchers=Novērotāji
|
||||
stargazers=Zvaigžņdevēji
|
||||
forks=Atdalītie repozitoriji
|
||||
|
||||
form.reach_limit_of_creation=Īpašnieks sasniedza maksimālu pieļaujamo (%d) izveidoto repozitoriju skaitu.
|
||||
form.name_reserved=Repozitorija nosaukums '%s' ir rezervēts.
|
||||
form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts.
|
||||
|
||||
@@ -367,8 +371,9 @@ migrate.clone_address=Klonēšanas adrese
|
||||
migrate.clone_address_desc=Tas var būt HTTP/HTTPS/GIT URL vai ceļš uz lokālā servera.
|
||||
migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju.
|
||||
migrate.invalid_local_path=Nekorents lokālais ceļš, tas neeksistē vai nav direktorijs.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Migrācija neizdevās: %v
|
||||
|
||||
mirror_from=spogulis no
|
||||
forked_from=atdalīts no
|
||||
fork_from_self=Nav iespējams atdalīt repozitoriju, kuram esat īpašnieks!
|
||||
copy_link=Kopēt
|
||||
@@ -388,9 +393,10 @@ create_new_repo_command=Izveidot jaunu repozitoriju komandrindā
|
||||
push_exist_repo=Nosūtīt izmaiņas no komandrindas eksistējošam repozitorijam
|
||||
repo_is_empty=Šis repozitorijs ir tukšs, apskatiet atkal vēlāk!
|
||||
|
||||
code=Kods
|
||||
branch=Atzars
|
||||
tree=Koks
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filtrēt atzarus vai tagus
|
||||
branches=Atzari
|
||||
tags=Tagi
|
||||
issues=Problēmas
|
||||
@@ -467,7 +473,7 @@ issues.closed_at=`aizvērts <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`atvērts atkārtoti <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`pieminēja šo problēmu revīzijā <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Autors
|
||||
issues.admin=Administrators
|
||||
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>
|
||||
@@ -484,8 +490,9 @@ issues.label_modify=Etiķetes labošana
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Jauns izmaiņu pieprasījums
|
||||
pulls.compare_changes=Salīdzināt izmaiņas
|
||||
pulls.compare_changes_desc=Salīdzināt divus atzarus un izveidot izmaiņu pieprasījumu.
|
||||
pulls.compare_base=pamata
|
||||
@@ -505,9 +512,9 @@ pulls.merged=Sapludināts
|
||||
pulls.has_merged=Šo izmaiņu pieprasījums tika veiksmīgi sapludināts!
|
||||
pulls.data_broken=Nepieejami izmaiņu pieprasījuma dati, jo dzēsta informācija no atdalītā repozitorija.
|
||||
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
|
||||
pulls.can_auto_merge_desc=Ir iespējams veikt automātisko sapludināšanas darbību šim izmaiņu pieprasījumam.
|
||||
pulls.cannot_auto_merge_desc=Nav iespējams veikt automātisko sapludināšanas darbību, jo starp revīzijām ir konflikti.
|
||||
pulls.cannot_auto_merge_helper=Lūdzu, izmantojiet komandrindas rīku, lai to atrisinātu.
|
||||
pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski saplūdināt.
|
||||
pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski saplūdināts konfliktu dēļ.
|
||||
pulls.cannot_auto_merge_helper=Lūdzu sapludiniet manuāli, lai atrisinātu konfliktus.
|
||||
pulls.merge_pull_request=Izmaiņu pieprasījuma sapludināšana
|
||||
pulls.open_unmerged_pull_exists=`Jūs nevarat veikt atkārtotas atvēršanas darbību, jo jau eksistē izmaiņu pieprasījums (#%d) no šī repozitorija ar tādu pašu sapludināšanas informāciju un gaida sapludināšanu.`
|
||||
|
||||
@@ -535,29 +542,72 @@ milestones.deletion=Atskaites punkta dzēšana
|
||||
milestones.deletion_desc=Dzēšot šo atskaites punktu tiks noņemta arī saistītā informācija no problēmu ziņojumiem. Vai vēlaties turpināt?
|
||||
milestones.deletion_success=Atskaites punkts tika veiksmīgi izdzēsts!
|
||||
|
||||
wiki=Vikivietne
|
||||
wiki.welcome=Laipni lūgti vikivietnē!
|
||||
wiki.welcome_desc=Vikivietne ir vieta, kur Jūs varat dokumentēt savu projektu, lai padarīto to labāku.
|
||||
wiki.create_first_page=Izveidot pirmo lapu
|
||||
wiki.page=Lapa
|
||||
wiki.filter_page=Meklēt lapu
|
||||
wiki.new_page=Izveidot jaunu lapu
|
||||
wiki.default_commit_message=Uzrakstiet piezīmes par šīm izmaiņām (neobligāti).
|
||||
wiki.save_page=Saglabāt lapu
|
||||
wiki.last_commit_info=%s laboja lapu %s
|
||||
wiki.edit_page_button=Labot
|
||||
wiki.new_page_button=Jauna lapa
|
||||
wiki.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
|
||||
|
||||
settings=Iestatījumi
|
||||
settings.options=Opcijas
|
||||
settings.collaboration=Sadarbība
|
||||
settings.collaboration.admin=Admin
|
||||
settings.collaboration.write=Write
|
||||
settings.collaboration.read=Read
|
||||
settings.collaboration.undefined=Undefined
|
||||
settings.hooks=Tīmekļa āķi
|
||||
settings.githooks=Git āķi
|
||||
settings.basic_settings=Pamatiestatījumi
|
||||
settings.danger_zone=Bīstamā zona
|
||||
settings.site=Oficiālā mājas lapa
|
||||
settings.update_settings=Mainīt iestatījumus
|
||||
settings.change_reponame_prompt=Šī izmaiņa ietekmēs saites, kas ir saistītas ar šo repozitoriju.
|
||||
settings.advanced_settings=Papildu iestatījumi
|
||||
settings.wiki_desc=Iespējot vikivietni, lai atļautu cilvēkiem rakstīt dokumentus
|
||||
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.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju
|
||||
settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=Jūs varat izmantot <code>{user}{repo}{index}</code> lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram.
|
||||
settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus
|
||||
settings.danger_zone=Bīstamā zona
|
||||
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
|
||||
settings.convert=Konvertēt uz parastu repozitoriju
|
||||
settings.convert_desc=Šo spoguli ir iespējams konvertēt par parastu repozitoriju. Šī ir neatgriezeniska darbība.
|
||||
settings.convert_notices_1=- Šī darbība konvertēs šo repozitoriju par parastu repozitoriju un to nebūs iespējams atcelt.
|
||||
settings.convert_confirm=Apstiprināt konvertēšanu
|
||||
settings.convert_succeed=Repozitorijs tika veiksmīgi konvertēts uz parastu repozitoriju.
|
||||
settings.transfer=Mainīt īpašnieku
|
||||
settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs.
|
||||
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
|
||||
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.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=Dzēst Vikivietnes datus
|
||||
settings.wiki_delete_desc=Vikivietnes datu dzēšana ir neatgriezeniska. Pārliecinieties vai patiešām to vēlaties.
|
||||
settings.wiki_delete_notices_1=- Šī darbība dzēsīs un atspējos %s Vikivietni
|
||||
settings.wiki_deletion_success=Repozitorija Vikivietnes dati tika veiksmīgi izdzēsti.
|
||||
settings.delete=Dzēst šo repozitoriju
|
||||
settings.delete_desc=Dzēšot repozitoriju, tā datus vairs nebūs iespējams atgūt. Pirms dzēšanas pārliecinieites vai patiešām vēlaties to darīt.
|
||||
settings.delete_notices_1=- Šī darbība ir <strong>NEATGRIEZENISKA</strong>.
|
||||
settings.delete_notices_2=- Šī darbība neatgriezeniski izdzēsīs visus šī repozitorija datus, tai skaitā Git datus, problēmu ziņojumus, komentārus un definētās piekļuves tiesības.
|
||||
settings.delete_notices_fork_1=- Ja repozitorijs ir publisks, visi atdalītie repozitoriji kļūs neatkarīgi.
|
||||
settings.delete_notices_fork_2=- Ja repozitorijs ir privāts, tiks dzēsti arī visi atdalītie repozitoriji.
|
||||
settings.delete_notices_fork_3=- Ja vēlaties saglabāt atdalīts repozitorijus pēc dzēšanas, sākumā nomainiet repozitorija redzamību uz publisku.
|
||||
settings.delete_notices_fork_1=- All forks will become independent after deletion.
|
||||
settings.deletion_success=Repozitorijs tika veiksmīgi dzēsts!
|
||||
settings.update_settings_success=Repozitorija opcijas ir veiksmīgi saglabātas.
|
||||
settings.transfer_owner=Jaunais īpašnieks
|
||||
settings.make_transfer=Mainīt
|
||||
@@ -565,14 +615,21 @@ 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=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=Search user...
|
||||
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.
|
||||
settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks.
|
||||
settings.add_webhook=Pievienot tīmekļa āķi
|
||||
settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
|
||||
settings.webhook_deletion=Dzēst tīmekļa āķi
|
||||
settings.webhook_deletion_desc=Dzēšot tīmekļa āķi tiks dzēsta visa ar to saistītā informācija un izpildes vēsture. Vai vēlaties turpināt?
|
||||
settings.webhook_deletion_success=Tīmekļa āķis tika veiksmīgi izdzēsts!
|
||||
settings.webhook.test_delivery=Testa piegāde
|
||||
settings.webhook.test_delivery_desc=Veikt viltus push-notikuma piegādi lai notestētu Jūsu tīmekļa āķa iestatījumus
|
||||
settings.webhook.test_delivery_success=Testa web-āķis ir pievienots piegādes rindai. Var paiet dažas sekundes, kamēr tas parādīsies piegāžu vēsturē.
|
||||
settings.webhook.request=Pieprasījums
|
||||
settings.webhook.response=Atbilde
|
||||
settings.webhook.headers=Galvenes
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=Domēns
|
||||
settings.slack_channel=Kanāls
|
||||
settings.deploy_keys=Izvietot atslēgas
|
||||
settings.add_deploy_key=Pievienot izvietošanas atslēgu
|
||||
settings.deploy_key_desc=Izvietošanas atslēgai ir tikai lasīšanas piekļuve. Tā nav tā pati kā Jūsu personīgā konta SSH atslēga.
|
||||
settings.no_deploy_keys=Nav pievienota neviena izvietošanas atslēga.
|
||||
settings.title=Virsraksts
|
||||
settings.deploy_key_content=Saturs
|
||||
@@ -627,9 +685,13 @@ diff.parent=vecāks
|
||||
diff.commit=revīzija
|
||||
diff.data_not_available=Salīdzināšanas dati nav pieejami.
|
||||
diff.show_diff_stats=Rādīt salīdzināšanas statistiku
|
||||
diff.show_split_view=Dalītais skats
|
||||
diff.show_unified_view=Apvienotais skats
|
||||
diff.stats_desc=<strong>%d mainītis faili</strong> ar <strong>%d papildinājumiem</strong> un <strong>%d dzēšanām</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Parādīt failu
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=Laidieni
|
||||
release.new_release=Jauns laidiens
|
||||
@@ -639,28 +701,28 @@ release.stable=Stabila
|
||||
release.edit=labot
|
||||
release.ahead=<strong>%d</strong> revīzijas atzarā %s kopš šī laidiena
|
||||
release.source_code=Izejas kods
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=Publicējiet laidienus, lai veiktu produkta iterācijas.
|
||||
release.edit_subheader=Detalizēts žurnāls var palīdzēt lietotājiem saprast, kas tika uzlabots.
|
||||
release.tag_name=Taga nosaukums
|
||||
release.target=Mērķis
|
||||
release.tag_helper=Publicējot, izvēlieties esošu vai izveidojiet jaunu tagu.
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=Virsraksts
|
||||
release.content=Saturs
|
||||
release.write=Rakstīt
|
||||
release.preview=Priekšskatītījums
|
||||
release.loading=Notiek ielāde...
|
||||
release.prerelease_desc=Šī ir pirmslaidiena versija
|
||||
release.prerelease_helper=Tiks norādīts, ka šis laidiens nav gatavs lietošanai produkcijas režīmā.
|
||||
release.cancel=Cancel
|
||||
release.cancel=Atcelt
|
||||
release.publish=Publicēt laidienu
|
||||
release.save_draft=Saglabāt melnrakstu
|
||||
release.edit_release=Labot laidienu
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=Dzēst šo laidienu
|
||||
release.deletion=Laidiena dzēšana
|
||||
release.deletion_desc=Dzēšot šo laidienu tiks dzēsts arī atbilstošs Git tags. Vai vēlaties turpināt?
|
||||
release.deletion_success=Laidiens tika veiksmīgi dzēsts!
|
||||
release.tag_name_already_exist=Laidiens ar šādu taga nosaukumu jau eksistē.
|
||||
release.downloads=Downloads
|
||||
release.downloads=Lejupielādes
|
||||
|
||||
[org]
|
||||
org_name_holder=Organizācijas nosaukums
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=Organizācijas dzēšana
|
||||
settings.delete_org_desc=Šī organizācija tiks pilnībā izdzēsta, vai vēlaties turpināt?
|
||||
settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā.
|
||||
|
||||
members.membership_visibility=Dalībnieka redzamība:
|
||||
members.public=Publisks
|
||||
members.public_helper=padarīt privātu
|
||||
members.private=Privāts
|
||||
members.private_helper=padarīt publisku
|
||||
members.member_role=Dalībnieka loma:
|
||||
members.owner=Īpašnieks
|
||||
members.member=Biedri
|
||||
members.conceal=Noslēpt
|
||||
members.remove=Noņemt
|
||||
members.leave=Atstāt
|
||||
members.invite_desc=Sāciet rakstīt lietotājvārdu, lai uzaicinātu jaunu biedru organizācijā %s:
|
||||
members.invite_desc=Pievienot jaunu dalībnieku pie %s:
|
||||
members.invite_now=Uzaicināt tagad
|
||||
|
||||
teams.join=Pievienoties
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=Šai komandai ir <strong>lasīšanas</strong> tiesīb
|
||||
teams.write_permission_desc=Šai komandai ir <strong>rakstīšanas</strong> tiesības: dalībnieki var lasīt un nosūtīt izmaiņas repozitorijiem.
|
||||
teams.admin_permission_desc=Šai komandai ir <strong>administratora</strong> tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem.
|
||||
teams.repositories=Komandas repozitoriji
|
||||
teams.search_repo_placeholder=Meklēt repozitorijā...
|
||||
teams.add_team_repository=Pievienot komandas repozitoriju
|
||||
teams.remove_repo=Noņemt
|
||||
teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to.
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=Dzēst visus neaktīvos kontus
|
||||
dashboard.delete_inactivate_accounts_success=Visi neaktīvie kotni tika veiksmīgi izdzēsti.
|
||||
dashboard.delete_repo_archives=Dzēst visu repozitoriju arhīvus
|
||||
dashboard.delete_repo_archives_success=Visu repozitoriju arhīvi tika veiksmīgi izdzēsti.
|
||||
dashboard.delete_missing_repos=Delete all repository records that lost Git files
|
||||
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
|
||||
dashboard.delete_missing_repos=Dzēst visus repozitorija ierakstus, kas zaudēja Git failus
|
||||
dashboard.delete_missing_repos_success=Visi repozitorija ieraksti, kas zaudēja Git failus tika veiksmīgi dzēsti.
|
||||
dashboard.git_gc_repos=Veikt repozitoriju datu sakārtošānu (git gc)
|
||||
dashboard.git_gc_repos_success=Datu sakārtošana visiem repozitorijiem veiksmīgi pabeigta.
|
||||
dashboard.resync_all_sshkeys=Pārrakstīt '.ssh/authorized_keys' failu (brīdinājums: ne-Git atslēgas tiks pazaudētas)
|
||||
dashboard.resync_all_sshkeys_success=Visas publiskās atslēgas tika veiksmīgi pārrakstītas.
|
||||
dashboard.resync_all_update_hooks=Pārrakstīt visu repozitoriju izmaiņu āķus (nepieciešams, ja tiek mainīta konfigurācijas faila atrašanās vieta)
|
||||
dashboard.resync_all_update_hooks_success=Visu repozitoriju izmaiņu āķi tika veiksmīgi pārrakstīti.
|
||||
dashboard.reinit_missing_repos=Atkārtoti inicializēt visus repozitorija ierakstus, kam trūkst Git failu
|
||||
dashboard.reinit_missing_repos_success=Visi repozitorija ieraksti, kam trūkst Git faili, tika atkārtoti inicializēti.
|
||||
|
||||
dashboard.server_uptime=Servera darbības laiks
|
||||
dashboard.current_goroutine=Izmantotās Gorutīnas
|
||||
@@ -820,6 +886,8 @@ users.auth_login_name=Autentifikācijas pieteikšanās vārds
|
||||
users.password_helper=Atstājiet tukšu, ja nevēlaties mainīt.
|
||||
users.update_profile_success=Konta profils tika veiksmīgi saglabāts.
|
||||
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.is_admin=Šim kontam ir administratora piekļuves tiesības
|
||||
users.allow_git_hook=Šim kontam ir tiesības pievienot/labot Git āķus
|
||||
@@ -851,6 +919,7 @@ auths.enabled=Iespējota
|
||||
auths.updated=Atjaunināta
|
||||
auths.auth_type=Autentifikācijas tips
|
||||
auths.auth_name=Autentifikācijas nosaukums
|
||||
auths.security_protocol=Security Protocol
|
||||
auths.domain=Domēns
|
||||
auths.host=Resursdators
|
||||
auths.port=Ports
|
||||
@@ -859,9 +928,12 @@ auths.bind_password=Saistīšanas parole
|
||||
auths.bind_password_helper=Brīdinājums: Šī parole tiks saglabāta nešifrētā veidā. Neizmantojiet kontu ar augstām privilēģijām.
|
||||
auths.user_base=Lietotāja pamatnosacījumi
|
||||
auths.user_dn=Lietotāja DN
|
||||
auths.attribute_username=Lietotājvārda atribūts
|
||||
auths.attribute_username_placeholder=Atstājiet tukšu, lai izmantotu lietotājvārdu ar kuru autorizējaties.
|
||||
auths.attribute_name=Vārda atribūts
|
||||
auths.attribute_surname=Uzvārda atribūts
|
||||
auths.attribute_mail=E-pasta atribūts
|
||||
auths.attributes_in_bind=Nolasīt atribūtus no saistīšanas DN konteksta
|
||||
auths.filter=Lietotāju filts
|
||||
auths.admin_filter=Administratoru filtrs
|
||||
auths.ms_ad_sa=MS Ad SA
|
||||
@@ -883,6 +955,7 @@ auths.update=Mainīt autentifikācijas iestatījumus
|
||||
auths.delete=Dzēst šo autentifikāciju
|
||||
auths.delete_auth_title=Autentifikācijas dzēšana
|
||||
auths.delete_auth_desc=Šī autentifikācija tiks dzēsta, vai vēlaties turpināt?
|
||||
auths.still_in_used=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
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Statisko failu atrašanās vieta
|
||||
config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta
|
||||
config.script_type=Skripta veids
|
||||
config.reverse_auth_user=Reversā lietotāja autentifikācija
|
||||
|
||||
config.ssh_config=SSH konfigurācija
|
||||
config.ssh_enabled=Iespējots
|
||||
config.ssh_start_builtin_server=Startēt iebūvēto serveri
|
||||
config.ssh_domain=Domēns
|
||||
config.ssh_port=Ports
|
||||
config.ssh_listen_port=Klausīšanās ports
|
||||
config.ssh_root_path=Saknes ceļš
|
||||
config.ssh_key_test_path=Atslēgu pārbaudes ceļš
|
||||
config.ssh_keygen_path=Keygen ('ssh-keygen') ceļš
|
||||
config.ssh_minimum_key_size_check=Minimālā atslēgas lieluma pārbaude
|
||||
config.ssh_minimum_key_sizes=Minimālais atslēgas lielums
|
||||
|
||||
config.db_config=Datu bāzes konfigurācija
|
||||
config.db_type=Veids
|
||||
config.db_host=Resursdators
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=Pieprasīt e-pasta apstiprināšanu
|
||||
config.disable_register=Atspējot jaunu lietotāju reģistrāciju
|
||||
config.show_registration_button=Rādīt reģistrēšanās pogu
|
||||
config.require_sign_in_view=Nepieciešama autorizācija
|
||||
config.enable_cache_avatar=Glabāt profila attēlus kešatmiņā
|
||||
config.mail_notify=Pasta paziņojumi
|
||||
config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi
|
||||
config.enable_captcha=Iespējot drošības kodu
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Atspējot HELO
|
||||
config.mailer_name=Nosaukums
|
||||
config.mailer_host=Resursdators
|
||||
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
|
||||
@@ -962,23 +1050,34 @@ monitor.start=Sākuma laiks
|
||||
monitor.execute_time=Izpildes laiks
|
||||
|
||||
notices.system_notice_list=Sistēmas paziņojumi
|
||||
notices.view_detail_header=Skatīt paziņojuma detaļas
|
||||
notices.actions=Darbības
|
||||
notices.select_all=Iezīmēt visu
|
||||
notices.deselect_all=Atcelt visa iezīmēšanu
|
||||
notices.inverse_selection=Apgriezeniskā iezīmēšana
|
||||
notices.delete_selected=Dzēst iezīmēto
|
||||
notices.delete_all=Dzēst visus paziņojumus
|
||||
notices.type=Veids
|
||||
notices.type_1=Repozitorijs
|
||||
notices.desc=Apraksts
|
||||
notices.op=Op.
|
||||
notices.delete_success=Sistēmas paziņojums tika veiksmīgi izdzēsts.
|
||||
notices.delete_success=Sistēmas paziņojumi tika veiksmīgi izdzēstas.
|
||||
|
||||
[action]
|
||||
create_repo=izveidoja repozitoriju <a href="%s">%s</a>
|
||||
rename_repo=pārsauca repozitoriju no <code>%[1]s</code> uz <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=veica izmaiņu nosūtīšanu atzaram <a href="%[1]s/src/%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a>
|
||||
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=`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>
|
||||
push_tag=pievienoja tagu <a href="%s/src/%s">%[2]s</a> repozitorijam <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Veikt salīdzināšanu starp šīm 2 revīzijām
|
||||
compare_commits=Salīdzināt šīs %d revīzijas
|
||||
|
||||
[tool]
|
||||
ago=atpakaļ
|
||||
|
||||
387
conf/locale/locale_nl-NL.ini
Executable file → Normal file
387
conf/locale/locale_nl-NL.ini
Executable file → Normal file
@@ -1,34 +1,35 @@
|
||||
app_desc=Een eenvoudige zelfgehoste Git service geschreven in Go
|
||||
|
||||
home=Huis
|
||||
home=Home
|
||||
dashboard=Dashboard
|
||||
explore=Verkennen
|
||||
help=Help
|
||||
sign_in=Inloggen
|
||||
sign_out=Afmelden
|
||||
sign_out=Uitloggen
|
||||
sign_up=Aanmelden
|
||||
register=Registreer
|
||||
register=Registreren
|
||||
website=Website
|
||||
version=Versie
|
||||
page=Pagina
|
||||
template=Sjabloon
|
||||
language=Taal
|
||||
create_new=Create...
|
||||
create_new=Creëren...
|
||||
user_profile_and_more=Gebruikersprofiel en meer
|
||||
signed_in_as=Aangemeld als
|
||||
|
||||
username=Gebruikersnaam
|
||||
email=E-mail
|
||||
password=Wachttwoord
|
||||
password=Wachtwoord
|
||||
re_type=Verificatie
|
||||
captcha=CAPTCHA
|
||||
|
||||
repository=Repositorie
|
||||
repository=Repository
|
||||
organization=Organisatie
|
||||
mirror=Spiegel
|
||||
new_repo=Nieuwe repositorie
|
||||
new_repo=Nieuwe repository
|
||||
new_migrate=Nieuwe migratie
|
||||
new_fork=Nieuwe vork Repository
|
||||
new_mirror=Nieuwe Kopie
|
||||
new_fork=Nieuwe Fork
|
||||
new_org=Nieuwe organisatie
|
||||
manage_org=Beheer organisaties
|
||||
admin_panel=Adminpaneel
|
||||
@@ -37,25 +38,18 @@ settings=Instellingen
|
||||
your_profile=Uw profiel
|
||||
your_settings=Uw instellingen
|
||||
|
||||
news_feed=Nieuwsfeed
|
||||
pull_requests=Pull-aanvragen
|
||||
activities=Activiteiten
|
||||
pull_requests=Pull requests
|
||||
issues=Kwesties
|
||||
|
||||
cancel=Annuleer
|
||||
|
||||
[search]
|
||||
search=Zoeken...
|
||||
repository=Opslagplaats
|
||||
user=Gebruiker
|
||||
issue=Probleem
|
||||
code=Code
|
||||
cancel=Annuleren
|
||||
|
||||
[install]
|
||||
install=Installatie
|
||||
title=Installatiestappen voor de eerste keer opstarten
|
||||
docker_helper=If you're running Gogs inside Docker, please read <a target="_blank" href="%s">Guidelines</a> carefully before you change anything in this page!
|
||||
requite_db_desc=Gogs requires MySQL, PostgreSQL, SQLite3 or TiDB.
|
||||
db_title=Database instellingen
|
||||
docker_helper=Als u gebruik maakt Gogs binnen Docker, lees dan de <a target="_blank" href="%s">richtlijnen</a> voordat u iets veranderen op deze pagina!
|
||||
requite_db_desc=Gogs vereist MySQL, PostgreSQL, SQite3 of TiDB.
|
||||
db_title=Database-instellingen
|
||||
db_type=Database-type
|
||||
host=Host
|
||||
user=Gebruikersnaam
|
||||
@@ -64,11 +58,11 @@ db_name=Database naam
|
||||
db_helper=Gebruik InnoDB engine met utf8_general_ci karakterset voor MySQL.
|
||||
ssl_mode=SSL-modus
|
||||
path=Pad
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database.
|
||||
err_empty_db_path=SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name=TiDB database name does not allow characters "." and "-".
|
||||
no_admin_and_disable_registration=You cannot disable registration without creating an admin account.
|
||||
err_empty_admin_password=Admin password cannot be empty.
|
||||
sqlite_helper=Het pad van de SQLite3- of TiDB-database.<br>Als u Gogs start als een service, geef dan een absoluut pad op.
|
||||
err_empty_db_path=SQLite3 of TiDB databankpad mag niet leeg.
|
||||
err_invalid_tidb_name=TiDB databank naam niet tekens kunnen "." en "-".
|
||||
no_admin_and_disable_registration=Je kunt niet de registratie uit te schakelen zonder een beheerders account.
|
||||
err_empty_admin_password=Beheerder wachtwoord kan niet leeg zijn.
|
||||
|
||||
general_title=Toepassing algemene instellingen
|
||||
app_name=Applicatienaam
|
||||
@@ -85,6 +79,8 @@ http_port=HTTP-poort
|
||||
http_port_helper=Poortnummer waar het programma naar luistert.
|
||||
app_url=Applicatie URL
|
||||
app_url_helper=Dit heeft invloed op de HTTP/HTTPS kloon urls en de urls die in de email worden gebruikt
|
||||
log_root_path=Log-pad
|
||||
log_root_path_helper=Directory waar logbestanden opgeslagen worden.
|
||||
|
||||
optional_title=Optionele instellingen
|
||||
email_title=E-mail service instellingen
|
||||
@@ -102,8 +98,8 @@ disable_gravatar=Gravatar Service uitschakelen
|
||||
disable_gravatar_popup=Schakel Gravatar en andere bronnen uit, alle avatars worden door gebruikers geüpload of zijn standaard.
|
||||
disable_registration=Schakel zelfregistratie uit
|
||||
disable_registration_popup=Schakel zelfregistratie uit, alleen admins kunnen accounts maken.
|
||||
enable_captcha=Enable Captcha
|
||||
enable_captcha_popup=Require validate captcha for user self-registration.
|
||||
enable_captcha=Inschakelen Captcha
|
||||
enable_captcha_popup=Vereis captcha validatie voor zelf-registratie van gebruiker.
|
||||
require_sign_in_view=Schakel vereiste aanmelding om pagina's te zien in
|
||||
require_sign_in_view_popup=Alleen ingelogde gebruikers kunnen pagina's bekijken, bezoekers kunnen alleen de login/registratie pagina's zien.
|
||||
admin_setting_desc=U hoeft niet meteen een administratie account te maken, de gebruiker met ID=1 krijgt automatisch administratierechten.
|
||||
@@ -111,16 +107,17 @@ admin_title=Instellingen beheerdersaccount
|
||||
admin_name=Gebruikersnaam
|
||||
admin_password=Wachtwoord
|
||||
confirm_password=Verifieer wachtwoord
|
||||
admin_email=Admin E-mail
|
||||
admin_email=Beheerder E-mail
|
||||
install_gogs=Installeer Gogs
|
||||
test_git_failed=Git test niet gelukt: 'git' commando %v
|
||||
sqlite3_not_available=Uw versie biedt geen ondersteuning voor SQLite3, download de officiële binaire versie van %s, niet de gobuild versie.
|
||||
invalid_db_setting=Uw database instellingen zijn niet correct: %v
|
||||
invalid_repo_path=Repositorie basis pad is niet correct: %v
|
||||
invalid_repo_path=Repositorie basis map is niet correct: %v
|
||||
run_user_not_match=De uitvoerende gebruiker is niet de huidig gebruiker: %s -> %s
|
||||
save_config_failed=Kan de configuratie niet opslaan: %v
|
||||
invalid_admin_setting=Uw admin-instellingen zijn niet geldig: %v
|
||||
install_success=Welkom! Wij zijn veheugd dat u voor Gogs heeft gekozen, veel plezier en tot ziens
|
||||
invalid_log_root_path=Ongeldig log-pad: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Gebruikersnaam of e-mail
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=In uw repositories
|
||||
|
||||
[explore]
|
||||
repos=Repositories
|
||||
users=Gebruikers
|
||||
search=Zoeken
|
||||
|
||||
[auth]
|
||||
create_new_account=Maak nieuw account aan
|
||||
@@ -158,13 +157,14 @@ 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=Please activate your account
|
||||
activate_email=Verify your e-mail address
|
||||
reset_password=Reset your password
|
||||
register_success=Register success, Welcome
|
||||
register_notify=Welcome on board
|
||||
activate_account=Activeer uw account
|
||||
activate_email=Verifieer je e-mailadres
|
||||
reset_password=Stel je wachtwoord opnieuw in
|
||||
register_success=Registratie succesvol, welkom
|
||||
register_notify=Welkom aan boord
|
||||
|
||||
[modal]
|
||||
yes=Ja
|
||||
@@ -173,7 +173,7 @@ modify=Aanpassen
|
||||
|
||||
[form]
|
||||
UserName=Gebruikersnaam
|
||||
RepoName=Repositorie naam
|
||||
RepoName=Naam van repository
|
||||
Email=e-mailadres
|
||||
Password=Wachtwoord
|
||||
Retype=Verifieer wachtwoord
|
||||
@@ -192,17 +192,16 @@ min_size_error=moet minimaal %s karakters bevatten.
|
||||
max_size_error=mag maximaal %s karakters bevatten.
|
||||
email_error=is niet een valide e-mail adres.
|
||||
url_error=is niet een valide URL.
|
||||
include_error=` must contain substring '%s'.`
|
||||
include_error=` moet substring '%s' bevatten.`
|
||||
unknown_error=Onbekende fout:
|
||||
captcha_incorrect=Captcha komt niet overeen.
|
||||
password_not_match=Wachtwoord en verificatie wachtwoord komen niet overeen.
|
||||
|
||||
username_been_taken=Gebruikersnaam is al in gebruik.
|
||||
repo_name_been_taken=Repositorie naam is al in gebruik.
|
||||
repo_name_been_taken=Deze naam is al in gebruik.
|
||||
org_name_been_taken=Organisatie naam is al in gebruik.
|
||||
team_name_been_taken=Team naam is al in gebruik.
|
||||
email_been_used=e-mailadres is al in gebruik.
|
||||
illegal_team_name=Team naam bevat illegale karakters.
|
||||
username_password_incorrect=Gebruikersnaam of wachtwoord is niet correct.
|
||||
enterred_invalid_repo_name=U heeft een onjuiste repositorie naam ingevoerd.
|
||||
enterred_invalid_owner_name=U heeft een onjuiste eigenaar ingevoerd.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=Uw account heeft nog een eigendom op een repositorie. U moet deze
|
||||
still_has_org=Uw account nog steeds lidmaatschap van organisatie, u hebt naar links of hen eerst verwijderen.
|
||||
org_still_own_repo=De organisatie heeft nog eigendomen op repositories. U moet deze eerst verwijderen of overdragen.
|
||||
|
||||
still_own_user=Deze authenticatie methode wordt nog gebruikt door sommige gebruikers. U moet hen eerst verplaatsen of verwijderen.
|
||||
|
||||
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
|
||||
followers=Volgers
|
||||
starred=Sterren
|
||||
following=Volgt
|
||||
follow=Volg
|
||||
unfollow=Niet meer volgen
|
||||
|
||||
form.name_reserved=De gebruikersnaam '%s' is gereserveerd.
|
||||
form.name_pattern_not_allowed=Het gebruikersnaam patroon '%s' is niet toegestaan.
|
||||
@@ -247,30 +245,31 @@ uid=uid
|
||||
|
||||
public_profile=Openbaar profiel
|
||||
profile_desc=Uw e-mailadres is openbaar en zal gebruikt worden voor alle account gerelateerde berichtgevingen en bewerkingingen die via de website worden gedaan.
|
||||
password_username_disabled=Extern opgeslagen gebruikers zijn niet toegestaan om hun gebruikersnaam veranderen.
|
||||
full_name=Volledige naam
|
||||
website=Website
|
||||
location=Locatie
|
||||
update_profile=Profile bijwerken
|
||||
update_profile_success=Uw profiel is succesvol bijgewerkt.
|
||||
change_username=Username veranderd
|
||||
change_username_prompt=This change will affect the way how links relate to your account.
|
||||
change_username_prompt=Deze verandering zal de weg links hebben betrekking op uw account beïnvloeden.
|
||||
continue=Doorgaan
|
||||
cancel=Annuleren
|
||||
|
||||
enable_custom_avatar=Aangepaste avatar inschakelen
|
||||
enable_custom_avatar_helper=Avatar niet ophalen van Gravatar
|
||||
choose_new_avatar=Kies een nieuwe avatar
|
||||
update_avatar=Avatar instelling bijwerken
|
||||
delete_current_avatar=Verwijder huidige avatar
|
||||
uploaded_avatar_not_a_image=Geüpload bestand is geen afbeelding.
|
||||
no_custom_avatar_available=Geen aangepaste avatar beschikbaar, kan niet worden ingeschakeld.
|
||||
update_avatar_success=Instellingen voor avatar succesvol bijgewerkt.
|
||||
|
||||
change_password=Verander wachtwoord
|
||||
old_password=Huidige wachtwoord
|
||||
new_password=Nieuw wachtwoord
|
||||
retype_new_password=Retype New Password
|
||||
retype_new_password=Herhaal Nieuw Wachtwoord
|
||||
password_incorrect=Huidig wachtwoord is niet correct.
|
||||
change_password_success=Wachtwoord is succesvol gewijzigd. U kunt nu met uw nieuwe wachtwoord inloggen.
|
||||
password_change_disabled=Extern opgeslagen gebruikers zijn niet toegestaan om hun wachtwoord te wijzigen.
|
||||
|
||||
emails=E-mailadressen
|
||||
manage_emails=E-mailadressen beheren
|
||||
@@ -278,9 +277,9 @@ email_desc=Uw primaire e-mailadres zal worden gebruikt voor meldingen en andere
|
||||
primary=Primair
|
||||
primary_email=Instellen als primair
|
||||
delete_email=Verwijder
|
||||
email_deletion=E-mail Deletion
|
||||
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success=E-mail has been deleted successfully!
|
||||
email_deletion=E-mail Verwijderen
|
||||
email_deletion_desc=Dit e-mailadres verwijdert, worden gerelateerde informatie van uw account te verwijderen. Wil je verdergaan?
|
||||
email_deletion_success=E-mail is succesvol verwijderd!
|
||||
add_new_email=Nieuw e-mailadres toevoegen
|
||||
add_email=E-mailadres toevoegen
|
||||
add_email_confirmation_sent=Een nieuwe bevestiging e-mail werd verstuurd naar '%s', gelieve uw inbox in de komende %d uren te controleren om het bevestigingsproces te voltooien.
|
||||
@@ -331,16 +330,16 @@ delete_account_desc=Dit account zal permanent worden verwijderd. Wilt u doorgaan
|
||||
|
||||
[repo]
|
||||
owner=Eigenaar
|
||||
repo_name=Repositorie naam
|
||||
repo_name_helper=Een goede repositorie naam is kort, memorabel en <strong>uniek</strong>.
|
||||
repo_name=Naam van repository
|
||||
repo_name_helper=Een goede repository-naam is kort, makkelijk te onthouden en <strong>uniek</strong>.
|
||||
visibility=Zichtbaarheid
|
||||
visiblity_helper=Deze repositorie is <span class="ui red text">privaat</span>
|
||||
visiblity_helper_forced=Site admin has forced all new repositories to be <span class="ui red text">Private</span>
|
||||
visiblity_helper_forced=Sitebeheerder heeft alle nieuwe repositories gedwongen <span class="ui red text">privé</span> te zijn
|
||||
visiblity_fork_helper=(Verandering van deze waarde zal van invloed zijn op alle forks)
|
||||
clone_helper=De behoeftehulp van klonen? Bezoek <a target="_blank" href="%s"> helpen</a>!
|
||||
fork_repo=Vork Repository
|
||||
fork_repo=Repository forken
|
||||
fork_from=Afsplitsing van
|
||||
fork_visiblity_helper=Gevorkte repository wijzigen zijn bereik potentiële kopers niet
|
||||
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
|
||||
@@ -349,13 +348,18 @@ license_helper=Selecteer een licentie bestand
|
||||
readme=Leesmij-bestand
|
||||
readme_helper=Selecteer een sjabloon voor het Leesmij-bestand
|
||||
auto_init=Initialiseer deze repositorie met de geselecteerde bestanden en sjabloon
|
||||
create_repo=Nieuwe Repositorie
|
||||
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)
|
||||
watchers=Watchers
|
||||
mirror_address=Kopie-adres
|
||||
mirror_address_desc=Gelieve noodzakelijke gebruikersgegevens in de adresbalk.
|
||||
watchers=Volgers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=De eigenaar heeft maximale creatie limiet van %d repositories bereikt.
|
||||
form.name_reserved=Repositorienaam '%s' is gereserveerd.
|
||||
form.name_pattern_not_allowed=Repositorie naampatroon '%s' is niet toegestaan.
|
||||
|
||||
@@ -365,15 +369,16 @@ migrate_type_helper=Deze repositorie zal een <span class="text blue">mirror</spa
|
||||
migrate_repo=Migreer repositorie
|
||||
migrate.clone_address=Clone adres
|
||||
migrate.clone_address_desc=Dit kan een HTTP/HTTPS/GIT URL zijn of een lokaal pad.
|
||||
migrate.permission_denied=You are not allowed to import local repositories.
|
||||
migrate.permission_denied=U bent niet toegestaan om deze lokale repositories te importeren.
|
||||
migrate.invalid_local_path=Ongeldig lokaal pad, het pad bestaat niet of het is geen map.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Migratie is mislukt: %v
|
||||
|
||||
mirror_from=spiegel van
|
||||
forked_from=geforked van
|
||||
fork_from_self=U kunt geen repository forken die u al beheert!
|
||||
copy_link=Kopieer
|
||||
copy_link_success=Copied!
|
||||
copy_link_error=Press ⌘-C or Ctrl-C to copy
|
||||
copy_link_success=Gekopieerd!
|
||||
copy_link_error=Druk op ⌘-C of Ctrl-C om te kopiëren
|
||||
copied=Gekopieerd
|
||||
unwatch=Negeren
|
||||
watch=Volgen
|
||||
@@ -386,11 +391,12 @@ quick_guide=Snelstart gids
|
||||
clone_this_repo=Kloon deze repositorie
|
||||
create_new_repo_command=Maak een nieuwe repositorie aan vanaf de console
|
||||
push_exist_repo=Push een bestaande repositorie vanaf de console
|
||||
repo_is_empty=This repository is empty, please come back later!
|
||||
repo_is_empty=Deze repositories is leeg is, probeer het later opnieuw!
|
||||
|
||||
code=Code
|
||||
branch=Aftakking
|
||||
tree=Boom
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filter branch of tag
|
||||
branches=Aftakkingen
|
||||
tags=Labels
|
||||
issues=Kwesties
|
||||
@@ -422,7 +428,7 @@ issues.new.no_milestone=Geen mijlpaal
|
||||
issues.new.clear_milestone=Verwijder mijlpaal
|
||||
issues.new.open_milestone=Open mijlpalen
|
||||
issues.new.closed_milestone=Gesloten mijlpalen
|
||||
issues.new.assignee=Verantwoordelijke
|
||||
issues.new.assignee=Toegewezen aan
|
||||
issues.new.clear_assignee=Verwijder verantwoordelijke
|
||||
issues.new.no_assignee=Geen verantwoordelijke
|
||||
issues.create=Maak probleem
|
||||
@@ -465,9 +471,9 @@ issues.reopen_comment_issue=Heropen en geef commentaar
|
||||
issues.create_comment=Reageer
|
||||
issues.closed_at=`gesloten om <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`heropend om <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at='verwees naar dit probleem vanuit een commit <a id="%[1]s" href="#%[1]s"> %[2]s'</a>
|
||||
issues.commit_ref_at=`verwees naar dit probleem vanuit een commit <a id="%[1]s" href="#%[1]s"> %[2]s'</a>`
|
||||
issues.poster=Poster
|
||||
issues.admin=Admin
|
||||
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>
|
||||
@@ -484,8 +490,9 @@ issues.label_modify=Wijzig label
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Nieuwe Pull aanvraag
|
||||
pulls.compare_changes=Vergelijk veranderingen
|
||||
pulls.compare_changes_desc=Vergelijk twee vertakkingen en maak een pull verzoek voor wijzigingen.
|
||||
pulls.compare_base=base
|
||||
@@ -496,20 +503,20 @@ 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=merged %[1]d commits from <code>%[2]s</code> into <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
|
||||
pulls.reopen_to_merge=Please reopen this pull request to perform merge operation.
|
||||
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.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=You can perform auto-merge operation on this pull request.
|
||||
pulls.cannot_auto_merge_desc=You can't perform auto-merge operation because there are conflicts between commits.
|
||||
pulls.cannot_auto_merge_helper=Please use command line tool to solve it.
|
||||
pulls.reopen_to_merge=Heropen deze pull request aub om een een merge actie uit te voeren.
|
||||
pulls.merged=Samengevoegd
|
||||
pulls.has_merged=Dit pull-request is samengevoegd!
|
||||
pulls.data_broken=Omdat informatie over de fork is verwijderd, zijn de gegevens van dit pull-request niet beschikbaar.
|
||||
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=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
|
||||
@@ -535,29 +542,72 @@ milestones.deletion=Mijlpaal verwijderen
|
||||
milestones.deletion_desc=Het verwijderen van dit label zal alle informatie in de gerelateerde problemen verwijderen. Wilt u doorgaan?
|
||||
milestones.deletion_success=Mijlpaal is met succes verwijderd!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Welkom op de Wiki!
|
||||
wiki.welcome_desc=In een wiki kunnen gebruikers samen een project documenteren en bediscussiëren.
|
||||
wiki.create_first_page=Maak de eerste pagina
|
||||
wiki.page=Pagina
|
||||
wiki.filter_page=Filter pagina
|
||||
wiki.new_page=Maak nieuwe pagina
|
||||
wiki.default_commit_message=Schrijf een notitie over deze aanpassing (optioneel).
|
||||
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=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
|
||||
|
||||
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 haken
|
||||
settings.githooks=Git-hooks
|
||||
settings.basic_settings=Basis instellingen
|
||||
settings.danger_zone=Gevaren zone
|
||||
settings.site=Officiële site
|
||||
settings.update_settings=Instellingen bewerken
|
||||
settings.change_reponame_prompt=This change will affect how links relate to the repository.
|
||||
settings.change_reponame_prompt=Deze verandering zal gevolgen hebben voor hoe links zich verhouden tot de repository.
|
||||
settings.advanced_settings=Geavanceerde opties
|
||||
settings.wiki_desc=Wiki inschakelen, om mensen documenten te laten schrijven
|
||||
settings.use_external_wiki=Externe wiki gebruiken
|
||||
settings.external_wiki_url=Externe wiki-URL
|
||||
settings.external_wiki_url_desc=Bezoekers worden doorgestuurd naar de URL als ze op het tabblad klikken.
|
||||
settings.issues_desc=Ingebouwde compacte issuetracker inschakelen
|
||||
settings.use_external_issue_tracker=Externe issuetracker gebruiken
|
||||
settings.tracker_url_format=URL-formaat externe issuetracker
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=U kan de aanduidingen <code>{user} {repo} {index}</code> gebruiken voor de gebruikersnaam, de naam van de repository en de lijst van open tickets.
|
||||
settings.pulls_desc=Schakel 'pull request' in om publieke bijdragen te mogelijk te maken
|
||||
settings.danger_zone=Gevaren zone
|
||||
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
|
||||
settings.convert=Converteren naar gewone repository
|
||||
settings.convert_desc=U kunt deze mirror converteren naar een gewone repository. Dit kan niet ongedaan worden gemaakt.
|
||||
settings.convert_notices_1=- 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.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
|
||||
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.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.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 be became independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.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
|
||||
settings.make_transfer=Maak overdracht
|
||||
@@ -565,14 +615,21 @@ settings.transfer_succeed=Eigendom repositorie succesvol overgedragen
|
||||
settings.confirm_delete=Bevestig verwijdering
|
||||
settings.add_collaborator=Nieuwe medewerker toevoegen
|
||||
settings.add_collaborator_success=medewerker is toegevoegd.
|
||||
settings.delete_collaborator=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=Search user...
|
||||
settings.search_user_placeholder=Zoek gebruiker...
|
||||
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_success=Webhook has been deleted successfully!
|
||||
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=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
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=Slack domein
|
||||
settings.slack_channel=Slack kanaal
|
||||
settings.deploy_keys=Installeer sleutels
|
||||
settings.add_deploy_key=Toevoegen deploy sleutel
|
||||
settings.deploy_key_desc=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
|
||||
@@ -627,9 +685,13 @@ diff.parent=bovenliggende
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Diff gegevens niet beschikbaar.
|
||||
diff.show_diff_stats=Toon Diff Stats
|
||||
diff.show_split_view=Zij-aan-zij weergave
|
||||
diff.show_unified_view=Gecombineerde weergave
|
||||
diff.stats_desc=<strong>%d gewijzigde bestanden</strong> met <strong>toevoegingen van %d</strong> en <strong>%d verwijderingen</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Bestand weergeven
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=Releases
|
||||
release.new_release=Nieuwe release
|
||||
@@ -639,32 +701,32 @@ 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.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
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
|
||||
release.tag_helper=Kies een bestaande tag, of creëer een nieuwe tag bij publiceren.
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=Titel
|
||||
release.content=Inhoud
|
||||
release.write=Schrijf
|
||||
release.preview=Voorbeeld
|
||||
release.loading=Laden...
|
||||
release.prerelease_desc=Dit is een beta-versie
|
||||
release.prerelease_helper=Wij wijzen u erop dat deze release is niet geschikt voor productie doeleinden.
|
||||
release.cancel=Cancel
|
||||
release.cancel=Annuleren
|
||||
release.publish=Release publiceren
|
||||
release.save_draft=Concept opslaan
|
||||
release.edit_release=Release bewerken
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=Deze release verwijderen
|
||||
release.deletion=Release verwijderen
|
||||
release.deletion_desc=Als deze release verwijdert, worden de bijbehorende Git tag ook gewist. Wilt u doorgaan?
|
||||
release.deletion_success=Release is verwijderd!
|
||||
release.tag_name_already_exist=Versie met deze naam bestaat al.
|
||||
release.downloads=Downloads
|
||||
|
||||
[org]
|
||||
org_name_holder=Organisatienaam
|
||||
org_full_name_holder=Organization Full Name
|
||||
org_full_name_holder=Volledige naam organisatie
|
||||
org_name_helper=Een goede organisatienaam is kort en memorabel.
|
||||
create_org=Nieuwe organisatie aanmaken
|
||||
repo_updated=Geupdate
|
||||
@@ -691,8 +753,8 @@ settings.website=Website
|
||||
settings.location=Locatie
|
||||
settings.update_settings=Instellingen bijwerken
|
||||
settings.update_setting_success=Organisatie instellingen zijn succesvol bijgewerkt.
|
||||
settings.change_orgname_prompt=This change will affect how links relate to the organization.
|
||||
settings.update_avatar_success=Organization avatar setting has been updated successfully.
|
||||
settings.change_orgname_prompt=Deze verandering beinvloed de verhouding tussen links en de organisatie.
|
||||
settings.update_avatar_success=Organisatie avatar-instellingen zijn succesvol gewijzigd.
|
||||
settings.delete=Verwijder organisatie
|
||||
settings.delete_account=Verwijder deze organisatie
|
||||
settings.delete_prompt=Deze actie zal de origanisatie permanent verwijderen. U kunt dit <strong>NIET</strong> terug draaien!
|
||||
@@ -701,16 +763,17 @@ 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=Zichtbaarheid lidmaatschap:
|
||||
members.public=Openbaar
|
||||
members.public_helper=maak prive
|
||||
members.private=Prive
|
||||
members.private_helper=maak openbaar
|
||||
members.member_role=Rol van lid:
|
||||
members.owner=Eigenaar
|
||||
members.member=Lid
|
||||
members.conceal=Verbergen
|
||||
members.remove=Verwijderen
|
||||
members.leave=Verlaat
|
||||
members.invite_desc=Begin met het typen van een gebruikersnaam om een nieuw lid aan %s uit te nodigen:
|
||||
members.invite_desc=Voeg nieuw lid toe aan %s:
|
||||
members.invite_now=Nu uitnodigen
|
||||
|
||||
teams.join=Lid worden
|
||||
@@ -735,9 +798,10 @@ teams.read_permission_desc=Dit team heeft <strong>Lees</strong> rechten : leden
|
||||
teams.write_permission_desc=Dit team heeft <strong>Schrijf</strong> rechten : leden kunnen repositories lezen en push aanvragen verwerken.
|
||||
teams.admin_permission_desc=Dit team heeft <strong>Beheerders</strong> rechten : leden kunnen repositories lezen en push aanvragen verwerken en medewerkers toevoegen.
|
||||
teams.repositories=Teamrepositories
|
||||
teams.search_repo_placeholder=Repository zoeken...
|
||||
teams.add_team_repository=Nieuwe teamrepositorie aanmaken
|
||||
teams.remove_repo=Verwijder
|
||||
teams.add_nonexistent_repo=De opslagplaats die u probeert toe te voegen niet bestaat, kunt u het eerst aanmaken.
|
||||
teams.add_nonexistent_repo=De opslagplaats die u probeert toe te voegen bestaat niet: maak deze eerst aan.
|
||||
|
||||
[admin]
|
||||
dashboard=Dashboard
|
||||
@@ -748,9 +812,9 @@ authentication=Autenticaties
|
||||
config=Configuratie
|
||||
notices=Systeem aankondigingen
|
||||
monitor=Bijhouden
|
||||
first_page=First
|
||||
last_page=Last
|
||||
total=Total: %d
|
||||
first_page=Eerste
|
||||
last_page=Laatste
|
||||
total=Totaal: %d
|
||||
|
||||
dashboard.statistic=Statistieken
|
||||
dashboard.operations=Bewerkingen
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=Verwijder alle inactieve accounts
|
||||
dashboard.delete_inactivate_accounts_success=Alle inactivering van rekeningen hebben verwijderd.
|
||||
dashboard.delete_repo_archives=Verwijderen van alle repositories archieven
|
||||
dashboard.delete_repo_archives_success=Alle repositories archieven hebben verwijderd.
|
||||
dashboard.delete_missing_repos=Delete all repository records that lost Git files
|
||||
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
|
||||
dashboard.delete_missing_repos=Verwijder alle repositories zonder Git files
|
||||
dashboard.delete_missing_repos_success=Alle repositories zonder Git files verwijderd.
|
||||
dashboard.git_gc_repos=Garbage collectie uitvoeren
|
||||
dashboard.git_gc_repos_success=Garbage collectie met succes uitgevoerd.
|
||||
dashboard.resync_all_sshkeys=Herschrijf '.ssh/authorized_keys' (Let op: alle sleutels die niet van Gogs zijn zullen verloren gaan!)
|
||||
dashboard.resync_all_sshkeys_success=Alle publieke sleutels zijn herschreven.
|
||||
dashboard.resync_all_update_hooks=Herschrijf alle repositorie-hooks (nodig als de configuratie bestandslocatie is gewijzigd)
|
||||
dashboard.resync_all_update_hooks_success=Alle repositorie-hooks zijn herschreven.
|
||||
dashboard.reinit_missing_repos=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
|
||||
@@ -811,24 +877,26 @@ users.activated=Geactiveerd
|
||||
users.admin=Admin
|
||||
users.repos=Repos
|
||||
users.created=Aangemaakt
|
||||
users.send_register_notify=Send Registration Notification To User
|
||||
users.new_success=New account '%s' has been created successfully.
|
||||
users.send_register_notify=Stuur notificatie voor registratie naar gebruiker
|
||||
users.new_success=Nieuw account '%s' is aangemaakt.
|
||||
users.edit=Bewerken
|
||||
users.auth_source=Authentication Source
|
||||
users.auth_source=Authenticatiebron
|
||||
users.local=Lokaal
|
||||
users.auth_login_name=Authentication Login Name
|
||||
users.password_helper=Leave it empty to remain unchanged.
|
||||
users.auth_login_name=Authenticatie-loginnaam
|
||||
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-limiet voor aanmaken van repositories
|
||||
users.max_repo_creation_desc=(Zet op -1 om de globale limiet te gebruiken)
|
||||
users.is_activated=Dit account is geactiveerd
|
||||
users.is_admin=Dit account heeft beheerdersrechten
|
||||
users.allow_git_hook=Deze account beschikt over machtigingen voor het maken van Git haken
|
||||
users.allow_import_local=This account has permissions to import local repositories
|
||||
users.allow_import_local=Dit account mag lokale repositories importeren
|
||||
users.update_profile=Account profiel bijwerken
|
||||
users.delete_account=Dit account verwijderen
|
||||
users.still_own_repo=Dit account is nog steeds eigendom van een repositorie. U moet deze repositorie eerst verwijderen of overdragen.
|
||||
users.still_has_org=Deze account nog steeds lidmaatschap van organisatie, u hebt naar links of hen eerst verwijderen.
|
||||
users.deletion_success=Account has been deleted successfully!
|
||||
users.deletion_success=Het account is verwijderd!
|
||||
|
||||
orgs.org_manage_panel=Organisaties beheren
|
||||
orgs.name=Naam
|
||||
@@ -843,46 +911,51 @@ repos.watches=Volgers
|
||||
repos.stars=Sterren
|
||||
repos.issues=Kwesties
|
||||
|
||||
auths.auth_manage_panel=Authentication Manage Panel
|
||||
auths.new=Add New Source
|
||||
auths.auth_manage_panel=Authenticatie-beheer paneel
|
||||
auths.new=Nieuwe bron toevoegen
|
||||
auths.name=Naam
|
||||
auths.type=Type
|
||||
auths.enabled=Ingeschakeld
|
||||
auths.updated=Bijgewerkt
|
||||
auths.auth_type=Authentication Type
|
||||
auths.auth_name=Authentication Name
|
||||
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=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.filter=User Filter
|
||||
auths.admin_filter=Admin Filter
|
||||
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
|
||||
auths.smtp_auth=SMTP Authentication Type
|
||||
auths.smtp_auth=SMTP-authenticatietype
|
||||
auths.smtphost=SMTP host
|
||||
auths.smtpport=SMTP poort
|
||||
auths.allowed_domains=Allowed Domains
|
||||
auths.allowed_domains_helper=Leave it empty to not restrict any domains. Multiple domains should be separated by comma ','.
|
||||
auths.allowed_domains=Toegelaten domeinen
|
||||
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=Skip TLS Verify
|
||||
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.update=Update Authentication Setting
|
||||
auths.delete=Delete This Authentication
|
||||
auths.delete_auth_title=Authentication Deletion
|
||||
auths.delete_auth_desc=This authentication is going to be deleted, do you want to continue?
|
||||
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=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!
|
||||
|
||||
config.server_config=Serverconfiguratie
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Statische bestanden basis pad
|
||||
config.log_file_root_path=Log bestand basis pad
|
||||
config.script_type=Script type
|
||||
config.reverse_auth_user=Omgekeerde verificatie gebruiker
|
||||
|
||||
config.ssh_config=SSH-configuratie
|
||||
config.ssh_enabled=Ingeschakeld
|
||||
config.ssh_start_builtin_server=Ingebouwde server starten
|
||||
config.ssh_domain=Domein
|
||||
config.ssh_port=Poort
|
||||
config.ssh_listen_port=Luister op poort
|
||||
config.ssh_root_path=Root-pad
|
||||
config.ssh_key_test_path=Pad voor key-tests
|
||||
config.ssh_keygen_path=Pad van keygen ('ssh-keygen')
|
||||
config.ssh_minimum_key_size_check=Controleer minimale key-lengte
|
||||
config.ssh_minimum_key_sizes=Minimale key-lengtes
|
||||
|
||||
config.db_config=Databaseconfiguratie
|
||||
config.db_type=Type
|
||||
config.db_host=Host
|
||||
@@ -907,16 +993,15 @@ config.db_user=Gebruiker
|
||||
config.db_ssl_mode=SSL modus
|
||||
config.db_ssl_mode_helper=(alleen voor "postgres")
|
||||
config.db_path=Pad
|
||||
config.db_path_helper=(for "sqlite3" and "tidb")
|
||||
config.db_path_helper=(voor "sqlite3" en "tidb")
|
||||
config.service_config=Serviceconfiguratie
|
||||
config.register_email_confirm=E-mailbevestiging registreren
|
||||
config.disable_register=Registratie uitgeschakeld
|
||||
config.show_registration_button=Registeren knop weergeven
|
||||
config.require_sign_in_view=Inloggen vereist om te kunnen inzien
|
||||
config.enable_cache_avatar=Avatar Cache inschakelen
|
||||
config.mail_notify=E-mailnotificaties
|
||||
config.disable_key_size_check=Disable Minimum Key Size Check
|
||||
config.enable_captcha=Enable Captcha
|
||||
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
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Schakel HELO uit
|
||||
config.mailer_name=Naam
|
||||
config.mailer_host=Host
|
||||
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
|
||||
@@ -962,23 +1050,34 @@ monitor.start=Starttijd
|
||||
monitor.execute_time=Uitvoertijd
|
||||
|
||||
notices.system_notice_list=Systeem aankondigingen
|
||||
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=Verwijder alle berichten
|
||||
notices.type=Type
|
||||
notices.type_1=Opslagplaats
|
||||
notices.desc=Beschrijving
|
||||
notices.op=Op.
|
||||
notices.delete_success=Systeem bericht is met succes verwijderd.
|
||||
notices.delete_success=System notices have been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo=repositorie aangemaakt in <a href="%s">%s</a>
|
||||
rename_repo=renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=push update naar <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`opende issue in <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>`
|
||||
create_pull_request=`created 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>`
|
||||
comment_issue=`reactie op issue <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=repositorie verplaatst naar <code>%s</code> naar <a href="%s">%s</a>
|
||||
push_tag=geduwd label <a href="%s/src/%s"> %[2]s</a> naar <a href="%[1]s"> %[3]s</a>
|
||||
compare_2_commits=Weergave vergelijking voor deze 2 commits
|
||||
compare_commits=Toon vergelijking voor deze %d commits
|
||||
|
||||
[tool]
|
||||
ago=geleden
|
||||
|
||||
631
conf/locale/locale_pl-PL.ini
Executable file → Normal file
631
conf/locale/locale_pl-PL.ini
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
265
conf/locale/locale_pt-BR.ini
Executable file → Normal file
265
conf/locale/locale_pt-BR.ini
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
app_desc=Um serviço de Git auto-hospedado e amigável escrito em Go
|
||||
|
||||
home=Página Inicial
|
||||
dashboard=Painel de controle
|
||||
dashboard=Página Inicial
|
||||
explore=Explorar
|
||||
help=Ajuda
|
||||
sign_in=Entrar
|
||||
@@ -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
|
||||
@@ -20,7 +20,7 @@ signed_in_as=Você é
|
||||
username=Usuário
|
||||
email=E-mail
|
||||
password=Senha
|
||||
re_type=Redigite
|
||||
re_type=Digite novamente
|
||||
captcha=Captcha
|
||||
|
||||
repository=Repositório
|
||||
@@ -28,6 +28,7 @@ organization=Organização
|
||||
mirror=Espelho
|
||||
new_repo=Novo Repositório
|
||||
new_migrate=Nova Migração
|
||||
new_mirror=Novo espelho
|
||||
new_fork=Novo Fork de Repositório
|
||||
new_org=Nova Organização
|
||||
manage_org=Gerenciar Organizações
|
||||
@@ -37,22 +38,15 @@ settings=Configurações
|
||||
your_profile=Seu perfil
|
||||
your_settings=Suas configurações
|
||||
|
||||
news_feed=Feed de Notícias
|
||||
pull_requests=Solicitações de Pull
|
||||
activities=Atividades
|
||||
pull_requests=Pull Requests
|
||||
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
|
||||
title=Etapas de instalação para primeira execução
|
||||
docker_helper=Se você está rodando o Gogs dentro do Docker, por favor leia os <a target="_blank" href="%s">Guias</a> cuidadosamente antes de mudar qualquer coisa nesta página!
|
||||
requite_db_desc=Gogs requer MySQL, PostgreSQL, SQLite3 ou TiDB.
|
||||
db_title=Configurações de Banco de Dados
|
||||
@@ -60,22 +54,22 @@ db_type=Tipo do Banco de Dados
|
||||
host=Host
|
||||
user=Usuário
|
||||
password=Senha
|
||||
db_name=Nome do Banco de Dados
|
||||
db_name=Nome do banco de dados
|
||||
db_helper=Por favor, use o mecanismo INNODB com o conjunto de caracteres utf8_general_ci para MySQL.
|
||||
ssl_mode=Modo SSL
|
||||
path=Caminho
|
||||
sqlite_helper=O caminho do arquivo do banco de dados SQLite3 ou TiDB.
|
||||
sqlite_helper=O caminho do arquivo de banco de dados SQLite3 ou TiDB. <br>Por favor use o caminho absoluto quando você iniciar como serviço.
|
||||
err_empty_db_path=O Caminho do banco de dados SQLite3 ou TiDB não pode ser vazio.
|
||||
err_invalid_tidb_name=Nome do banco de dados TiDB não permite os caracteres "." e "-".
|
||||
no_admin_and_disable_registration=Você não pode desabilitar o registro sem criar uma conta de administrador.
|
||||
err_empty_admin_password=A senha de administrador não pode ser vazia.
|
||||
|
||||
general_title=Configurações Gerais do Gogs
|
||||
app_name=Nome do Aplicativo
|
||||
general_title=Configurações gerais do Gogs
|
||||
app_name=Nome do aplicativo
|
||||
app_name_helper=Coloque o nome da sua organização aqui!
|
||||
repo_path=Caminho da Raiz do Repositório
|
||||
repo_path=Caminho da raíz do repositório
|
||||
repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório.
|
||||
run_user=Executar Usuário
|
||||
run_user=Usuário da execução
|
||||
run_user_helper=O usuário deve ter acesso ao caminho raiz do repositório e executar o Gogs
|
||||
domain=Domínio
|
||||
domain_helper=Isto afeta URLs para clonagem via SSH.
|
||||
@@ -83,35 +77,37 @@ ssh_port=Porta SSH
|
||||
ssh_port_helper=Número da porta que seu servidor SSH está usando, deixe vazio para desativar o recurso SSH.
|
||||
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=URL do aplicativo
|
||||
app_url_helper=Isto afeta a URL de clonagem via HTTP/HTTPs e também o email.
|
||||
log_root_path=Caminho do log
|
||||
log_root_path_helper=Pasta dos arquivos de log.
|
||||
|
||||
optional_title=Configurações Opcionais
|
||||
email_title=Configurações do Serviço de E-mail
|
||||
optional_title=Configurações opcionais
|
||||
email_title=Configurações do serviço de e-mail
|
||||
smtp_host=Host SMTP
|
||||
smtp_from=De
|
||||
smtp_from=De
|
||||
smtp_from_helper=O endereço de email deve atender a especificação RFC 5322. O formato deve ser um email ou "Nome" <email@example.com>.
|
||||
mailer_user=E-mail do Remetente
|
||||
mailer_password=Senha do Remetente
|
||||
register_confirm=Habilitar Confirmação de Registro
|
||||
mail_notify=Habilitar Notificação de Correio
|
||||
server_service_title=Configurações de Servidor e Outros Serviços
|
||||
offline_mode=Ativar Modo Offline
|
||||
mailer_user=E-mail do remetente
|
||||
mailer_password=Senha do remetente
|
||||
register_confirm=Habilitar confirmação de registro
|
||||
mail_notify=Habilitar notificação de e-mail
|
||||
server_service_title=Configurações de servidor e outros serviços
|
||||
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=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.
|
||||
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
|
||||
enable_captcha=Habilitar captcha
|
||||
enable_captcha_popup=Obrigar validação por captcha para auto-registro de usuários.
|
||||
require_sign_in_view=Requerer login para a visualização de páginas
|
||||
require_sign_in_view=Obrigar login para a visualização de páginas
|
||||
require_sign_in_view_popup=Somente usuários autenticados podem ver todas as páginas, visitantes somente podem entrar ou se cadastrar.
|
||||
admin_setting_desc=Você não precisa criar uma conta de administrador agora, no entanto o primeiro usuário (ID=1) automaticamente terá acesso de administrador.
|
||||
admin_title=Configurações da Conta de Administrador
|
||||
admin_name=Nome de Usuário
|
||||
admin_title=Configurações da conta de administrador
|
||||
admin_name=Nome de usuário
|
||||
admin_password=Senha
|
||||
confirm_password=Confirmar Senha
|
||||
admin_email=E-mail do Administrador
|
||||
confirm_password=Confirmar senha
|
||||
admin_email=E-mail do administrador
|
||||
install_gogs=Instalar Gogs
|
||||
test_git_failed=Falha ao testar o comando 'git': %v
|
||||
sqlite3_not_available=Sua versão não suporta SQLite3, por favor faça o download da versão binária oficial em %s, NÃO da versão gobuild.
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=O usuário da execução não é o usuário atual: %s -> %s
|
||||
save_config_failed=Falha ao salvar a configuração: %v
|
||||
invalid_admin_setting=Configuração da conta de administrador está inválida: %v
|
||||
install_success=Bem-vindo! Estamos contentes que você escolheu o Gogs, divirta-se e tenha cuidado.
|
||||
invalid_log_root_path=Pasta raíz do log é inválida: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Nome de Usuário ou E-mail
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=Em seus repositórios
|
||||
|
||||
[explore]
|
||||
repos=Repositórios
|
||||
users=Usuários
|
||||
search=Pesquisar
|
||||
|
||||
[auth]
|
||||
create_new_account=Criar Nova Conta
|
||||
@@ -158,13 +157,14 @@ 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
|
||||
activate_email=Verifique seu endereço de e-mail
|
||||
reset_password=Resetar sua senha
|
||||
register_success=Registrado com sucesso. Bem vindo
|
||||
register_notify=Welcome on board
|
||||
register_notify=Bem-vindo a bordo
|
||||
|
||||
[modal]
|
||||
yes=Sim
|
||||
@@ -187,7 +187,7 @@ AdminEmail=E-mail do Administrador
|
||||
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 (_).`
|
||||
size_error='deve ser o tamanho %s.'
|
||||
size_error=`deve ser do tamanho %s.`
|
||||
min_size_error=` deve conter pelo menos %s caracteres.`
|
||||
max_size_error=` deve conter no máximo %s caracteres.`
|
||||
email_error=` não é um endereço de e-mail válido.`
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=Nome do repositório já foi tomado.
|
||||
org_name_been_taken=Nome da organização já foi tomado.
|
||||
team_name_been_taken=Nome da equipe já foi tomado.
|
||||
email_been_used=Endereço de e-mail já foi usado.
|
||||
illegal_team_name=O nome da equipe contém caracteres não permitidos.
|
||||
username_password_incorrect=Usuário ou senha incorretos.
|
||||
enterred_invalid_repo_name=Por favor certifique-se que informou o nome do repositório corretamente.
|
||||
enterred_invalid_owner_name=Por favor, verifique se o nome do proprietário está correto.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=Sua conta ainda tem propriedade do repositório, você tem que ex
|
||||
still_has_org=Sua conta ainda faz parte da organização, você deve sair ou excluí-la primeiro.
|
||||
org_still_own_repo=Esta organização ainda tem a propriedade do repositório, você deve excluir ou transferí-la primeiro.
|
||||
|
||||
still_own_user=Esta autenticação ainda é usada por alguns usuários, você deve movê-los e depois apagar novamente.
|
||||
|
||||
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
|
||||
followers=Seguidores
|
||||
starred=Favorito
|
||||
following=Seguindo
|
||||
follow=Seguir
|
||||
unfollow=Deixar de seguir
|
||||
|
||||
form.name_reserved=O nome de usuário '%s' não pode ser usado.
|
||||
form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de usuário.
|
||||
@@ -247,6 +245,7 @@ uid=Uid
|
||||
|
||||
public_profile=Perfil Público
|
||||
profile_desc=Seu endereço de E-mail é publico e será usado para qualquer notificação relacionada à conta, e qualquer operação na web feita através do site.
|
||||
password_username_disabled=Usuários do tipo não-local não são permitidos de mudarem seu nome de usuário.
|
||||
full_name=Nome Completo
|
||||
website=Site
|
||||
location=Localização
|
||||
@@ -258,11 +257,10 @@ continue=Continuar
|
||||
cancel=Cancelar
|
||||
|
||||
enable_custom_avatar=Habilitar Avatar Customizado
|
||||
enable_custom_avatar_helper=Habilite para desativar a busca no Gravatar
|
||||
choose_new_avatar=Escolha um novo avatar
|
||||
update_avatar=Atualizar configuração de Avatar
|
||||
delete_current_avatar=Excluir o Avatar atual
|
||||
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
|
||||
no_custom_avatar_available=Nenhum avatar personalizado disponível, não pode habilitá-lo.
|
||||
update_avatar_success=Sua configuração de avatar foi atualizada com sucesso.
|
||||
|
||||
change_password=Mudança de senha
|
||||
@@ -271,6 +269,7 @@ new_password=Nova Senha
|
||||
retype_new_password=Digite novamente a nova senha
|
||||
password_incorrect=A senha atual não está correta.
|
||||
change_password_success=A senha está alterada com sucesso. Você pode agora entrar com a senha nova.
|
||||
password_change_disabled=Usuários do tipo não-local não são permitidos de mudarem sua senha.
|
||||
|
||||
emails=Endereços de E-mail
|
||||
manage_emails=Gerenciar endereços de e-mail
|
||||
@@ -351,11 +350,16 @@ 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)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
mirror_address=Endereço do espelho
|
||||
mirror_address_desc=Por favor, inclua as credenciais do usuário necessários no endereço.
|
||||
watchers=Observadores
|
||||
stargazers=Usuários que estrelaram
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=O proprietário atingiu o limite máximo de criação de repositórios de %d.
|
||||
form.name_reserved=O nome de repositório '%s' não pode ser usado.
|
||||
form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de repositório.
|
||||
|
||||
@@ -367,8 +371,9 @@ migrate.clone_address=Endereço de Clone
|
||||
migrate.clone_address_desc=Isto pode ser uma URL de HTTP/HTTPS/GIT ou um caminho de diretório local.
|
||||
migrate.permission_denied=Você não pode importar repositórios locais.
|
||||
migrate.invalid_local_path=Caminho local inválido, não existe ou não é um diretório.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Migração falhou: %v
|
||||
|
||||
mirror_from=espelho de
|
||||
forked_from=forkado de
|
||||
fork_from_self=Você não pode criar fork de um repositório que já é seu!
|
||||
copy_link=Copiar
|
||||
@@ -388,9 +393,10 @@ create_new_repo_command=Criar um novo repositório na linha de comando
|
||||
push_exist_repo=Push um repositório existente na linha de comando
|
||||
repo_is_empty=Este repositório está vazio, por favor volte mais tarde!
|
||||
|
||||
code=Código
|
||||
branch=Branch
|
||||
tree=Árvore
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filtrar branch ou tag
|
||||
branches=Branches
|
||||
tags=Tags
|
||||
issues=Problemas
|
||||
@@ -467,7 +473,7 @@ issues.closed_at=`fechado em <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`reaberto em <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`citou este problema em um commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Autor
|
||||
issues.admin=Administrador
|
||||
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>
|
||||
@@ -484,8 +490,9 @@ issues.label_modify=Alteração de etiqueta
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Novo Pull Request
|
||||
pulls.compare_changes=Comparar mudanças
|
||||
pulls.compare_changes_desc=Comparar os dois branches e criar pull request com as mudanças.
|
||||
pulls.compare_base=base
|
||||
@@ -505,11 +512,11 @@ pulls.merged=Merge realizado
|
||||
pulls.has_merged=Este pull request foi mesclado com sucesso!
|
||||
pulls.data_broken=Dados deste pull request foram quebrados devido à deleção de informação do fork.
|
||||
pulls.is_checking=A verificação do conflito ainda está em progresso, por favor recarregue a página em instantes.
|
||||
pulls.can_auto_merge_desc=Você pode realizar uma auto-mescla neste pull request.
|
||||
pulls.cannot_auto_merge_desc=Você não pode realizar uma auto-mescla porque há conflitos entre os commits.
|
||||
pulls.cannot_auto_merge_helper=Por favor, utilize linha de comando para solucionar isto.
|
||||
pulls.can_auto_merge_desc=Este pull request pode ser mesclado automaticamente.
|
||||
pulls.cannot_auto_merge_desc=Este pull request não pode ser mesclado automaticamente pois há conflitos.
|
||||
pulls.cannot_auto_merge_helper=Por favor, mescle manualmente para resolver os conflitos.
|
||||
pulls.merge_pull_request=Merge Pull Request
|
||||
pulls.open_unmerged_pull_exists=' Você não pode executar a operação de reabrir porque já existe uma solicitação de pull aberta (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.'
|
||||
pulls.open_unmerged_pull_exists=`Você não pode executar a operação de reabrir porque já existe uma solicitação de pull aberta (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.`
|
||||
|
||||
milestones.new=Novo marco
|
||||
milestones.open_tab=%d abertos
|
||||
@@ -535,29 +542,72 @@ milestones.deletion=Exclusão de marco
|
||||
milestones.deletion_desc=Excluir este marco removerá a informação dele em todos os problemas aos quais estiver associado. Você quer mesmo continuar?
|
||||
milestones.deletion_success=Marco excluído com sucesso!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Bem-vindo ao wiki!
|
||||
wiki.welcome_desc=Wiki é o lugar onde você gostaria de documentar o seu projeto em conjunto e torná-lo melhor.
|
||||
wiki.create_first_page=Criar a primeira página
|
||||
wiki.page=Página
|
||||
wiki.filter_page=Filtrar página
|
||||
wiki.new_page=Criar nova página
|
||||
wiki.default_commit_message=Escrever um comentário sobre esta atualização (opcional).
|
||||
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=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
|
||||
|
||||
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.danger_zone=Zona de Perigo
|
||||
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.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.use_external_issue_tracker=Usar issue tracker externo
|
||||
settings.tracker_url_format=Formato de URL do issue tracker externo
|
||||
settings.tracker_issue_style=Estilo de nome de issue tracker externo:
|
||||
settings.tracker_issue_style.numeric=Numérico <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alfanumérico <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=Você pode usar o espaço reservado <code>{user} {repo} {index}</code> para o nome do usuário, índice de nome e a questão do repositório.
|
||||
settings.pulls_desc=Habilitar pull requests para aceitar contribuições públicas
|
||||
settings.danger_zone=Zona de Perigo
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
|
||||
settings.convert=Converter para repositório tradicional
|
||||
settings.convert_desc=Você pode converter este espelho em um repositório tradicional. Esta ação não pode ser revertida.
|
||||
settings.convert_notices_1=- Esta operação vai converter este repositório espelho em um repositório tradicional. Esta ação não pode ser desfeita.
|
||||
settings.convert_confirm=Confirmar conversão
|
||||
settings.convert_succeed=Repositório espelho convertido para tradicional com sucesso.
|
||||
settings.transfer=Transferir Propriedade
|
||||
settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador.
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
|
||||
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.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=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
|
||||
settings.make_transfer=Fazer Transferência
|
||||
@@ -565,14 +615,21 @@ 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=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=Search user...
|
||||
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.
|
||||
settings.user_is_org_member=O usuário é um membro da organização que não pode ser adicionado como um colaborador.
|
||||
settings.add_webhook=Adicionar Webhook
|
||||
settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no Gogs. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
|
||||
settings.webhook_deletion=Deletar Webhook
|
||||
settings.webhook_deletion_desc=Deletar este Webhook vai remover sua informação e todo o histórico de entrega. Deseja continuar?
|
||||
settings.webhook_deletion_success=Webhook deletado com sucesso!
|
||||
settings.webhook.test_delivery=Entrega de teste
|
||||
settings.webhook.test_delivery_desc=Enviar uma entrega de evento de push falso para testar suas configurações de webhook
|
||||
settings.webhook.test_delivery_success=O teste webhook foi adicionado para a fila de entrega. Pode demorar alguns segundos antes de ser exibido no histórico de entrega.
|
||||
settings.webhook.request=Solicitação
|
||||
settings.webhook.response=Resposta
|
||||
settings.webhook.headers=Cabeçalhos
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=Domínio
|
||||
settings.slack_channel=Canal
|
||||
settings.deploy_keys=Chaves de Deploy
|
||||
settings.add_deploy_key=Nova chave
|
||||
settings.deploy_key_desc=Chave de deploy só tem acesso somente leitura. Não é igual as chaves SSH de conta pessoal.
|
||||
settings.no_deploy_keys=Você ainda não adicionou chaves para implantação de software.
|
||||
settings.title=Título
|
||||
settings.deploy_key_content=Conteúdo da chave
|
||||
@@ -627,9 +685,13 @@ diff.parent=pai
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Dados de Diff não disponíveis.
|
||||
diff.show_diff_stats=Mostrar estatísticas do Diff
|
||||
diff.show_split_view=Visão dividida
|
||||
diff.show_unified_view=Visão unificada
|
||||
diff.stats_desc=<strong> %d arquivos alterados</strong> com <strong>%d adições</strong> e <strong>%d exclusões</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Ver Arquivo
|
||||
diff.file_supressed=Diff do arquivo suprimido porque é muito extenso
|
||||
diff.too_many_files=Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff
|
||||
|
||||
release.releases=Versões
|
||||
release.new_release=Nova Versão
|
||||
@@ -639,26 +701,26 @@ release.stable=Estável
|
||||
release.edit=editar
|
||||
release.ahead=<strong>%d</strong> commits para %s depois desta versão
|
||||
release.source_code=Código fonte
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=Publicar versões para iterar o produto.
|
||||
release.edit_subheader=Um changelog detalhado ajuda os usuários a entenderem o que foi melhorado.
|
||||
release.tag_name=Nome da tag
|
||||
release.target=Destino
|
||||
release.tag_helper=Escolha uma tag existente, ou crie uma nova tag em publicar.
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=Título
|
||||
release.content=Conteúdo
|
||||
release.write=Escrever
|
||||
release.preview=Visualizar
|
||||
release.loading=Carregando...
|
||||
release.prerelease_desc=Esta é uma versão prévia
|
||||
release.prerelease_helper=Vou salientar que esta versão é identificada como não pronta para produção.
|
||||
release.cancel=Cancel
|
||||
release.cancel=Cancelar
|
||||
release.publish=Publicar Versão
|
||||
release.save_draft=Salvar Rascunho
|
||||
release.edit_release=Editar Versão
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=Deletar esta versão
|
||||
release.deletion=Deleção de versão
|
||||
release.deletion_desc=Deletar esta versão vai deletar a tag do git correspondente. Você deseja continuar?
|
||||
release.deletion_success=A versão foi deletada com sucesso!
|
||||
release.tag_name_already_exist=Já existiu versão com esse nome de tag.
|
||||
release.downloads=Downloads
|
||||
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=Deleção da Organização
|
||||
settings.delete_org_desc=Esta organização será deletada permanentemente, você quer continuar?
|
||||
settings.hooks_desc=Adicionar Webhooks que serão acionados para <strong>todos os repositórios</strong> dessa organização.
|
||||
|
||||
members.membership_visibility=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
|
||||
members.conceal=Ocultar
|
||||
members.remove=Remover
|
||||
members.leave=Sair
|
||||
members.invite_desc=Comece digitando um nome de usuário para convidá-lo como novo membro para %s:
|
||||
members.invite_desc=Adicionar novo membro em %s:
|
||||
members.invite_now=Convidar Agora
|
||||
|
||||
teams.join=Juntar-se
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=Essa equipe concede acesso para <strong>Leitura</stro
|
||||
teams.write_permission_desc=Esta equipe concede acesso para <strong>escrita</strong>: Membros podem ler e fazer push para os repositórios da equipe.
|
||||
teams.admin_permission_desc=Esta equipe concede acesso de <strong>Administrador</strong>: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe.
|
||||
teams.repositories=Repositórios da Equipe
|
||||
teams.search_repo_placeholder=Pesquisar repositório...
|
||||
teams.add_team_repository=Adicionar Repositório da Equipe
|
||||
teams.remove_repo=Remover
|
||||
teams.add_nonexistent_repo=O repositório que você está tentando adicionar não existe, por favor, crie-o primeiro.
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=Excluir todas as contas inativas
|
||||
dashboard.delete_inactivate_accounts_success=Todas as contas inativas foram excluídas com sucesso.
|
||||
dashboard.delete_repo_archives=Excluir todos os arquivos dos repositórios
|
||||
dashboard.delete_repo_archives_success=Todos os arquivos dos repositórios foram excluídos com sucesso.
|
||||
dashboard.delete_missing_repos=Delete all repository records that lost Git files
|
||||
dashboard.delete_missing_repos_success=All repository records that lost Git files have been deleted successfully.
|
||||
dashboard.delete_missing_repos=Deletar todos os repositórios que perderam arquivos do git
|
||||
dashboard.delete_missing_repos_success=Todos os registros de repositórios que perderam arquivos do git foram deletados com sucesso.
|
||||
dashboard.git_gc_repos=Fazer coleta de lixo nos repositórios
|
||||
dashboard.git_gc_repos_success=Em todos repositórios, a coleta de lixo foi realizada com sucesso.
|
||||
dashboard.resync_all_sshkeys=Reescrever o arquivo '.ssh/authorized_keys' (atenção: chaves que não sejam do Gogs serão perdidas)
|
||||
dashboard.resync_all_sshkeys_success=Todas as chaves públicas foram reescritas com sucesso.
|
||||
dashboard.resync_all_update_hooks=Reescrever todos os hooks de atualização dos repositórios (necessário quando o caminho de configuração customizado é alterado)
|
||||
dashboard.resync_all_update_hooks_success=Os hooks de atualização de todos os repositórios foram reescritos com sucesso.
|
||||
dashboard.reinit_missing_repos=Reinicializar todos os registros de repositório que perderam os arquivos do Git
|
||||
dashboard.reinit_missing_repos_success=Todos os repositórios que perderam arquivos do Git foram reinicializados com sucesso.
|
||||
|
||||
dashboard.server_uptime=Servidor Ligado
|
||||
dashboard.current_goroutine=Goroutines Atuais
|
||||
@@ -820,6 +886,8 @@ users.auth_login_name=Nome de login da autenticação
|
||||
users.password_helper=Deixe em branco para não mudar.
|
||||
users.update_profile_success=O perfil da conta foi atualizado com sucesso.
|
||||
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.is_admin=Esta conta tem permissões de administrador
|
||||
users.allow_git_hook=Esta conta tem permissões para criar hooks do Git
|
||||
@@ -851,6 +919,7 @@ auths.enabled=Habilitado
|
||||
auths.updated=Atualizado
|
||||
auths.auth_type=Tipo de autenticação
|
||||
auths.auth_name=Nome da autenticação
|
||||
auths.security_protocol=Protocolo de segurança
|
||||
auths.domain=Domínio
|
||||
auths.host=Host
|
||||
auths.port=Porta
|
||||
@@ -859,9 +928,12 @@ auths.bind_password=Vincular senha
|
||||
auths.bind_password_helper=Atenção: Esta senha é armazenada em texto plano. Não use uma conta com muitos privilégios.
|
||||
auths.user_base=Base de pesquisa do usuário
|
||||
auths.user_dn=Usuário do DN
|
||||
auths.attribute_username=Atributo nome de usuário
|
||||
auths.attribute_username_placeholder=Deixe vazio para usar o valor do campo de formulário de entrada de nome de usuário.
|
||||
auths.attribute_name=Atributo primeiro nome
|
||||
auths.attribute_surname=Atributo sobrenome
|
||||
auths.attribute_mail=Atributo e-mail
|
||||
auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN
|
||||
auths.filter=Filtro de usuário
|
||||
auths.admin_filter=Filtro de administrador
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -883,6 +955,7 @@ auths.update=Atualizar a configuração da autenticação
|
||||
auths.delete=Excluir esta autenticação
|
||||
auths.delete_auth_title=Exclusão da autenticação
|
||||
auths.delete_auth_desc=Esta autenticação esta prestes a ser deletada, deseja continuar?
|
||||
auths.still_in_used=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
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Caminho Raiz para Arquivo Estático
|
||||
config.log_file_root_path=Caminho Raiz para Arquivo de Log
|
||||
config.script_type=Tipo de Script
|
||||
config.reverse_auth_user=Usuário de Autenticação Reversa
|
||||
|
||||
config.ssh_config=Configuração de SSH
|
||||
config.ssh_enabled=Habilitado
|
||||
config.ssh_start_builtin_server=Iniciar servidor embutido
|
||||
config.ssh_domain=Domínio
|
||||
config.ssh_port=Porta
|
||||
config.ssh_listen_port=Porta de escuta
|
||||
config.ssh_root_path=Caminho da raiz
|
||||
config.ssh_key_test_path=Caminho da chave de teste
|
||||
config.ssh_keygen_path=Caminho do keygen ('ssh-keygen')
|
||||
config.ssh_minimum_key_size_check=Verificar tamanho mínimo da chave
|
||||
config.ssh_minimum_key_sizes=Tamanhos mínimos da chave
|
||||
|
||||
config.db_config=Configuração do Banco de Dados
|
||||
config.db_type=Tipo
|
||||
config.db_host=Host
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=Requerer Confirmação de E-mail
|
||||
config.disable_register=Desabilitar Registro
|
||||
config.show_registration_button=Mostrar Botão de Registo
|
||||
config.require_sign_in_view=Requerer Entrar no Gogs para Ver
|
||||
config.enable_cache_avatar=Habilitar Cache de Avatar
|
||||
config.mail_notify=Notificação de Correio
|
||||
config.disable_key_size_check=Desativar verificação de tamanho mínimo da chave
|
||||
config.enable_captcha=Habilitar o Captcha
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Desabilitar HELO
|
||||
config.mailer_name=Nome
|
||||
config.mailer_host=Host
|
||||
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
|
||||
@@ -962,23 +1050,34 @@ monitor.start=Hora de Início
|
||||
monitor.execute_time=Tempo de Execução
|
||||
|
||||
notices.system_notice_list=Sistema de Notificações
|
||||
notices.view_detail_header=Ver detalhe do anúncio
|
||||
notices.actions=Ações
|
||||
notices.select_all=Selecionar tudo
|
||||
notices.deselect_all=Desmarcar tudo
|
||||
notices.inverse_selection=Seleção inversa
|
||||
notices.delete_selected=Apagar seleção
|
||||
notices.delete_all=Excluir todos os avisos
|
||||
notices.type=Tipo
|
||||
notices.type_1=Repositório
|
||||
notices.desc=Descrição
|
||||
notices.op=Op.
|
||||
notices.delete_success=Aviso do sistema foi deletado com sucesso.
|
||||
notices.delete_success=Avisos do sistema foram excluídos com sucesso.
|
||||
|
||||
[action]
|
||||
create_repo=repositório criado <a href="%s"> %s</a>
|
||||
rename_repo=renomeou o o repositório <code>%[1]s</code> para <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=pushed para <a href="%[1]s/src/%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||
create_issue='questão aberta <a href="%s/issues/%s">%s#%[2]s</a>'
|
||||
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>`
|
||||
comment_issue='comentou sobre a questão <a href="%s/issues/%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>
|
||||
push_tag=Foi feito push na tag <a href="%s/src/%s">%[2]s</a> para <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Ver comparação desses 2 commits
|
||||
compare_commits=Ver comparação entre esses %d commits
|
||||
|
||||
[tool]
|
||||
ago=atrás
|
||||
|
||||
341
conf/locale/locale_ru-RU.ini
Executable file → Normal file
341
conf/locale/locale_ru-RU.ini
Executable file → Normal file
@@ -1,59 +1,53 @@
|
||||
app_desc=Удобная служба для собственного Git-репозитория, написанная на языке Go
|
||||
app_desc=Удобная служба для собственного Git-репозитория
|
||||
|
||||
home=Главная
|
||||
dashboard=Панель мониторинга
|
||||
dashboard=Панель управления
|
||||
explore=Обзор
|
||||
help=Помощь
|
||||
sign_in=Войти
|
||||
sign_out=Выход
|
||||
sign_up=Регистрация
|
||||
register=Зарегистрироваться
|
||||
register=Регистрация
|
||||
website=Веб-сайт
|
||||
version=Версия
|
||||
page=Страница
|
||||
template=Шаблон
|
||||
language=Язык
|
||||
create_new=Создать...
|
||||
user_profile_and_more=Профиль и остальное
|
||||
user_profile_and_more=Профиль пользователя и прочее
|
||||
signed_in_as=Вы вошли как
|
||||
|
||||
username=Имя пользователя
|
||||
email=Эл. почта
|
||||
password=Пароль
|
||||
re_type=Повтор
|
||||
captcha=Captcha
|
||||
re_type=Введите повторно
|
||||
captcha=Капча
|
||||
|
||||
repository=Репозиторий
|
||||
organization=Организация
|
||||
mirror=Зеркало
|
||||
new_repo=Новый репозиторий
|
||||
new_migrate=Новая Миграция
|
||||
new_fork=Новый проект из репозитория
|
||||
new_org=Новая Организация
|
||||
manage_org=Управление Организацией
|
||||
new_mirror=Новое зеркало
|
||||
new_fork=Новое ответвление репозитория
|
||||
new_org=Новая организация
|
||||
manage_org=Управление организациями
|
||||
admin_panel=Панель администратора
|
||||
account_settings=Настройки аккаунта
|
||||
settings=Настройки
|
||||
your_profile=Ваш профиль
|
||||
your_settings=Ваши настройки
|
||||
|
||||
news_feed=Лента новостей
|
||||
pull_requests=Pull Requests
|
||||
issues=Вопросы
|
||||
activities=Активность
|
||||
pull_requests=Запросы на слияние
|
||||
issues=Задачи
|
||||
|
||||
cancel=Отмена
|
||||
|
||||
[search]
|
||||
search=Поиск...
|
||||
repository=Репозиторий
|
||||
user=Пользователь
|
||||
issue=Проблема
|
||||
code=Код
|
||||
|
||||
[install]
|
||||
install=Установка
|
||||
title=Установочные шаги для первого запуска
|
||||
docker_helper=Если вы используете Gogs в Docker-контейнере, пожалуйста прочтите <a target="_blank" href="%s">эти советы</a>, перед тем как что-либо изменить!
|
||||
docker_helper=Если вы запускаете Gogs внутри Docker, пожалуйста прочтите <a target="_blank" href="%s">эти советы</a> внимательно перед тем как что-либо изменить на этой странице!
|
||||
requite_db_desc=Gogs требует MySQL, PostgreSQL, SQLite3 или TiDB.
|
||||
db_title=Настройки базы данных
|
||||
db_type=Тип базы данных
|
||||
@@ -64,17 +58,17 @@ db_name=Имя базы данных
|
||||
db_helper=Для MySQL используйте тип таблиц InnoDB с кодировкой utf8_general_ci.
|
||||
ssl_mode=Режим SSL
|
||||
path=Путь
|
||||
sqlite_helper=Путь до базы данных SQLite или TiDB.
|
||||
sqlite_helper=Путь к файлу базы данных SQLite3 или TiDB. <br>Укажите абсолютный путь при запуске в качестве службы.
|
||||
err_empty_db_path=Путь к базе данных SQLite3 или TiDB не может быть пустым.
|
||||
err_invalid_tidb_name=Название базы данных TiDB не может содержать символы "." и "-".
|
||||
no_admin_and_disable_registration=Вы не можете отключить регистрацию, не создав аккаунт администратора.
|
||||
err_invalid_tidb_name=Имя базы данных TiDB не может содержать символы "." и "-".
|
||||
no_admin_and_disable_registration=Вы не можете отключить регистрацию до создания учетной записи администратора.
|
||||
err_empty_admin_password=Пароль администратора не может быть пустым.
|
||||
|
||||
general_title=Общие параметры Gogs
|
||||
app_name=Имя приложения
|
||||
app_name_helper=Укажите здесь название вашей потрясающей организации!
|
||||
repo_path=Путь корня репозитория
|
||||
repo_path_helper=Все удаленные репозитории Git будут сохранены в этой директории.
|
||||
repo_path_helper=Все сетевые репозитории Git будут сохранены в этой директории.
|
||||
run_user=Пользователь
|
||||
run_user_helper=У пользователя должен быть доступ к пути к корню репозитория и к запуску Gogs.
|
||||
domain=Домен
|
||||
@@ -85,6 +79,8 @@ http_port=Порт HTTP
|
||||
http_port_helper=Номер порта, который приложение будет слушать.
|
||||
app_url=URL приложения
|
||||
app_url_helper=Этот параметр влияет на URL для клонирования по HTTP/HTTPS и на адреса в электронной почте.
|
||||
log_root_path=Путь к журналу
|
||||
log_root_path_helper=Каталог для записи файлов журнала.
|
||||
|
||||
optional_title=Расширенные настройки
|
||||
email_title=Настройки службы электронной почты
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=Текущий пользователь не является
|
||||
save_config_failed=Не удалось сохранить конфигурацию: %v
|
||||
invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v
|
||||
install_success=Добро пожаловать! Мы рады, что вы выбрали Gogs. Веселитесь и берегите себя.
|
||||
invalid_log_root_path=Недопустимый путь для логов: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Имя пользователь или E-mail
|
||||
@@ -128,14 +125,16 @@ password_holder=Пароль
|
||||
switch_dashboard_context=Переключить контекст панели управления
|
||||
my_repos=Мои репозитории
|
||||
collaborative_repos=Совместные репозитории
|
||||
my_orgs=Моя Организация
|
||||
my_orgs=Мои организации
|
||||
my_mirrors=Мои зеркала
|
||||
view_home=Показать %s
|
||||
|
||||
issues.in_your_repos=В вашем репозитории
|
||||
issues.in_your_repos=В ваших репозиториях
|
||||
|
||||
[explore]
|
||||
repos=Репозитории
|
||||
users=Пользователи
|
||||
search=Поиск
|
||||
|
||||
[auth]
|
||||
create_new_account=Создать новый аккаунт
|
||||
@@ -149,7 +148,7 @@ forget_password=Забыли пароль?
|
||||
sign_up_now=Нужен аккаунт? Зарегистрируйтесь.
|
||||
confirmation_mail_sent_prompt=Новое письмо для подтверждения было направлено на <b>%s</b>, пожалуйста, проверьте ваш почтовый ящик в течение %d часов для завершения регистрации.
|
||||
active_your_account=Активируйте свой аккаунт
|
||||
resent_limit_prompt=Вы слишком часто отправляете письмо с активацией. Подождите 3 минуты, пожалуйста.
|
||||
resent_limit_prompt=Извините, вы уже запросили активацию по электронной почте недавно. Пожалуйста, подождите 3 минуты, а затем повторите попытку.
|
||||
has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (<b>%s</b>). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже.
|
||||
resend_mail=Нажмите здесь, чтобы переотправить активационное письмо
|
||||
email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью.
|
||||
@@ -158,13 +157,14 @@ reset_password=Сброс пароля
|
||||
invalid_code=Извините, ваш код подтверждения истек или не является допустимым.
|
||||
reset_password_helper=Нажмите здесь, чтобы сбросить свой пароль
|
||||
password_too_short=Длина пароля не менее 6 символов.
|
||||
non_local_account=Нелокальные аккаунты не могут изменить пароль через Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=Пожалуйста активируйте свой аккаунт
|
||||
activate_email=Подтвердите адрес своей электронной почты
|
||||
reset_password=Восстановите ваш пароль
|
||||
register_success=Регистрация окончена. Добро пожаловать!
|
||||
register_notify=Welcome on board
|
||||
register_notify=Добро пожаловать на борт
|
||||
|
||||
[modal]
|
||||
yes=Да
|
||||
@@ -191,24 +191,23 @@ size_error=` должен быть размер %s.`
|
||||
min_size_error=«должен содержать по крайней мере %s символов.»
|
||||
max_size_error=` должен содержать максимум %s символов.`
|
||||
email_error=«не является адресом электронной почты.»
|
||||
url_error=«не является допустимым URL-адресом.»
|
||||
include_error=` должен содержать '%s'`
|
||||
url_error=` не является допустимым URL-адресом.`
|
||||
include_error=` должен содержать '%s'.`
|
||||
unknown_error=Неизвестная ошибка:
|
||||
captcha_incorrect=CAPTCHA не совпадает.
|
||||
password_not_match=Пароль и подтверждение пароля не совпадают.
|
||||
captcha_incorrect=Капча не пройдена.
|
||||
password_not_match=Пароли не совпадают.
|
||||
|
||||
username_been_taken=Имя пользователя уже принято.
|
||||
repo_name_been_taken=Имя репозитория уже принято.
|
||||
org_name_been_taken=Название организации было уже принято.
|
||||
team_name_been_taken=Название команды было уже принято.
|
||||
username_been_taken=Имя пользователя занято.
|
||||
repo_name_been_taken=Имя репозитория занято.
|
||||
org_name_been_taken=Название организации занято.
|
||||
team_name_been_taken=Название команды занято.
|
||||
email_been_used=Адрес электронной почты уже используется.
|
||||
illegal_team_name=Имя группы содержит недопустимые знаки.
|
||||
username_password_incorrect=Имя пользователя или пароль не правильный.
|
||||
enterred_invalid_repo_name=Пожалуйста, убедитесь, что введенно правильное имя хранилища.
|
||||
enterred_invalid_repo_name=Пожалуйста, убедитесь, что введено правильное имя репозитория.
|
||||
enterred_invalid_owner_name=Убедитесь, что введенное имя владельца верное.
|
||||
enterred_invalid_password=Убедитесь, что введенный пароль верен.
|
||||
user_not_exist=Данный пользователь не существует.
|
||||
last_org_owner=Удаляемый пользователь является последним в команде владельцев. Должен быть хотя бы один владелец.
|
||||
last_org_owner=Удаление последнего пользователя из команды владельцев невозможно, поскольку всегда должен быть хотя бы один владелец в любой организации.
|
||||
|
||||
invalid_ssh_key=К сожалению, мы не смогли проверить ваш SSH-ключ: %s
|
||||
unable_verify_ssh_key=Gogs не может проверить ваш SSH-ключ, но мы допускаем, что он действителен. Пожалуйста, удостоверьтесь самостоятельно, что ключ действителен.
|
||||
@@ -218,19 +217,18 @@ still_own_repo=На вашем аккаунте все еще остается
|
||||
still_has_org=Вы находитесь в организации, сперва Вам необходимо покинуть ее или удалить.
|
||||
org_still_own_repo=Данная организация все еще является владельцем репозиториев, необходимо удалить или переместить их в начале.
|
||||
|
||||
still_own_user=Эта проверка подлинности по-прежнему используется некоторыми пользователями, вы должны переместить их и затем снова удалить.
|
||||
|
||||
target_branch_not_exist=Целевая ветка не существует
|
||||
|
||||
[user]
|
||||
change_avatar=Измените ваш аватар на gravatar.com
|
||||
change_custom_avatar=Измените ваш аватар в настройках
|
||||
join_on=Присоединилась к
|
||||
change_avatar=Изменить аватар
|
||||
join_on=Присоединился
|
||||
repositories=Репозитории
|
||||
activity=Активность
|
||||
followers=Подписчики
|
||||
starred=Избранное
|
||||
following=Подписан
|
||||
follow=Подписаться
|
||||
unfollow=Отписаться
|
||||
|
||||
form.name_reserved=Имя пользователя '%s' зарезервировано.
|
||||
form.name_pattern_not_allowed=Имя пользователя «%s» не допускается.
|
||||
@@ -247,6 +245,7 @@ uid=UID
|
||||
|
||||
public_profile=Открытый профиль
|
||||
profile_desc=Адрес вашей электронной почты является публичным и будет использован для любых уведомлений, связанных с аккаунтом, а также для любых действий, совершенных через сайт.
|
||||
password_username_disabled=Нелокальные пользователи не могут изменить своё имя.
|
||||
full_name=ФИО
|
||||
website=Веб-сайт
|
||||
location=Местоположение
|
||||
@@ -258,11 +257,10 @@ continue=Далее
|
||||
cancel=Отмена
|
||||
|
||||
enable_custom_avatar=Включить собственный аватар
|
||||
enable_custom_avatar_helper=Включите эту опцию, чтоб отключить загрузку с Gravatar
|
||||
choose_new_avatar=Выбрать новый аватар
|
||||
update_avatar=Обновить настройку аватара
|
||||
delete_current_avatar=Удалить текущий аватар
|
||||
uploaded_avatar_not_a_image=Загружаемый файл не является изображением.
|
||||
no_custom_avatar_available=Собственный аватар недоступен, включить его невозможно.
|
||||
update_avatar_success=Настройка вашего аватара обновлена успешно.
|
||||
|
||||
change_password=Сменить пароль
|
||||
@@ -271,6 +269,7 @@ new_password=Новый пароль
|
||||
retype_new_password=Подтверждение нового пароля
|
||||
password_incorrect=Текущий пароль не правильный.
|
||||
change_password_success=Пароль сменен успешно. Теперь вы можете войти с новым паролем.
|
||||
password_change_disabled=Нелокальные пользователи не могут изменить свой пароль.
|
||||
|
||||
emails=Адреса электронной почты
|
||||
manage_emails=Управление адресами электронной почты
|
||||
@@ -319,7 +318,7 @@ token_name=Имя маркера
|
||||
generate_token=Генерировать маркер
|
||||
generate_token_succees=Успешно создан новый токен доступа! Пожалуйста сделайте копию вашего нового токена персонального доступа. Вы не сможете увидеть его снова!
|
||||
delete_token=Удалить
|
||||
access_token_deletion=Удаление персонального токена доступа
|
||||
access_token_deletion=Удаление личного токена доступа
|
||||
access_token_deletion_desc=Удаление этого персонального токена доступа приведет к удалению всех связанных прав доступа к приложению. Вы хотите продолжить?
|
||||
delete_token_success=Персональный токен доступа успешно удален! Не забудьте изменить настройки вашего приложения.
|
||||
|
||||
@@ -336,7 +335,7 @@ repo_name_helper=Лучшие названия репозиториев коро
|
||||
visibility=Видимость
|
||||
visiblity_helper=<span class="ui red text">Личный</span> репозиторий
|
||||
visiblity_helper_forced=Все новые репозитории являются <span class="ui red text">Личными</span> по желанию администратора сайта
|
||||
visiblity_fork_helper=(Изменение этого значения затронет все форки)
|
||||
visiblity_fork_helper=(Изменение этого значения затронет все ответвления)
|
||||
clone_helper=Нужна помощь в клонировании? Посетите страницу <a target="_blank" href="%s">помощи</a>!
|
||||
fork_repo=Ответвить репозиторий
|
||||
fork_from=Ответвление от
|
||||
@@ -351,11 +350,16 @@ 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=Интервал зеркалирования (час)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=Адрес зеркала
|
||||
mirror_address_desc=Укажите необходимые учетные данные в адрес.
|
||||
watchers=Наблюдатели
|
||||
stargazers=Звездочеты
|
||||
forks=Ответвления
|
||||
|
||||
form.reach_limit_of_creation=У владельца достигнут максимальный предел в %d создаваемых репозиториев.
|
||||
form.name_reserved=Имя репозитория '%s' зарезервировано.
|
||||
form.name_pattern_not_allowed=Шаблон имени репозитория '%s' не допускается.
|
||||
|
||||
@@ -367,10 +371,11 @@ migrate.clone_address=Скопировать адрес
|
||||
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь на сервере.
|
||||
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
|
||||
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Миграция не удалась: %v
|
||||
|
||||
forked_from=форк от
|
||||
fork_from_self=Вы не можете форкнуть репозитарий, так как Вы уже его владелец!
|
||||
mirror_from=зеркало из
|
||||
forked_from=ответвлено от
|
||||
fork_from_self=Вы не можете ответвить репозиторий, так как Вы уже его владелец!
|
||||
copy_link=Скопировать
|
||||
copy_link_success=Скопировано!
|
||||
copy_link_error=Нажмите ⌘-C или Ctrl-C для копирования
|
||||
@@ -388,13 +393,14 @@ create_new_repo_command=Создать новый репозиторий из к
|
||||
push_exist_repo=Отправить существующий репозиторий из командной строки
|
||||
repo_is_empty=Этот репозиторий пуст, пожалуйста, возвращайтесь позже!
|
||||
|
||||
code=Код
|
||||
branch=Ветка
|
||||
tree=Дерево
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Фильтр по ветке или тегу
|
||||
branches=Ветки
|
||||
tags=Метки
|
||||
issues=Обсуждения
|
||||
pulls=Пулл реквесты
|
||||
pulls=Запросы на слияние
|
||||
labels=Метки
|
||||
milestones=Этапы
|
||||
commits=Коммиты
|
||||
@@ -415,7 +421,7 @@ commits.newer=Новее
|
||||
|
||||
issues.new=Новая задача
|
||||
issues.new.labels=Метки
|
||||
issues.new.no_label=Не метка
|
||||
issues.new.no_label=Нет меток
|
||||
issues.new.clear_labels=Отчистить метки
|
||||
issues.new.milestone=Этап
|
||||
issues.new.no_milestone=Нет этапа
|
||||
@@ -429,8 +435,8 @@ issues.create=Добавить задачу
|
||||
issues.new_label=Новая метка
|
||||
issues.new_label_placeholder=Имя метки...
|
||||
issues.create_label=Добавить метку
|
||||
issues.open_tab=%d Открыть
|
||||
issues.close_tab=%d Закрыть
|
||||
issues.open_tab=%d открыто(ы)
|
||||
issues.close_tab=%d закрыто(ы)
|
||||
issues.filter_label=Метка
|
||||
issues.filter_label_no_select=Нет выбранной метки
|
||||
issues.filter_milestone=Этап
|
||||
@@ -439,7 +445,7 @@ 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.assigned_to_you=Назначено вам
|
||||
issues.filter_type.created_by_you=Созданные вами
|
||||
issues.filter_type.mentioning_you=Вы упомянуты
|
||||
issues.filter_sort=Сортировать
|
||||
@@ -449,25 +455,25 @@ issues.filter_sort.recentupdate=Недавно обновленные
|
||||
issues.filter_sort.leastupdate=Давно обновленные
|
||||
issues.filter_sort.mostcomment=Большего комментариев
|
||||
issues.filter_sort.leastcomment=Меньше комментариев
|
||||
issues.opened_by=%[1] открыта <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by=%[1]s открыта <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=%[1]s открыта %[2]s
|
||||
issues.previous=Предыдущая страница
|
||||
issues.next=Следующая страница
|
||||
issues.open_title=Открыта
|
||||
issues.closed_title=Закрыта
|
||||
issues.open_title=Открыто
|
||||
issues.closed_title=Закрыто
|
||||
issues.num_comments=комментариев: %d
|
||||
issues.commented_at=` прокомментировал <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.no_content=Пока нет содержимого.
|
||||
issues.close_issue=Закрыть
|
||||
issues.close_comment_issue=Прокомментировать и закрыть
|
||||
issues.reopen_issue=Открыть снова
|
||||
issues.reopen_comment_issue=Прокомментировать и открыть
|
||||
issues.reopen_comment_issue=Прокомментировать и открыть снова
|
||||
issues.create_comment=Комментировать
|
||||
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.admin=Администратор
|
||||
issues.collaborator=Соавтор
|
||||
issues.owner=Владелец
|
||||
issues.sign_up_for_free=Зарегистрируйтесь бесплатно
|
||||
issues.sign_in_require_desc=чтобы присоединиться к обсуждению. Уже есть аккаунт? <a href="%s">Войдите чтобы прокомментировать</a>
|
||||
@@ -484,41 +490,42 @@ issues.label_modify=Изменение метки
|
||||
issues.label_deletion=Удаление метки
|
||||
issues.label_deletion_desc=Удаление ярлыка затронет все связанные задачи. Продолжить?
|
||||
issues.label_deletion_success=Метка была удалена успешно!
|
||||
issues.num_participants=%d участников
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Новый запрос на слияние
|
||||
pulls.compare_changes=Сравнить изменения
|
||||
pulls.compare_changes_desc=Сравнить две ветки и создать пулл реквест для изменений.
|
||||
pulls.compare_changes_desc=Сравнить две ветки и создать запрос на слияние для изменений.
|
||||
pulls.compare_base=родительская ветка
|
||||
pulls.compare_compare=сравнить
|
||||
pulls.filter_branch=Фильтр по ветке
|
||||
pulls.no_results=Результатов не найдено.
|
||||
pulls.nothing_to_compare=Нечего сравнивать, родительская и текущая ветка одинаковые.
|
||||
pulls.has_pull_request=`Уже существует пулл-реквест между двумя целями <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=Создать пулл-реквест
|
||||
pulls.has_pull_request=`Уже существует запрос на слияние между двумя целями: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=Создать запрос на слияние
|
||||
pulls.title_desc=хочет смерджить %[1]d коммит(ов) из <code>%[2]s</code> в <code>%[3]s</code>
|
||||
pulls.merged_title_desc=слито %[1]d коммит(ов) из <code>%[2]s</code> в <code>%[3]s</code> %[4]s
|
||||
pulls.tab_conversation=Обсуждение
|
||||
pulls.tab_commits=Коммиты
|
||||
pulls.tab_files=Измененные файлы
|
||||
pulls.reopen_to_merge=Пожалуйста пересоздайте пулл-реквест для слияния.
|
||||
pulls.reopen_to_merge=Пожалуйста снова откройте этот запрос для слияния.
|
||||
pulls.merged=Слито
|
||||
pulls.has_merged=Слияние этого пулл-реквеста успешно завершено!
|
||||
pulls.data_broken=Содержимое этого пулл-реквеста было нарушено, вследствии удаления или клонирования информации.
|
||||
pulls.has_merged=Слияние этого запроса успешно завершено!
|
||||
pulls.data_broken=Содержимое этого запроса было нарушено вследствие удаления информации ответвления.
|
||||
pulls.is_checking=Продолжается проверка конфликтов, пожалуйста обновите страницу несколько позже.
|
||||
pulls.can_auto_merge_desc=Вы можете провести операцию автоматического слияния для этого пулл-реквеста.
|
||||
pulls.cannot_auto_merge_desc=Вы не можете произвести операцию автоматического слияния, потому как существуют конфликты между коммитами.
|
||||
pulls.cannot_auto_merge_helper=Используйте командную строку для решения этого.
|
||||
pulls.can_auto_merge_desc=Этот запрос на слияние может быть объединён автоматически.
|
||||
pulls.cannot_auto_merge_desc=Этот запрос на слияние не может быть объединён автоматически.
|
||||
pulls.cannot_auto_merge_helper=Пожалуйста, совершите слияние вручную для урегулирования конфликтов.
|
||||
pulls.merge_pull_request=Слить пулл-реквест
|
||||
pulls.open_unmerged_pull_exists=`Вы не можете произвести операцию переоткрытия, потому что уже существует пулл-реквест (#%d) из этого же репозитория, с такими же параметрами слияния, который ожидает слияния.`
|
||||
pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния. `
|
||||
|
||||
milestones.new=Новая контрольная точка
|
||||
milestones.open_tab=%d открыты
|
||||
milestones.close_tab=%d Закрыт
|
||||
milestones.close_tab=%d закрыты
|
||||
milestones.closed=Закрыт %s
|
||||
milestones.no_due_date=Срок не указан
|
||||
milestones.open=Открыть
|
||||
milestones.close=Закрыть
|
||||
milestones.new_subheader=Создавайте контрольные точки для трекинга ваших вопросов.
|
||||
milestones.new_subheader=Создавайте этапы для организации ваших задач.
|
||||
milestones.create=Создать контрольную точку
|
||||
milestones.title=Заголовок
|
||||
milestones.desc=Описание
|
||||
@@ -532,32 +539,75 @@ milestones.cancel=Отмена
|
||||
milestones.modify=Изменить контрольную точку
|
||||
milestones.edit_success=Изменения контрольной точки '%s' успешно сохранены!
|
||||
milestones.deletion=Удаление контрольной точки
|
||||
milestones.deletion_desc=Удаление этой контрольной точки приведет с удалению всей информации, во всех вопросах (Issues). Вы действительно хотите продолжить?
|
||||
milestones.deletion_desc=Удаление этого этапа приведет к удалению связанной информации во всех связанных задачах. Вы хотите продолжить?
|
||||
milestones.deletion_success=Контрольная точка успешно удалена!
|
||||
|
||||
wiki=Вики
|
||||
wiki.welcome=Добро пожаловать в Вики!
|
||||
wiki.welcome_desc=Вики это место, где вы можете документировать проект вместе и сделать его лучше.
|
||||
wiki.create_first_page=Создать первую страницу
|
||||
wiki.page=Страница
|
||||
wiki.filter_page=Фильтр страницы
|
||||
wiki.new_page=Создать новую страницу
|
||||
wiki.default_commit_message=Написать заметку о данном обновлении (опционально).
|
||||
wiki.save_page=Сохранить страницу
|
||||
wiki.last_commit_info=%s редактировал эту страницу %s
|
||||
wiki.edit_page_button=Редактировать
|
||||
wiki.new_page_button=Новая страница
|
||||
wiki.delete_page_button=Удалить страницу
|
||||
wiki.delete_page_notice_1=Будьте внимательны! Это приведет к удалению страницы <code>«%s»</code>.
|
||||
wiki.page_already_exists=Вики-страница с таким именем уже существует.
|
||||
wiki.pages=Страницы
|
||||
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.danger_zone=Опасная зона
|
||||
settings.site=Официальный сайт
|
||||
settings.update_settings=Обновить настройки
|
||||
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
|
||||
settings.advanced_settings=Расширенные настройки
|
||||
settings.wiki_desc=Включить Вики, чтобы позволить людям писать документы
|
||||
settings.use_external_wiki=Использовать внешнюю Wiki
|
||||
settings.external_wiki_url=URL-адрес внешней Вики
|
||||
settings.external_wiki_url_desc=Посетители будут перенаправлены на URL-адрес, когда они кликнут по вкладке.
|
||||
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
|
||||
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
|
||||
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
|
||||
settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач:
|
||||
settings.tracker_issue_style.numeric=Числовой <span class="ui light grey text"> (1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Буквенно-цифровой <span class="ui light grey text"> (ABC-123, DEF-234,...)</span>
|
||||
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
|
||||
settings.pulls_desc=Включить публичные запросы на слияние
|
||||
settings.danger_zone=Опасная зона
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.convert=Преобразовать в обычный репозиторий
|
||||
settings.convert_desc=Это зеркало можно преобразовать в обычный репозиторий. Это не может быть отменено.
|
||||
settings.convert_notices_1=- Эта операция преобразует это зеркало в обычный репозиторий, и она не может быть отменена.
|
||||
settings.convert_confirm=Подтвердите преобразование
|
||||
settings.convert_succeed=Репозиторий был успешно преобразован в обычный.
|
||||
settings.transfer=Передать права собственности
|
||||
settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора.
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.delete=Удалить этот репозиторий
|
||||
settings.delete_desc=Как только вы удалите репозиторий — пути назад не будет. Удостоверьтесь, что вам это точно нужно.
|
||||
settings.transfer_notices_1=- Вы можете потерять доступ, если новый владелец является отдельным пользователем.
|
||||
settings.transfer_notices_2=- Вы сохраните доступ, если новым владельцем станет организация, владельцем которой вы являетесь.
|
||||
settings.transfer_form_title=Введите сопутствующую информацию для подтверждения операции:
|
||||
settings.wiki_delete=Стереть данные Вики
|
||||
settings.wiki_delete_desc=Будьте внимательны! Как только вы удалите Вики — пути назад не будет.
|
||||
settings.wiki_delete_notices_1=-Это будет удалено и отключит Вики для %s
|
||||
settings.wiki_deletion_success=Данные Вики успешно стерты.
|
||||
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_2=- Эта операция навсегда удалит всё из этого репозитория, включая данные Git, связанные с ним задачи, комментарии и права доступа для сотрудников.
|
||||
settings.delete_notices_fork_1=- Все отвлетвления станут независимыми после удаления.
|
||||
settings.deletion_success=Репозиторий был успешно удалён!
|
||||
settings.update_settings_success=Настройка репозитория обновлена успешно.
|
||||
settings.transfer_owner=Новый владелец
|
||||
settings.make_transfer=Выполнить передачу
|
||||
@@ -565,14 +615,21 @@ settings.transfer_succeed=Владение репозиторием было у
|
||||
settings.confirm_delete=Подтвердить удаление
|
||||
settings.add_collaborator=Добавить нового соавтора
|
||||
settings.add_collaborator_success=Был добавлен новый соавтор.
|
||||
settings.delete_collaborator=Удалить
|
||||
settings.collaborator_deletion=Удаление соавтора
|
||||
settings.collaborator_deletion_desc=Этот пользователь больше не будет иметь доступа для совместной работы в этом репозитории после удаления. Вы хотите продолжить?
|
||||
settings.remove_collaborator_success=Соавтор был удален.
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.search_user_placeholder=Поиск пользователя...
|
||||
settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
|
||||
settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора.
|
||||
settings.add_webhook=Добавить Webhook
|
||||
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gogs. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
|
||||
settings.webhook_deletion=Удалить веб-хук
|
||||
settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей, связанной с ним, информации, включая историю. Хотите продолжить?
|
||||
settings.webhook_deletion_success=Веб-хук успешно удален!
|
||||
settings.webhook.test_delivery=Проверить доставку
|
||||
settings.webhook.test_delivery_desc=Отправить push для тестирования настройки веб-хуков
|
||||
settings.webhook.test_delivery_success=Тест веб-хука была добавлен в очередь доставки. Это может занять несколько секунд, прежде чем он отобразится в истории доставки.
|
||||
settings.webhook.request=Запрос
|
||||
settings.webhook.response=Ответ
|
||||
settings.webhook.headers=Заголовки
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=Домен
|
||||
settings.slack_channel=Канал
|
||||
settings.deploy_keys=Ключи развертывания
|
||||
settings.add_deploy_key=Добавить ключ развертывания
|
||||
settings.deploy_key_desc=Ключи развёртывания доступны только для чтения. Это не то же самое что и SSH-ключи аккаунта.
|
||||
settings.no_deploy_keys=Вы не добавляли ключи развертывания.
|
||||
settings.title=Заголовок
|
||||
settings.deploy_key_content=Содержимое
|
||||
@@ -625,42 +683,46 @@ settings.deploy_key_deletion_success=Ключ развертывания усп
|
||||
diff.browse_source=Просмотр исходного кода
|
||||
diff.parent=Родитель
|
||||
diff.commit=Сommit
|
||||
diff.data_not_available=Данные Diff не доступны.
|
||||
diff.data_not_available=Данные Diff недоступны.
|
||||
diff.show_diff_stats=Показать статистику Diff
|
||||
diff.show_split_view=Разделённый вид
|
||||
diff.show_unified_view=Единый вид
|
||||
diff.stats_desc=<strong> %d измененных файлов</strong> с <strong>%d добавлено</strong> и <strong>%d удалено</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Просмотреть файл
|
||||
diff.file_supressed=Разница между файлами не показана из-за своего большого размера
|
||||
diff.too_many_files=Некоторые файлы не были показать из-за большого количества измененных файлов
|
||||
|
||||
release.releases=Релизы
|
||||
release.new_release=Новый релиз
|
||||
release.draft=Черновик
|
||||
release.prerelease=Предрелиз
|
||||
release.prerelease=Пре-релиз
|
||||
release.stable=Стабильный
|
||||
release.edit=Редактировать
|
||||
release.ahead=<strong>%d</strong> коммитов %s начиная с этого релиза
|
||||
release.source_code=Исходный код
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=Публикуйте релизы для итерации продукта.
|
||||
release.edit_subheader=Подробный журнал изменений может помочь пользователям понять, что было улучшено.
|
||||
release.tag_name=Имя тега
|
||||
release.target=Цель
|
||||
release.tag_helper=Выберите существующий тег, или создайте новый.
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=Заголовок
|
||||
release.content=Содержимое
|
||||
release.write=Запись
|
||||
release.preview=Предварительный просмотр
|
||||
release.loading=Загрузка...
|
||||
release.prerelease_desc=Это предварительный релиз
|
||||
release.prerelease_helper=Отдельно отметим, что этот релиз не готов к использованию в продакшене.
|
||||
release.cancel=Cancel
|
||||
release.cancel=Отменить
|
||||
release.publish=Опубликовать релиз
|
||||
release.save_draft=Сохранить черновик
|
||||
release.edit_release=Редактировать релиз
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.tag_name_already_exist=Релиз с этим именем тега уже существует.
|
||||
release.downloads=Downloads
|
||||
release.delete_release=Удалить этот релиз
|
||||
release.deletion=Удаление релиза
|
||||
release.deletion_desc=Удаление этого релиза удалит соответствующую Git метку. Вы хотите продолжить?
|
||||
release.deletion_success=Релиз был успешно удален!
|
||||
release.tag_name_already_exist=Релиз с этим именем метки уже существует.
|
||||
release.downloads=Загрузки
|
||||
|
||||
[org]
|
||||
org_name_holder=Название организации
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=Удаление Организации
|
||||
settings.delete_org_desc=Эта организация будет удалена навсегда. Хотите всё-равно продолжить?
|
||||
settings.hooks_desc=Добавьте автоматическое обновление, который будет вызываться для <strong>всех репозиций</strong> под этой Группой.
|
||||
|
||||
members.membership_visibility=Видимость участника команды:
|
||||
members.public=Публичный
|
||||
members.public_helper=Сделать Приватным
|
||||
members.private=Приватный
|
||||
members.private_helper=Сделать Публичным
|
||||
members.member_role=Роль участника:
|
||||
members.owner=Владелец
|
||||
members.member=Участник
|
||||
members.conceal=Скрыть
|
||||
members.remove=Удалить
|
||||
members.leave=Покинуть
|
||||
members.invite_desc=Начните вводить имя пользователя чтобы пригласить нового члена %s:
|
||||
members.invite_desc=Добавить нового участника в %s:
|
||||
members.invite_now=Пригласите сейчас
|
||||
|
||||
teams.join=Объединить
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=Эта команда предоставляет до
|
||||
teams.write_permission_desc=Эта команда предоставляет доступ на <strong>Запись</strong>: члены могут получать и выполнять push команды в репозитории.
|
||||
teams.admin_permission_desc=Эта команда дает <strong>административный</strong> доступ: участники могут читать, пушить и добавлять соавторов к ее репозиториям.
|
||||
teams.repositories=Репозитории группы разработки
|
||||
teams.search_repo_placeholder=Поиск репозитория...
|
||||
teams.add_team_repository=Добавить репозиторий группы разработки
|
||||
teams.remove_repo=Удалить
|
||||
teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте.
|
||||
@@ -755,7 +819,7 @@ total=Всего: %d
|
||||
dashboard.statistic=Статистика
|
||||
dashboard.operations=Операции
|
||||
dashboard.system_status=Статус системного монитора
|
||||
dashboard.statistic_info=В базе данных Gogs записано <b>%d</b> пользователей, <b>%d</b> организаций, <b>%d</b> публичных ключей, <b>%d</b> репозиторий, <b>%d</b> подписок на репозитории, <b>%d</b> добавлений в избранное, <b>%d</b> действий, <b>%d</b> доступов, <b>%d</b> обсуждений, <b>%d</b> комментариев, <b>%d</b> социальных учетных записей, <b>%d</b> подписок на пользователей, <b>%d</b> зеркал, <b>%d</b> релизов, <b>%d</b> источников входа, <b>%d</b> веб-хуков, <b>%d</b> вех, <b>%d</b> меток, <b>%d</b> задач хуков, <b>%d</b> команд, <b>%d</b> задач по обновлению, <b>%d</b> присоединенных файлов.
|
||||
dashboard.statistic_info=В базе данных Gogs записано <b>%d</b> пользователей, <b>%d</b> организаций, <b>%d</b> публичных ключей, <b>%d</b> репозиториев, <b>%d</b> подписок на репозитории, <b>%d</b> добавлений в избранное, <b>%d</b> действий, <b>%d</b> доступов, <b>%d</b> задач, <b>%d</b> комментариев, <b>%d</b> социальных учетных записей, <b>%d</b> подписок на пользователей, <b>%d</b> зеркал, <b>%d</b> релизов, <b>%d</b> источников входа, <b>%d</b> веб-хуков, <b>%d</b> этапов, <b>%d</b> меток, <b>%d</b> задач хуков, <b>%d</b> команд, <b>%d</b> задач по обновлению, <b>%d</b> присоединенных файлов.
|
||||
dashboard.operation_name=Наименование Операции
|
||||
dashboard.operation_switch=Переключить
|
||||
dashboard.operation_run=Запуск
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=Удалить все неактивиро
|
||||
dashboard.delete_inactivate_accounts_success=Все неактивированные учетные записи удалены успешно.
|
||||
dashboard.delete_repo_archives=Удаление всех архивов репозиториев
|
||||
dashboard.delete_repo_archives_success=Все архивы репозиториев были успешно удалены.
|
||||
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=Удаление всех записей о репозитории с отсутствующими файлами Git
|
||||
dashboard.delete_missing_repos_success=Все репозитории с отсутствующими Git файлами успешно удалены.
|
||||
dashboard.git_gc_repos=Выполнить сборку мусора на репозиториях
|
||||
dashboard.git_gc_repos_success=Сборка мусора на всех репозиториях успешно выполнена.
|
||||
dashboard.resync_all_sshkeys=Переписать файл «.ssh/authorized_keys» (осторожно: не Gogs ключи будут утеряны)
|
||||
dashboard.resync_all_sshkeys_success=Были успешно переписаны все открытые ключи.
|
||||
dashboard.resync_all_update_hooks=Перезаписать все апдейт-хуки этого репозитория (необходимо, когда изменен путь до папки конфигураций)
|
||||
dashboard.resync_all_update_hooks_success=Апдейт-хуки всех репозиториев успешно перезаписаны.
|
||||
dashboard.reinit_missing_repos=Реинициализировать все репозитории с утерянными Git файлами
|
||||
dashboard.reinit_missing_repos_success=Все репозитории с утерянными Git файлами успешно реинициализированы.
|
||||
|
||||
dashboard.server_uptime=Время непрерывной работы сервера
|
||||
dashboard.current_goroutine=Текущий Goroutines
|
||||
@@ -820,6 +886,8 @@ users.auth_login_name=Логин для авторизации
|
||||
users.password_helper=Оставьте пустым, чтобы оставить без изменений.
|
||||
users.update_profile_success=Профиль учетной записи обновлен успешно.
|
||||
users.edit_account=Изменение учетной записи
|
||||
users.max_repo_creation=Ограничение максимального количества создаваемых репозиториев
|
||||
users.max_repo_creation_desc=(Установить -1 для использования стандартного глобального значения предела)
|
||||
users.is_activated=Эта учетная запись активирована
|
||||
users.is_admin=У этой учетной записи есть права администратора
|
||||
users.allow_git_hook=Пользователь имеет право создать Git перехватчик
|
||||
@@ -841,7 +909,7 @@ repos.name=Имя
|
||||
repos.private=Приватный
|
||||
repos.watches=Следят
|
||||
repos.stars=В избранном
|
||||
repos.issues=Вопросы
|
||||
repos.issues=Задачи
|
||||
|
||||
auths.auth_manage_panel=Панель управления аутнентификациями
|
||||
auths.new=Добавить новый источник
|
||||
@@ -851,6 +919,7 @@ auths.enabled=Включено
|
||||
auths.updated=Обновлено
|
||||
auths.auth_type=Тип аутентификации
|
||||
auths.auth_name=Имя аутентификации
|
||||
auths.security_protocol=Протокол безопасности
|
||||
auths.domain=Домен
|
||||
auths.host=Хост
|
||||
auths.port=Порт
|
||||
@@ -859,9 +928,12 @@ auths.bind_password=Привязать пароль
|
||||
auths.bind_password_helper=Внимание: Этот пароль сохранен в небезопасном виде. Не используйте высоко-привилегированную учетную запись.
|
||||
auths.user_base=База для поиска пользователя
|
||||
auths.user_dn=DN пользователя
|
||||
auths.attribute_username=Атрибут username
|
||||
auths.attribute_username_placeholder=Оставьте пустым, чтобы использовать имя пользователя для регистрации.
|
||||
auths.attribute_name=Имя аттрибута
|
||||
auths.attribute_surname=Фамилия аттрибута
|
||||
auths.attribute_mail=Электронная почта аттрибута
|
||||
auths.attributes_in_bind=Извлечение атрибутов в виде Bind DN
|
||||
auths.filter=Фильтр пользователя
|
||||
auths.admin_filter=Фильтр администратора
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -883,6 +955,7 @@ auths.update=Обновить параметры аутентификации
|
||||
auths.delete=Удалить этот канал аутентификации
|
||||
auths.delete_auth_title=Удаление канала аутентификации
|
||||
auths.delete_auth_desc=Этот канал аутентификации будет удален. Вы уверены что хотите продолжить?
|
||||
auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему.
|
||||
auths.deletion_success=Канал аутентификации успешно удален!
|
||||
|
||||
config.server_config=Конфигурация сервера
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=Статичный путь до файла
|
||||
config.log_file_root_path=Путь до папки с логами
|
||||
config.script_type=Тип сценария
|
||||
config.reverse_auth_user=Заголовок с именем пользователя для авторизации на reverse proxy
|
||||
|
||||
config.ssh_config=Конфигурация SSH
|
||||
config.ssh_enabled=Включено
|
||||
config.ssh_start_builtin_server=Запустить встроенный сервер
|
||||
config.ssh_domain=Домен
|
||||
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=Тип
|
||||
config.db_host=Хост
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=Требуется подтверждение по
|
||||
config.disable_register=Отключить регистрацию
|
||||
config.show_registration_button=Показать кнопку регистрации
|
||||
config.require_sign_in_view=Для просмотра необходима авторизация
|
||||
config.enable_cache_avatar=Кешировать аватар
|
||||
config.mail_notify=Почтовые уведомления
|
||||
config.disable_key_size_check=Отключить проверку на минимальный размер ключа
|
||||
config.enable_captcha=Включить капчу
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=Отключить HELO
|
||||
config.mailer_name=Имя
|
||||
config.mailer_host=Сервер
|
||||
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=Настройки кеша
|
||||
@@ -962,6 +1050,13 @@ monitor.start=Момент начала
|
||||
monitor.execute_time=Время выполнения
|
||||
|
||||
notices.system_notice_list=Система уведомлений
|
||||
notices.view_detail_header=Подробности уведомления
|
||||
notices.actions=Действия
|
||||
notices.select_all=Выбрать всё
|
||||
notices.deselect_all=Убрать выделение со всего
|
||||
notices.inverse_selection=Инверсия выделения
|
||||
notices.delete_selected=Удалить выбранные
|
||||
notices.delete_all=Удалить все уведомления
|
||||
notices.type=Тип
|
||||
notices.type_1=Репозиторий
|
||||
notices.desc=Описание
|
||||
@@ -969,16 +1064,20 @@ 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>
|
||||
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]</a>`
|
||||
create_pull_request=`созданный пулл-реквест <a href="%s/pulls/%s">%s#%[2]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/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>`
|
||||
reopen_issue=`возобновил(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`создал запрос на слияние <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
close_pull_request=`закрыл запрос на слияние <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
reopen_pull_request=`открыл снова запрос на слияние <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`прокомментировал(а) вопрос <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`слил пул реквест <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=перенес репозиторий <code>%s</code> в <a href="%s">%s</a>
|
||||
push_tag=запушил тэг <a href="%s/src/%s">%[2]s</a> в <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Просмотреть сравнение двух коммитов
|
||||
push_tag=запушил(а) метку <a href="%s/src/%s">%[2]s</a> в <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=Просмотр сравнение для этих %d коммитов
|
||||
|
||||
[tool]
|
||||
ago=назад
|
||||
@@ -991,13 +1090,13 @@ now=сейчас
|
||||
1w=1 неделя %s
|
||||
1mon=1 месяц %s
|
||||
1y=1 год %s
|
||||
seconds=%d секунд %s
|
||||
minutes=%d минут %s
|
||||
seconds=секунд %[2]s: %[1]d
|
||||
minutes=минут %[2]s: %[1]d
|
||||
hours=%d часов %s
|
||||
days=%d дней %s
|
||||
weeks=недель %s: %d
|
||||
months=месяцев %s: %d
|
||||
years=лет %s: %d
|
||||
days=дней %[2]s: %[1]d
|
||||
weeks=недель %[2]s: %[1]d
|
||||
months=месяцев %[2]s: %[1]d
|
||||
years=лет %[2]s: %[1]d
|
||||
raw_seconds=секунд
|
||||
raw_minutes=минут
|
||||
|
||||
|
||||
1108
conf/locale/locale_tr-TR.ini
Normal file
1108
conf/locale/locale_tr-TR.ini
Normal file
File diff suppressed because it is too large
Load Diff
163
conf/locale/locale_zh-CN.ini
Executable file → Normal file
163
conf/locale/locale_zh-CN.ini
Executable file → Normal file
@@ -28,6 +28,7 @@ organization=组织
|
||||
mirror=镜像
|
||||
new_repo=创建新的仓库
|
||||
new_migrate=迁移外部仓库
|
||||
new_mirror=创建新的镜像
|
||||
new_fork=创建新的派生仓库
|
||||
new_org=创建新的组织
|
||||
manage_org=管理我的组织
|
||||
@@ -37,19 +38,12 @@ settings=帐户设置
|
||||
your_profile=个人信息
|
||||
your_settings=用户设置
|
||||
|
||||
news_feed=最新活动
|
||||
activities=最近活动
|
||||
pull_requests=合并请求
|
||||
issues=工单管理
|
||||
|
||||
cancel=取消
|
||||
|
||||
[search]
|
||||
search=搜索...
|
||||
repository=仓库
|
||||
user=用户
|
||||
issue=工单
|
||||
code=代码
|
||||
|
||||
[install]
|
||||
install=安装页面
|
||||
title=首次运行安装程序
|
||||
@@ -64,7 +58,7 @@ db_name=数据库名称
|
||||
db_helper=如果您使用 MySQL,请使用 INNODB 引擎以及 utf8_general_ci 字符集。
|
||||
ssl_mode=SSL 模式
|
||||
path=数据库文件路径
|
||||
sqlite_helper=SQLite3 或 TiDB 的数据库路径。
|
||||
sqlite_helper=SQLite3 或 TiDB 数据库文件路径。<br>作为服务启动时,请使用绝对路径。
|
||||
err_empty_db_path=SQLite3 或 TiDB 的数据库路径不能为空。
|
||||
err_invalid_tidb_name=TiDB 数据库名称不允许包含字符 "." 或 "-" 。
|
||||
no_admin_and_disable_registration=您不能够在未创建管理员用户的情况下禁止注册。
|
||||
@@ -85,6 +79,8 @@ http_port=HTTP 端口号
|
||||
http_port_helper=应用监听的端口号
|
||||
app_url=应用 URL
|
||||
app_url_helper=该设置影响 HTTP/HTTPS 克隆地址和一些邮箱中的链接。
|
||||
log_root_path=日志路径
|
||||
log_root_path_helper=存放日志文件的目录
|
||||
|
||||
optional_title=可选设置
|
||||
email_title=邮件服务设置
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=运行系统用户非当前用户:%s -> %s
|
||||
save_config_failed=应用配置保存失败:%v
|
||||
invalid_admin_setting=管理员帐户设置不正确:%v
|
||||
install_success=您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG!
|
||||
invalid_log_root_path=无效的日志路径:%v
|
||||
|
||||
[home]
|
||||
uname_holder=用户名或邮箱
|
||||
@@ -135,7 +132,9 @@ view_home=访问 %s
|
||||
issues.in_your_repos=属于该用户仓库的
|
||||
|
||||
[explore]
|
||||
repos=探索仓库
|
||||
repos=仓库
|
||||
users=用户
|
||||
search=搜索
|
||||
|
||||
[auth]
|
||||
create_new_account=创建帐户
|
||||
@@ -158,6 +157,7 @@ reset_password=重置密码
|
||||
invalid_code=对不起,您的确认代码已过期或已失效。
|
||||
reset_password_helper=单击此处重置密码
|
||||
password_too_short=密码长度不能少于 6 位!
|
||||
non_local_account=非本地类型的帐户无法通过 Gogs 修改密码。
|
||||
|
||||
[mail]
|
||||
activate_account=请激活您的帐户
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=仓库名称已经被占用。
|
||||
org_name_been_taken=组织名称已经被占用。
|
||||
team_name_been_taken=团队名称已经被占用。
|
||||
email_been_used=邮箱地址已经被使用。
|
||||
illegal_team_name=团队名称包含非法字符。
|
||||
username_password_incorrect=用户名或密码不正确。
|
||||
enterred_invalid_repo_name=请检查您输入的仓库名称是正确。
|
||||
enterred_invalid_owner_name=请检查您输入的新所有者用户名是否正确。
|
||||
@@ -218,19 +217,18 @@ still_own_repo=您的帐户仍然是某些仓库的拥有者,您必须先转
|
||||
still_has_org=您的帐户仍旧是某些组织的成员,您必须先离开或删除组织。
|
||||
org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除组织操作!
|
||||
|
||||
still_own_user=该授权认证依旧被部分用户使用,请先删除该部分用户后再试!
|
||||
|
||||
target_branch_not_exist=目标分支不存在。
|
||||
|
||||
[user]
|
||||
change_avatar=到 gravatar.com 上修改您的头像
|
||||
change_custom_avatar=到个人设置中修改头像
|
||||
change_avatar=修改头像
|
||||
join_on=加入于
|
||||
repositories=仓库列表
|
||||
activity=公开活动
|
||||
followers=关注者
|
||||
starred=已点赞
|
||||
following=关注中
|
||||
follow=关注
|
||||
unfollow=取消关注
|
||||
|
||||
form.name_reserved=用户名 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
|
||||
@@ -247,6 +245,7 @@ uid=用户 ID
|
||||
|
||||
public_profile=公开信息
|
||||
profile_desc=您的邮箱地址将会被公开,并被用于接收帐户的所有提醒和通知。
|
||||
password_username_disabled=非本地类型的用户被禁止修改用户名。
|
||||
full_name=自定义名称
|
||||
website=个人网站
|
||||
location=所在地区
|
||||
@@ -258,11 +257,10 @@ continue=继续操作
|
||||
cancel=取消操作
|
||||
|
||||
enable_custom_avatar=启动自定义头像
|
||||
enable_custom_avatar_helper=激活该选项来禁止从 Gravatar 获取头像
|
||||
choose_new_avatar=选择新的头像
|
||||
update_avatar=更新头像设置
|
||||
delete_current_avatar=删除当前头像
|
||||
uploaded_avatar_not_a_image=上传的文件不是一张图片!
|
||||
no_custom_avatar_available=未上传过自定义头像,无法激活该选项。
|
||||
update_avatar_success=您的头像设置更新成功!
|
||||
|
||||
change_password=修改密码
|
||||
@@ -271,6 +269,7 @@ new_password=新的密码
|
||||
retype_new_password=重新输入新的密码
|
||||
password_incorrect=当前密码不正确!
|
||||
change_password_success=密码修改成功!您现在可以使用新的密码登录。
|
||||
password_change_disabled=非本地类型的用户被禁止修改密码。
|
||||
|
||||
emails=邮箱地址
|
||||
manage_emails=管理邮箱地址
|
||||
@@ -351,11 +350,16 @@ readme_helper=请选择自述文档模板
|
||||
auto_init=使用选定的文件和模板初始化仓库
|
||||
create_repo=创建仓库
|
||||
default_branch=默认分支
|
||||
mirror_prune=修剪
|
||||
mirror_prune_desc=当远程追踪的引用被删除时本地也同步删除
|
||||
mirror_interval=镜像同步周期(小时)
|
||||
mirror_address=镜像地址
|
||||
mirror_address_desc=请在镜像地址中写入必要的用户凭据信息。
|
||||
watchers=关注者
|
||||
stargazers=称赞者
|
||||
forks=派生仓库
|
||||
|
||||
form.reach_limit_of_creation=该用户已经达到允许创建 %d 个仓库的最大上限。
|
||||
form.name_reserved=仓库名称 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=仓库名称不允许 '%s' 的格式。
|
||||
|
||||
@@ -369,6 +373,7 @@ migrate.permission_denied=您没有获得导入本地仓库的权限。
|
||||
migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录!
|
||||
migrate.failed=迁移失败:%v
|
||||
|
||||
mirror_from=镜像自地址
|
||||
forked_from=派生自
|
||||
fork_from_self=无法派生已经拥有的仓库!
|
||||
copy_link=复制链接
|
||||
@@ -388,6 +393,7 @@ create_new_repo_command=从命令行创建一个新的仓库
|
||||
push_exist_repo=从命令行推送已经创建的仓库
|
||||
repo_is_empty=该仓库不包含任何内容,请稍后再进行访问!
|
||||
|
||||
code=代码
|
||||
branch=分支
|
||||
tree=目录树
|
||||
filter_branch_and_tag=过滤分支或标签
|
||||
@@ -467,7 +473,7 @@ issues.closed_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 关闭`
|
||||
issues.reopened_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 重新开启`
|
||||
issues.commit_ref_at=`在代码提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中引用了该工单`
|
||||
issues.poster=发布者
|
||||
issues.admin=管理员
|
||||
issues.collaborator=协作者
|
||||
issues.owner=所有者
|
||||
issues.sign_up_for_free=免费注册
|
||||
issues.sign_in_require_desc=并加入到对话中来。如果您已经注册,可以直接 <a href="%s">登录并评论</a>
|
||||
@@ -484,6 +490,7 @@ issues.label_modify=修改标签
|
||||
issues.label_deletion=删除标签操作
|
||||
issues.label_deletion_desc=删除该标签将会移除所有工单中相关的信息。是否继续?
|
||||
issues.label_deletion_success=标签删除成功!
|
||||
issues.num_participants=%d 名参与者
|
||||
|
||||
pulls.new=创建合并请求
|
||||
pulls.compare_changes=对比文件变化
|
||||
@@ -505,9 +512,9 @@ pulls.merged=已合并
|
||||
pulls.has_merged=该合并请求已经成功合并!
|
||||
pulls.data_broken=该合并请求的数据由于派生仓库的相关信息被删除而被破坏。
|
||||
pulls.is_checking=该合并请求正在进行冲突检查,请稍后再刷新页面。
|
||||
pulls.can_auto_merge_desc=您可以实现该合并请求的自动合并操作。
|
||||
pulls.cannot_auto_merge_desc=因为代码提交存在冲突,您无法对该合并请求执行自动合并操作。
|
||||
pulls.cannot_auto_merge_helper=请使用命令行工具来解决冲突。
|
||||
pulls.can_auto_merge_desc=该合并请求可以进行自动合并操作。
|
||||
pulls.cannot_auto_merge_desc=该合并请求存在冲突,无法进行自动合并操作。
|
||||
pulls.cannot_auto_merge_helper=请手动拉取代码变更以解决冲突。
|
||||
pulls.merge_pull_request=合并请求
|
||||
pulls.open_unmerged_pull_exists=`由于已经存在来自相同仓库和合并信息的未合并请求(#%d),您无法执行重新开启操作。`
|
||||
|
||||
@@ -535,29 +542,72 @@ milestones.deletion=删除里程碑操作
|
||||
milestones.deletion_desc=删除该里程碑将会移除所有工单中相关的信息。是否继续?
|
||||
milestones.deletion_success=里程碑删除成功!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=欢迎使用 Wiki!
|
||||
wiki.welcome_desc=Wiki 是用于共同协作文档的地方,清晰的文档可以帮助其他人深入了解您的项目。
|
||||
wiki.create_first_page=创建第一个页面
|
||||
wiki.page=页面
|
||||
wiki.filter_page=过滤页面
|
||||
wiki.new_page=创建新的页面
|
||||
wiki.default_commit_message=关于此次修改的说明(可选)。
|
||||
wiki.save_page=保存页面
|
||||
wiki.last_commit_info=%s 于 %s 修改了此页面
|
||||
wiki.edit_page_button=修改
|
||||
wiki.new_page_button=新的页面
|
||||
wiki.delete_page_button=删除页面
|
||||
wiki.delete_page_notice_1=此操作将删除页面 <code>"%s"</code>,请三思而后行。
|
||||
wiki.page_already_exists=相同名称的 Wiki 页面已经存在。
|
||||
wiki.pages=所有页面
|
||||
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.danger_zone=危险操作区
|
||||
settings.site=官方网站
|
||||
settings.update_settings=更新仓库设置
|
||||
settings.change_reponame_prompt=该操作将会影响到所有与该仓库有关的链接
|
||||
settings.advanced_settings=高级设置
|
||||
settings.wiki_desc=启用 Wiki 以允许用户协作文档
|
||||
settings.use_external_wiki=使用外部 Wiki
|
||||
settings.external_wiki_url=外部 Wiki 链接
|
||||
settings.external_wiki_url_desc=当访问者单击分页标签时,将会被重定向到该链接。
|
||||
settings.issues_desc=启用内置的轻量级工单管理系统
|
||||
settings.use_external_issue_tracker=使用外部的工单管理系统
|
||||
settings.tracker_url_format=外部工单管理系统的 URL 格式
|
||||
settings.tracker_issue_style=外部工单管理系统命名风格:
|
||||
settings.tracker_issue_style.numeric=纯数字 <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=字母和数字结合 <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
|
||||
settings.pulls_desc=启用合并请求以接受社区贡献
|
||||
settings.danger_zone=危险操作区
|
||||
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
|
||||
settings.convert=转换为普通仓库
|
||||
settings.convert_desc=您可以将该镜像仓库转换为普通仓库,且此操作不可逆。
|
||||
settings.convert_notices_1=- 该操作会将该镜像仓库转换为普通仓库,且操作不可逆。
|
||||
settings.convert_confirm=确认转换
|
||||
settings.convert_succeed=转换为普通仓库类型成功!
|
||||
settings.transfer=转移仓库所有权
|
||||
settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐户或组织。
|
||||
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
|
||||
settings.delete=删除本仓库
|
||||
settings.delete_desc=删除仓库操作不可逆转,请三思而后行。
|
||||
settings.transfer_notices_1=- 如果您将仓库转移给个人用户,您将会丢失操作权限。
|
||||
settings.transfer_notices_2=- 如果您将仓库转移给您是所有者的组织,您的操作权限将被保留。
|
||||
settings.transfer_form_title=请输入以下信息以确认您的操作:
|
||||
settings.wiki_delete=清除 Wiki 数据
|
||||
settings.wiki_delete_desc=清除 Wiki 数据操作不可逆转,请三思而后行。
|
||||
settings.wiki_delete_notices_1=- 此操作将会清除并禁用仓库 %s 的 Wiki
|
||||
settings.wiki_deletion_success=仓库 Wiki 数据清除成功!
|
||||
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=新拥有者
|
||||
settings.make_transfer=确认转移仓库
|
||||
@@ -565,14 +615,21 @@ settings.transfer_succeed=仓库所有权转移成功!
|
||||
settings.confirm_delete=确认删除仓库
|
||||
settings.add_collaborator=增加新的协作者
|
||||
settings.add_collaborator_success=成功添加新的协作者!
|
||||
settings.delete_collaborator=删除
|
||||
settings.collaborator_deletion=删除协作者
|
||||
settings.collaborator_deletion_desc=此用户被删除后将不再拥有相关的协作权限。是否继续?
|
||||
settings.remove_collaborator_success=被操作的协作者已经被收回权限!
|
||||
settings.search_user_placeholder=搜索用户...
|
||||
settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者!
|
||||
settings.user_is_org_member=被操作的用户是组织成员,因此无法添加为协作者!
|
||||
settings.add_webhook=添加 Web 钩子
|
||||
settings.hooks_desc=Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文档</a> 获取更多信息。
|
||||
settings.webhook_deletion=删除 Web 钩子
|
||||
settings.webhook_deletion_desc=删除该 Web 钩子将会删除与其有关的信息和推送历史。是否继续?
|
||||
settings.webhook_deletion_success=Web 钩子删除成功!
|
||||
settings.webhook.test_delivery=测试推送
|
||||
settings.webhook.test_delivery_desc=生成并推送一个模拟的 Push 事件
|
||||
settings.webhook.test_delivery_success=测试推送已经加入到队列,请耐心等待数秒再刷新推送记录。
|
||||
settings.webhook.request=请求内容
|
||||
settings.webhook.response=响应内容
|
||||
settings.webhook.headers=头信息
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=域名
|
||||
settings.slack_channel=频道
|
||||
settings.deploy_keys=管理部署密钥
|
||||
settings.add_deploy_key=添加部署密钥
|
||||
settings.deploy_key_desc=部署密钥仅具有只读权限,它在功能上和个人用户的公开密钥有本质区别。
|
||||
settings.no_deploy_keys=您还没有添加任何部署密钥。
|
||||
settings.title=标题
|
||||
settings.deploy_key_content=密钥文本
|
||||
@@ -627,9 +685,13 @@ diff.parent=父节点
|
||||
diff.commit=当前提交
|
||||
diff.data_not_available=暂无可用数据
|
||||
diff.show_diff_stats=显示文件统计
|
||||
diff.show_split_view=分列视图
|
||||
diff.show_unified_view=合并视图
|
||||
diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
|
||||
diff.bin=二进制
|
||||
diff.view_file=查看文件
|
||||
diff.file_supressed=文件差异内容过多而无法显示
|
||||
diff.too_many_files=部分文件因为文件数量过多而无法显示
|
||||
|
||||
release.releases=版本发布
|
||||
release.new_release=发布新版
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=组织删除操作
|
||||
settings.delete_org_desc=该组织将被永久性删除,您确定要继续操作吗?
|
||||
settings.hooks_desc=在此处添加的 Web 钩子将会应用到该组织下的 <strong>所有仓库</strong>。
|
||||
|
||||
members.membership_visibility=成员可见性:
|
||||
members.public=公开成员
|
||||
members.public_helper=设为私有
|
||||
members.private=私有成员
|
||||
members.private_helper=设为公开
|
||||
members.member_role=成员角色:
|
||||
members.owner=管理员
|
||||
members.member=普通成员
|
||||
members.conceal=隐藏身份
|
||||
members.remove=移除成员
|
||||
members.leave=离开组织
|
||||
members.invite_desc=请输入被邀请到组织 %s 的用户名称:
|
||||
members.invite_desc=邀请新的用户加入 %s:
|
||||
members.invite_now=立即邀请
|
||||
|
||||
teams.join=加入团队
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=该团队拥有对所属仓库的 <strong>读取</str
|
||||
teams.write_permission_desc=该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
|
||||
teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
|
||||
teams.repositories=团队仓库
|
||||
teams.search_repo_placeholder=搜索仓库...
|
||||
teams.add_team_repository=添加团队仓库
|
||||
teams.remove_repo=移除仓库
|
||||
teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先创建仓库!
|
||||
@@ -773,6 +837,8 @@ dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件(警告
|
||||
dashboard.resync_all_sshkeys_success=所有公钥重新生成成功!
|
||||
dashboard.resync_all_update_hooks=重新生成所有仓库的 Update 钩子(用于自定义配置文件被修改)
|
||||
dashboard.resync_all_update_hooks_success=所有仓库的 Update 钩子重新生成成功!
|
||||
dashboard.reinit_missing_repos=重新初始化所有丢失 Git 文件的仓库
|
||||
dashboard.reinit_missing_repos_success=所有丢失 Git 文件的仓库重新初始化成功!
|
||||
|
||||
dashboard.server_uptime=服务运行时间
|
||||
dashboard.current_goroutine=当前 Goroutines 数量
|
||||
@@ -820,6 +886,8 @@ users.auth_login_name=认证登录名称
|
||||
users.password_helper=将值留空使其保持不变。
|
||||
users.update_profile_success=该用户信息更新成功!
|
||||
users.edit_account=编辑用户信息
|
||||
users.max_repo_creation=最大允许创建仓库数量
|
||||
users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值)
|
||||
users.is_activated=该用户已被激活
|
||||
users.is_admin=该用户具有管理员权限
|
||||
users.allow_git_hook=该用户具有创建 Git 钩子的权限
|
||||
@@ -851,6 +919,7 @@ auths.enabled=已启用
|
||||
auths.updated=最后更新时间
|
||||
auths.auth_type=认证类型
|
||||
auths.auth_name=认证名称
|
||||
auths.security_protocol=安全协议
|
||||
auths.domain=域名
|
||||
auths.host=主机地址
|
||||
auths.port=主机端口
|
||||
@@ -859,9 +928,12 @@ auths.bind_password=绑定密码
|
||||
auths.bind_password_helper=警告:该密码将会以明文的形式保存在数据库中。请不要使用拥有高权限的帐户!
|
||||
auths.user_base=用户搜索基准
|
||||
auths.user_dn=User DN
|
||||
auths.attribute_username=用户名属性
|
||||
auths.attribute_username_placeholder=留空表示使用用户登录时所使用的用户名
|
||||
auths.attribute_name=名字属性
|
||||
auths.attribute_surname=姓氏属性
|
||||
auths.attribute_mail=邮箱属性
|
||||
auths.attributes_in_bind=从 Bind DN 中拉取属性信息
|
||||
auths.filter=用户过滤规则
|
||||
auths.admin_filter=管理员过滤规则
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -883,6 +955,7 @@ auths.update=更新认证设置
|
||||
auths.delete=删除该认证
|
||||
auths.delete_auth_title=删除认证操作
|
||||
auths.delete_auth_desc=该认证将被删除。是否继续?
|
||||
auths.still_in_used=此认证仍旧与一些用户有关联,请先删除或者将这些用户转换为其它登录类型。
|
||||
auths.deletion_success=授权源删除成功!
|
||||
|
||||
config.server_config=服务器配置
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=静态文件根目录
|
||||
config.log_file_root_path=日志文件根目录
|
||||
config.script_type=脚本类型
|
||||
config.reverse_auth_user=反向代理认证
|
||||
|
||||
config.ssh_config=SSH 配置
|
||||
config.ssh_enabled=启用服务
|
||||
config.ssh_start_builtin_server=启用内置服务
|
||||
config.ssh_domain=域名
|
||||
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=数据库类型
|
||||
config.db_host=主机地址
|
||||
@@ -913,7 +999,6 @@ config.register_email_confirm=注册邮件确认
|
||||
config.disable_register=关闭注册功能
|
||||
config.show_registration_button=显示注册按钮
|
||||
config.require_sign_in_view=强制登录浏览
|
||||
config.enable_cache_avatar=开启缓存头像
|
||||
config.mail_notify=邮件通知提醒
|
||||
config.disable_key_size_check=禁用密钥最小长度检查
|
||||
config.enable_captcha=启用验证码服务
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=禁用 HELO 操作
|
||||
config.mailer_name=发送者名称
|
||||
config.mailer_host=邮件主机地址
|
||||
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 配置
|
||||
@@ -962,6 +1050,13 @@ monitor.start=开始时间
|
||||
monitor.execute_time=已执行时间
|
||||
|
||||
notices.system_notice_list=系统提示管理
|
||||
notices.view_detail_header=查看提示详情
|
||||
notices.actions=操作
|
||||
notices.select_all=选中全部
|
||||
notices.deselect_all=取消所有选中
|
||||
notices.inverse_selection=反向选中
|
||||
notices.delete_selected=删除选中项
|
||||
notices.delete_all=删除所有提示
|
||||
notices.type=提示类型
|
||||
notices.type_1=仓库
|
||||
notices.desc=描述
|
||||
@@ -973,12 +1068,16 @@ 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/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>`
|
||||
reopen_issue=`重新开启了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`创建了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
close_pull_request=`关闭了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
reopen_pull_request=`重新开启了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`评论了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`合并了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=将仓库 <code>%s</code> 转移至 <a href="%s">%s</a>
|
||||
push_tag=推送了标签 <a href="%s/src/%s">%[2]s</a> 到 <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=查看 2 次提交的内容对比
|
||||
compare_commits=对比 %d 次代码提交
|
||||
|
||||
[tool]
|
||||
ago=之前
|
||||
|
||||
491
conf/locale/locale_zh-HK.ini
Executable file → Normal file
491
conf/locale/locale_zh-HK.ini
Executable file → Normal file
@@ -3,95 +3,91 @@ app_desc=基於 Go 語言的自助 Git 服務
|
||||
home=首頁
|
||||
dashboard=控制面版
|
||||
explore=探索
|
||||
help=幫助
|
||||
sign_in=登錄
|
||||
sign_out=退出
|
||||
help=說明
|
||||
sign_in=登入
|
||||
sign_out=登出
|
||||
sign_up=註冊
|
||||
register=註冊
|
||||
website=官方網站
|
||||
version=當前版本
|
||||
website=網站
|
||||
version=版本
|
||||
page=頁面
|
||||
template=模版
|
||||
language=語言選項
|
||||
template=樣板
|
||||
language=語言
|
||||
create_new=創建...
|
||||
user_profile_and_more=用戶信息及更多
|
||||
signed_in_as=已登錄用戶
|
||||
|
||||
username=用戶名
|
||||
email=郵箱
|
||||
username=用戶名稱
|
||||
email=電子郵件
|
||||
password=密碼
|
||||
re_type=確認密碼
|
||||
captcha=驗證碼
|
||||
|
||||
repository=倉庫
|
||||
repository=儲存庫
|
||||
organization=組織
|
||||
mirror=鏡像
|
||||
new_repo=創建新的倉庫
|
||||
new_repo=新增儲存庫
|
||||
new_migrate=遷移外部倉庫
|
||||
new_fork=新的派生倉庫
|
||||
new_org=創建新的組織
|
||||
manage_org=管理我的組織
|
||||
admin_panel=管理面版
|
||||
account_settings=帳戶設置
|
||||
settings=帳戶設置
|
||||
your_profile=個人信息
|
||||
your_settings=用戶設置
|
||||
new_mirror=新鏡像
|
||||
new_fork=新增程式庫分支
|
||||
new_org=新增組織
|
||||
manage_org=管理組織
|
||||
admin_panel=管理面板
|
||||
account_settings=帳號設定
|
||||
settings=設定
|
||||
your_profile=個人資料
|
||||
your_settings=用戶設定
|
||||
|
||||
news_feed=最新活動
|
||||
activities=活動
|
||||
pull_requests=合併請求
|
||||
issues=問題管理
|
||||
issues=問題
|
||||
|
||||
cancel=取消
|
||||
|
||||
[search]
|
||||
search=搜尋...
|
||||
repository=倉庫
|
||||
user=用戶
|
||||
issue=工單
|
||||
code=程式碼
|
||||
|
||||
[install]
|
||||
install=安裝頁面
|
||||
title=首次執行安裝程序
|
||||
docker_helper=If you're running Gogs inside Docker, please read <a target="_blank" href="%s">Guidelines</a> carefully before you change anything in this page!
|
||||
requite_db_desc=Gogs requires MySQL, PostgreSQL, SQLite3 or TiDB.
|
||||
title=首次安裝步驟
|
||||
docker_helper=如果您正在使用 Docker 容器運行 Gogs,請務必先仔細閱讀 <a target="_blank" href="%s">官方文檔</a> 後再對本頁面進行填寫。
|
||||
requite_db_desc=Gogs 要求安裝 MySQL、PostgreSQL、SQLite3 或 TiDB。
|
||||
db_title=數據庫設置
|
||||
db_type=數據庫類型
|
||||
host=數據庫主機
|
||||
user=數據庫用戶
|
||||
password=數據庫用戶密碼
|
||||
db_name=數據庫名稱
|
||||
db_type=資料庫類型
|
||||
host=主機
|
||||
user=帳號
|
||||
password=密碼
|
||||
db_name=資料庫名稱
|
||||
db_helper=如果您使用 MySQL,請使用 INNODB 引擎以及 utf8_general_ci 字符集。
|
||||
ssl_mode=SSL 模式
|
||||
path=數據庫文件路徑
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database.
|
||||
err_empty_db_path=SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name=TiDB database name does not allow characters "." and "-".
|
||||
no_admin_and_disable_registration=You cannot disable registration without creating an admin account.
|
||||
err_empty_admin_password=Admin password cannot be empty.
|
||||
sqlite_helper=SQLite3 或 TiDB 資料庫檔案路徑。<br>作為以服務執行時,請使用絕對路徑。
|
||||
err_empty_db_path=SQLite3 或 TiDB 的數據庫路徑不能為空。
|
||||
err_invalid_tidb_name=TiDB 數據庫名稱不允許包含字符 "." 或 "-" 。
|
||||
no_admin_and_disable_registration=您不能夠在未創建管理員用戶的情況下禁止註冊。
|
||||
err_empty_admin_password=管理員密碼不能為空。
|
||||
|
||||
general_title=應用基本設置
|
||||
app_name=應用名稱
|
||||
app_name_helper=為您的組織取個響亮而又偉大的名稱
|
||||
repo_path=倉庫根目錄
|
||||
repo_path_helper=所有 Git 遠程倉庫都將被存放於該目錄。
|
||||
run_user=執行系統用戶
|
||||
run_user_helper=該用戶必須具有對倉庫根目錄和執行 Gogs 的操作權限。
|
||||
repo_path=儲存庫的根目錄
|
||||
repo_path_helper=所有Git遠端儲存庫將會儲存在這個目錄之下。
|
||||
run_user=執行使用者
|
||||
run_user_helper=該用戶必須具有對儲存庫根目錄和執行 Gogs 的操作權限。
|
||||
domain=域名
|
||||
domain_helper=該設置影響 SSH 複製地址。
|
||||
ssh_port=SSH 埠
|
||||
ssh_port_helper=您的 SSH 服務正在使用此埠號,若要禁用SSH 功能請保持欄位空白。
|
||||
http_port=HTTP 端口號
|
||||
http_port_helper=應用監聽的端口號
|
||||
app_url=應用 URL
|
||||
app_url=應用程式網址
|
||||
app_url_helper=該設置影響 HTTP/HTTPS 複製地址和一些郵箱中的連結。
|
||||
log_root_path=日誌路徑
|
||||
log_root_path_helper=寫入日誌檔目錄
|
||||
|
||||
optional_title=可選設置
|
||||
email_title=電子郵件服務設定
|
||||
smtp_host=SMTP 主機
|
||||
smtp_from=郵件來自
|
||||
smtp_from=寄件者
|
||||
smtp_from_helper=郵件來自地址,遵循 RFC 5322 標准。可以是一個單純的郵箱地址或使用 "name" <email@example.com> 的格式。
|
||||
mailer_user=發送郵箱
|
||||
mailer_user=寄件者 E-mail
|
||||
mailer_password=發送郵箱密碼
|
||||
register_confirm=啟用註冊郵箱確認
|
||||
mail_notify=啟用郵件通知提醒
|
||||
@@ -102,8 +98,8 @@ disable_gravatar=禁用 Gravatar 服務
|
||||
disable_gravatar_popup=禁用 Gravatar 和自定義源,僅使用由用戶上傳或默認的頭像。
|
||||
disable_registration=禁止用戶自主註冊
|
||||
disable_registration_popup=禁止用戶自主註冊功能,只有管理員可以添加帳號。
|
||||
enable_captcha=Enable Captcha
|
||||
enable_captcha_popup=Require validate captcha for user self-registration.
|
||||
enable_captcha=啟用驗證碼服務
|
||||
enable_captcha_popup=要求在用戶註冊時輸入驗證碼
|
||||
require_sign_in_view=啓用登錄訪問限制
|
||||
require_sign_in_view_popup=只有已登錄的用戶才能夠訪問頁面,否則將只能看到登錄或註冊頁面。
|
||||
admin_setting_desc=創建管理員帳號並不是必須的,因為 ID=1 的用戶將自動獲得管理員權限。
|
||||
@@ -111,7 +107,7 @@ admin_title=管理員帳號設置
|
||||
admin_name=管理員用戶名
|
||||
admin_password=管理員密碼
|
||||
confirm_password=確認密碼
|
||||
admin_email=Admin E-mail
|
||||
admin_email=管理員郵箱
|
||||
install_gogs=立即安裝
|
||||
test_git_failed=無法識別 'git' 命令:%v
|
||||
sqlite3_not_available=您所使用的發行版本不支持 SQLite3,請從 %s 下載官方構建版,而不是 gobuild 版本。
|
||||
@@ -121,6 +117,7 @@ run_user_not_match=執行系統用戶非當前用戶:%s -> %s
|
||||
save_config_failed=應用配置保存失敗:%v
|
||||
invalid_admin_setting=管理員帳戶設置不正確:%v
|
||||
install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG!
|
||||
invalid_log_root_path=日誌根目錄無效: %v
|
||||
|
||||
[home]
|
||||
uname_holder=用戶名或郵箱
|
||||
@@ -136,6 +133,8 @@ issues.in_your_repos=屬於該用戶倉庫的
|
||||
|
||||
[explore]
|
||||
repos=探索倉庫
|
||||
users=用戶
|
||||
search=搜索
|
||||
|
||||
[auth]
|
||||
create_new_account=創建帳戶
|
||||
@@ -158,13 +157,14 @@ reset_password=重置密碼
|
||||
invalid_code=對不起,您的確認代碼已過期或已失效。
|
||||
reset_password_helper=單擊此處重置密碼
|
||||
password_too_short=密碼長度不能少於 6 位!
|
||||
non_local_account=Non-local accounts cannot change passwords through Gogs.
|
||||
|
||||
[mail]
|
||||
activate_account=Please activate your account
|
||||
activate_email=Verify your e-mail address
|
||||
reset_password=Reset your password
|
||||
register_success=Register success, Welcome
|
||||
register_notify=Welcome on board
|
||||
activate_account=請激活您的帳戶
|
||||
activate_email=請驗證您的郵箱地址
|
||||
reset_password=重置密碼
|
||||
register_success=註冊成功,歡迎使用
|
||||
register_notify=歡迎使用
|
||||
|
||||
[modal]
|
||||
yes=確認操作
|
||||
@@ -173,7 +173,7 @@ modify=確認修改
|
||||
|
||||
[form]
|
||||
UserName=用戶名
|
||||
RepoName=倉庫名稱
|
||||
RepoName=儲存庫名稱
|
||||
Email=郵箱地址
|
||||
Password=密碼
|
||||
Retype=確認密碼
|
||||
@@ -192,7 +192,7 @@ min_size_error=長度最小為 %s 個字符。
|
||||
max_size_error=長度最大為 %s 個字符。
|
||||
email_error=不是一個有效的郵箱地址。
|
||||
url_error=不是一個有效的 URL。
|
||||
include_error=` must contain substring '%s'.`
|
||||
include_error=必須包含子字符串 '%s'。
|
||||
unknown_error=未知錯誤:
|
||||
captcha_incorrect=驗證碼未匹配。
|
||||
password_not_match=密碼與確認密碼未匹配。
|
||||
@@ -202,7 +202,6 @@ repo_name_been_taken=倉庫名稱已經被佔用。
|
||||
org_name_been_taken=組織名稱已經被佔用。
|
||||
team_name_been_taken=團隊名稱已經被佔用。
|
||||
email_been_used=郵箱地址已經被使用。
|
||||
illegal_team_name=團隊名稱包含不合法字符。
|
||||
username_password_incorrect=用戶名或密碼不正確。
|
||||
enterred_invalid_repo_name=請檢查您輸入的倉庫名稱是正確。
|
||||
enterred_invalid_owner_name=請檢查您輸入的新所有者用戶名是否正確。
|
||||
@@ -218,19 +217,18 @@ still_own_repo=您的帳戶仍然是某些倉庫的擁有者,您必須先轉
|
||||
still_has_org=您的帳戶仍舊是某些組織的成員,您必須先離開或刪除組織。
|
||||
org_still_own_repo=該組織仍然是某些倉庫的擁有者,您必須先轉移或刪除它們才能執行刪除組織操作!
|
||||
|
||||
still_own_user=該授權認證依舊被部分用戶使用,請先刪除該部分用戶後再試!
|
||||
|
||||
target_branch_not_exist=目標分支不存在
|
||||
|
||||
[user]
|
||||
change_avatar=到 gravatar.com 上修改您的頭像
|
||||
change_custom_avatar=到個人設置中修改頭像
|
||||
change_avatar=Change your avatar
|
||||
join_on=加入於
|
||||
repositories=倉庫列表
|
||||
activity=公開活動
|
||||
followers=關註者
|
||||
starred=已讚好
|
||||
following=關註中
|
||||
follow=關注
|
||||
unfollow=取消關注
|
||||
|
||||
form.name_reserved=用戶名 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
|
||||
@@ -247,30 +245,31 @@ uid=用戶 ID
|
||||
|
||||
public_profile=公開信息
|
||||
profile_desc=您的郵箱地址將會被公開,並被用於接收帳戶的所有提醒和通知。
|
||||
password_username_disabled=不允許非本地類型使用者更改他們的使用者名。
|
||||
full_name=自定義名稱
|
||||
website=個人網站
|
||||
location=所在地區
|
||||
update_profile=更新信息
|
||||
update_profile_success=您的個人信息更新成功!
|
||||
change_username=用戶名將被修改
|
||||
change_username_prompt=This change will affect the way how links relate to your account.
|
||||
change_username_prompt=該操作將會影響到所有與您帳戶有關的鏈接
|
||||
continue=繼續操作
|
||||
cancel=取消操作
|
||||
|
||||
enable_custom_avatar=啟動自定義頭像
|
||||
enable_custom_avatar_helper=激活該選項來禁止從 Gravatar 獲取頭像
|
||||
choose_new_avatar=選擇新的頭像
|
||||
update_avatar=更新頭像設置
|
||||
delete_current_avatar=刪除當前頭像
|
||||
uploaded_avatar_not_a_image=上傳的文件不是一張圖片!
|
||||
no_custom_avatar_available=沒有任何自定義頭像,無法激活該選項。
|
||||
update_avatar_success=您的頭像設置更新成功!
|
||||
|
||||
change_password=修改密碼
|
||||
old_password=當前密碼
|
||||
new_password=新的密碼
|
||||
retype_new_password=Retype New Password
|
||||
retype_new_password=重新輸入新的密碼
|
||||
password_incorrect=當前密碼不正確!
|
||||
change_password_success=密碼修改成功!您現在可以使用新的密碼登錄。
|
||||
password_change_disabled=不允許非本地類型使用者,更改其密碼。
|
||||
|
||||
emails=電子郵件地址
|
||||
manage_emails=管理電子郵件地址
|
||||
@@ -278,9 +277,9 @@ email_desc=您的主要邮箱地址将被用于通知提醒和其它操作。
|
||||
primary=主要
|
||||
primary_email=设为主要
|
||||
delete_email=刪除
|
||||
email_deletion=E-mail Deletion
|
||||
email_deletion_desc=Delete this e-mail address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success=E-mail has been deleted successfully!
|
||||
email_deletion=刪除郵箱
|
||||
email_deletion_desc=刪除該郵箱地址將會移除所有相關的信息。是否繼續?
|
||||
email_deletion_success=成功刪除郵箱!
|
||||
add_new_email=添加新的電子郵件地址
|
||||
add_email=添加電子郵件
|
||||
add_email_confirmation_sent=一封待確認的電子郵件已發送到 '%s',請在%d 小時內檢查您的收件箱,並完成確認過程。
|
||||
@@ -335,7 +334,7 @@ repo_name=倉庫名稱
|
||||
repo_name_helper=偉大的倉庫名稱一般都較短、令人深刻並且 <strong>獨一無二</strong> 的。
|
||||
visibility=可見度
|
||||
visiblity_helper=該倉庫為 <span class="ui red text">私有的</span>
|
||||
visiblity_helper_forced=Site admin has forced all new repositories to be <span class="ui red text">Private</span>
|
||||
visiblity_helper_forced=網站管理員已強制要求所有新建倉庫必須為 <span class="ui red text">私有的</span>
|
||||
visiblity_fork_helper=(修改該值將會影響到所有派生倉庫)
|
||||
clone_helper=不知道如何操作?訪問 <a target="_blank"href="%s"> 帮助説明</a> !
|
||||
fork_repo=派生倉庫
|
||||
@@ -343,19 +342,24 @@ fork_from=派生自
|
||||
fork_visiblity_helper=派生倉庫無法修改可見性。
|
||||
repo_desc=倉庫描述
|
||||
repo_lang=倉庫語言
|
||||
repo_lang_helper=Select .gitignore files
|
||||
repo_lang_helper=請選擇 .gitignore 文件
|
||||
license=授權許可
|
||||
license_helper=請選擇授權許可文件
|
||||
readme=Readme
|
||||
readme_helper=Select a readme template
|
||||
auto_init=Initialize this repository with selected files and template
|
||||
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=鏡像同步周期(小時)
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=鏡像地址
|
||||
mirror_address_desc=請在位址中包括必要的使用者憑據。
|
||||
watchers=關注者
|
||||
stargazers=稱讚者
|
||||
forks=派生倉庫
|
||||
|
||||
form.reach_limit_of_creation=擁有者已達到儲存庫最大的新增上限 %d。
|
||||
form.name_reserved=倉庫名稱 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=倉庫名稱不允許 '%s' 的格式。
|
||||
|
||||
@@ -365,36 +369,38 @@ migrate_type_helper=該倉庫將是一個 <span class="text blue">鏡像</span>
|
||||
migrate_repo=遷移倉庫
|
||||
migrate.clone_address=複製地址
|
||||
migrate.clone_address_desc=該地址可以是 HTTP/HTTPS/GIT URL 或本地服務器路徑。
|
||||
migrate.permission_denied=You are not allowed to import local repositories.
|
||||
migrate.permission_denied=您並沒有導入本地倉庫的權限。
|
||||
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=遷移失敗:%v
|
||||
|
||||
mirror_from=镜像来自
|
||||
forked_from=派生自
|
||||
fork_from_self=無法派生已經擁有的倉庫!
|
||||
copy_link=複製連結
|
||||
copy_link_success=Copied!
|
||||
copy_link_error=Press ⌘-C or Ctrl-C to copy
|
||||
copy_link_success=複製成功!
|
||||
copy_link_error=請按下 ⌘-C 或 Ctrl-C 複製
|
||||
copied=複製成功
|
||||
unwatch=取消關註
|
||||
unwatch=取消關注
|
||||
watch=關註
|
||||
unstar=取消讚好
|
||||
star=讚好
|
||||
fork=派生
|
||||
fork=複刻
|
||||
|
||||
no_desc=暫無描述
|
||||
quick_guide=快速幫助
|
||||
clone_this_repo=複製當前倉庫
|
||||
create_new_repo_command=從命令行創建一個新的倉庫
|
||||
push_exist_repo=從命令行推送已經創建的倉庫
|
||||
repo_is_empty=This repository is empty, please come back later!
|
||||
repo_is_empty=這倉庫不包含任何內容,請稍後再訪問!
|
||||
|
||||
code=代碼
|
||||
branch=分支
|
||||
tree=目錄樹
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=過濾分支或標籤
|
||||
branches=分支列表
|
||||
tags=標籤列表
|
||||
issues=問題管理
|
||||
pulls=Pull Requests
|
||||
pulls=合併請求
|
||||
labels=標籤
|
||||
milestones=里程碑
|
||||
commits=提交歷史
|
||||
@@ -449,7 +455,7 @@ issues.filter_sort.recentupdate=最近更新
|
||||
issues.filter_sort.leastupdate=最少更新
|
||||
issues.filter_sort.mostcomment=最多評論
|
||||
issues.filter_sort.leastcomment=最少評論
|
||||
issues.opened_by=opened %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by=由 <a href="%[2]s">%[3]s</a> 與 %[1]s創建
|
||||
issues.opened_by_fake=由 %[2]s 於 %[1]s創建
|
||||
issues.previous=上一頁
|
||||
issues.next=下一頁
|
||||
@@ -465,9 +471,9 @@ issues.reopen_comment_issue=重新開啟及評論
|
||||
issues.create_comment=評論
|
||||
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=`referenced this issue from a commit <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.admin=管理員
|
||||
issues.collaborator=協同者
|
||||
issues.owner=所有者
|
||||
issues.sign_up_for_free=免費註冊
|
||||
issues.sign_in_require_desc=及加入到對話當中。如果您已經註冊,可以直接 <a href="%s">登錄及評論</a>
|
||||
@@ -484,32 +490,33 @@ issues.label_modify=修改標籤
|
||||
issues.label_deletion=刪除標籤
|
||||
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
|
||||
issues.label_deletion_success=標籤刪除成功!
|
||||
issues.num_participants=%d 參與者
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=創建合併請求
|
||||
pulls.compare_changes=對比文件變化
|
||||
pulls.compare_changes_desc=對比兩個分支間的文件變化及發起一個合併請求。
|
||||
pulls.compare_base=base
|
||||
pulls.compare_compare=compare
|
||||
pulls.filter_branch=Filter branch
|
||||
pulls.compare_base=基準分支
|
||||
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.create=Create 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.tab_conversation=Conversation
|
||||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Files changed
|
||||
pulls.reopen_to_merge=Please reopen this pull request to perform merge operation.
|
||||
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.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=You can perform auto-merge operation on this pull request.
|
||||
pulls.cannot_auto_merge_desc=You can't perform auto-merge operation because there are conflicts between commits.
|
||||
pulls.cannot_auto_merge_helper=Please use command line tool to solve it.
|
||||
pulls.merge_pull_request=Merge 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.`
|
||||
pulls.nothing_to_compare=基準和對比分支代碼已經同步,無需進行對比。
|
||||
pulls.has_pull_request=`已經存在目標分支的合併請求:<a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=創建合併請求
|
||||
pulls.title_desc=請求將 %[1]d 次代碼提交從 <code>%[2]s</code> 合併至 <code>%[3]s</code>
|
||||
pulls.merged_title_desc=於 %[4]s 將 %[1]d 次代碼提交從 <code>%[2]s</code>合併至 <code>%[3]s</code>
|
||||
pulls.tab_conversation=對話內容
|
||||
pulls.tab_commits=代碼提交
|
||||
pulls.tab_files=文件變動
|
||||
pulls.reopen_to_merge=請重新開啟合併請求來完成合併操作。
|
||||
pulls.merged=已合併
|
||||
pulls.has_merged=該合併請求已經成功合併!
|
||||
pulls.data_broken=該合併請求的數據由於派生倉庫的相關信息被刪除而被破壞。
|
||||
pulls.is_checking=該合併請求正在進行衝突檢查,請稍後再刷新頁面。
|
||||
pulls.can_auto_merge_desc=這個拉請求可以自動合併。
|
||||
pulls.cannot_auto_merge_desc=由於存在衝突,不能自動合併這推送請求。
|
||||
pulls.cannot_auto_merge_helper=請手動合併來解決衝突。
|
||||
pulls.merge_pull_request=合併請求
|
||||
pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d),您無法執行重新開啟操作。`
|
||||
|
||||
milestones.new=新的里程碑
|
||||
milestones.open_tab=%d 開啟中
|
||||
@@ -535,29 +542,72 @@ milestones.deletion=刪除里程碑
|
||||
milestones.deletion_desc=刪除該里程碑將會移除所有問題中相關信息。是否繼續?
|
||||
milestones.deletion_success=里程碑刪除成功!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=歡迎使用 Wiki!
|
||||
wiki.welcome_desc=Wiki 是用於共同協作文檔的地方,清晰的文檔可以幫助其他人深入了解您的項目。
|
||||
wiki.create_first_page=創建第一個頁面
|
||||
wiki.page=頁面
|
||||
wiki.filter_page=過濾頁面
|
||||
wiki.new_page=創建新的頁面
|
||||
wiki.default_commit_message=關於此次修改的說明(可選)。
|
||||
wiki.save_page=保存頁面
|
||||
wiki.last_commit_info=%s 於 %s 修改了此頁面
|
||||
wiki.edit_page_button=修改
|
||||
wiki.new_page_button=新的頁面
|
||||
wiki.delete_page_button=刪除頁面
|
||||
wiki.delete_page_notice_1=這將刪除頁面 <code>"%s"</code>。請三思而後行。
|
||||
wiki.page_already_exists=相同名稱的 Wiki 頁面已經存在。
|
||||
wiki.pages=所有頁面
|
||||
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.danger_zone=危險操作區
|
||||
settings.site=官方網站
|
||||
settings.update_settings=更新倉庫設置
|
||||
settings.change_reponame_prompt=This change will affect how links relate to the repository.
|
||||
settings.change_reponame_prompt=該操作將會影響到所有與該倉庫有關的鏈接
|
||||
settings.advanced_settings=高級設置
|
||||
settings.wiki_desc=啟用 Wiki 以允許用戶協作文檔
|
||||
settings.use_external_wiki=使用外部 wiki
|
||||
settings.external_wiki_url=外部 Wiki 連結
|
||||
settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到 URL。
|
||||
settings.issues_desc=啟用內置的輕量級問題管理系統
|
||||
settings.use_external_issue_tracker=使用外部的問題管理系統
|
||||
settings.tracker_url_format=外部問題管理系統的 URL 格式
|
||||
settings.tracker_issue_style=External Issue Tracker Naming Style:
|
||||
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
|
||||
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
|
||||
settings.pulls_desc=啟用合併請求以接受社區貢獻
|
||||
settings.danger_zone=危險操作區
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.convert=轉換為正規倉庫
|
||||
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.
|
||||
settings.transfer=轉移倉庫所有權
|
||||
settings.transfer_desc=您可以將倉庫轉移至您擁有管理員權限的帳戶或組織。
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.transfer_notices_1=- 如果您將倉庫轉移給個人用戶,您將會丟失操作權限。
|
||||
settings.transfer_notices_2=- 如果您將倉庫轉移給您是所有者的組織,您的操作權限將被保留。
|
||||
settings.transfer_form_title=請輸入以下信息以確認您的操作:
|
||||
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=- 將刪除和停用 %s 的 wiki
|
||||
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
|
||||
settings.delete=刪除本倉庫
|
||||
settings.delete_desc=刪除倉庫操作不可逆轉,請三思而後行。
|
||||
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.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 be became independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滾。
|
||||
settings.delete_notices_2=- 此操作將永久刪除該倉庫,包括 Git 數據、 問題、 評論和協作者的操作權限。
|
||||
settings.delete_notices_fork_1=- All forks will become independent after deletion.
|
||||
settings.deletion_success=倉庫刪除成功!
|
||||
settings.update_settings_success=倉庫設置更新成功!
|
||||
settings.transfer_owner=新擁有者
|
||||
settings.make_transfer=確認轉移倉庫
|
||||
@@ -565,19 +615,26 @@ settings.transfer_succeed=倉庫所有權轉移成功!
|
||||
settings.confirm_delete=確認刪除倉庫
|
||||
settings.add_collaborator=增加新的協作者
|
||||
settings.add_collaborator_success=成功添加新的協作者!
|
||||
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=被操作的協作者已經被收回權限!
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.search_user_placeholder=搜索用戶...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=被操作的用戶是組織成員,因此無法添加為協作者!
|
||||
settings.add_webhook=添加 Web 鉤子
|
||||
settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
|
||||
settings.webhook_deletion=Delete Webhook
|
||||
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
|
||||
settings.webhook_deletion_success=Webhook has been deleted successfully!
|
||||
settings.webhook.request=Request
|
||||
settings.webhook.response=Response
|
||||
settings.webhook.headers=Headers
|
||||
settings.webhook.payload=Payload
|
||||
settings.webhook.body=Body
|
||||
settings.webhook_deletion=刪除 Web 鉤子
|
||||
settings.webhook_deletion_desc=刪除該 Web 鉤子將會刪除與其有關的信息和推送歷史。是否繼續?
|
||||
settings.webhook_deletion_success=Web 鉤子刪除成功!
|
||||
settings.webhook.test_delivery=測試推送
|
||||
settings.webhook.test_delivery_desc=生成並推送一個模擬的 Push 事件
|
||||
settings.webhook.test_delivery_success=測試推送已經加入到隊列,請耐心等待數秒再刷新推送記錄。
|
||||
settings.webhook.request=請求內容
|
||||
settings.webhook.response=響應內容
|
||||
settings.webhook.headers=標題
|
||||
settings.webhook.payload=推送內容
|
||||
settings.webhook.body=響應內容
|
||||
settings.githooks_desc=Git 鉤子是由 Git 本身提供的功能,以下為 Gogs 所支持的鉤子列表。
|
||||
settings.githook_edit_desc=如果鉤子未啟動,則會顯示樣例文件中的內容。如果想要刪除某個鉤子,則提交空白文本即可。
|
||||
settings.githook_name=鉤子名稱
|
||||
@@ -587,17 +644,17 @@ settings.add_webhook_desc=我們會通過 <code>POST</code> 請求將訂閱事
|
||||
settings.payload_url=推送地址
|
||||
settings.content_type=數據格式
|
||||
settings.secret=密鑰文本
|
||||
settings.slack_username=Username
|
||||
settings.slack_icon_url=Icon URL
|
||||
settings.slack_color=Color
|
||||
settings.slack_username=服務名稱
|
||||
settings.slack_icon_url=圖標 URL
|
||||
settings.slack_color=顏色代碼
|
||||
settings.event_desc=請設置您希望觸發 Web 鉤子的事件:
|
||||
settings.event_push_only=只推送 <code>push</code> 事件。
|
||||
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_push=Push
|
||||
settings.event_push_desc=Git push to a repository
|
||||
settings.event_send_everything=推送 <strong>所有</strong> 事件
|
||||
settings.event_choose=讓我選擇我的需要
|
||||
settings.event_create=創建
|
||||
settings.event_create_desc=創建分支或標籤
|
||||
settings.event_push=推送
|
||||
settings.event_push_desc=Git 倉庫推送
|
||||
settings.active=是否激活
|
||||
settings.active_helper=當指定事件發生時我們將會觸發此 Web 鉤子。
|
||||
settings.add_hook_success=Web 鉤子添加成功!
|
||||
@@ -612,6 +669,7 @@ settings.slack_domain=域名
|
||||
settings.slack_channel=頻道
|
||||
settings.deploy_keys=管理部署密鑰
|
||||
settings.add_deploy_key=添加部署密鑰
|
||||
settings.deploy_key_desc=部署密鑰僅具有隻讀權限,它在功能上和個人用戶的公開密鑰有本質區別。
|
||||
settings.no_deploy_keys=您還沒有添加任何部署密鑰。
|
||||
settings.title=標題
|
||||
settings.deploy_key_content=密鑰文本
|
||||
@@ -627,9 +685,13 @@ diff.parent=父節點
|
||||
diff.commit=當前提交
|
||||
diff.data_not_available=暫無可用數據
|
||||
diff.show_diff_stats=顯示文件統計
|
||||
diff.show_split_view=分割檢視
|
||||
diff.show_unified_view=統一視圖
|
||||
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
|
||||
diff.bin=二進制
|
||||
diff.view_file=查看文件
|
||||
diff.file_supressed=File diff supressed because it is too large
|
||||
diff.too_many_files=Some files were not shown because too many files changed in this diff
|
||||
|
||||
release.releases=版本發佈
|
||||
release.new_release=發佈新版本
|
||||
@@ -639,32 +701,32 @@ release.stable=穩定
|
||||
release.edit=編輯
|
||||
release.ahead=在該版本發佈之後已有 <strong>%d</strong> 次代碼提交到 %s 分支
|
||||
release.source_code=源代碼
|
||||
release.new_subheader=Publish releases to iterate product.
|
||||
release.edit_subheader=Detailed change log can help users understand what has been improved.
|
||||
release.new_subheader=發布版本對產品進行迭代。
|
||||
release.edit_subheader=詳細的變更日誌可以幫助用戶更好地了解產品做了哪些改進。
|
||||
release.tag_name=標籤名稱
|
||||
release.target=目標分支
|
||||
release.tag_helper=選擇或創建一個已存在的標籤
|
||||
release.title=Title
|
||||
release.content=Content
|
||||
release.title=標題
|
||||
release.content=內容
|
||||
release.write=內容編輯
|
||||
release.preview=效果預覽
|
||||
release.loading=正在加載...
|
||||
release.prerelease_desc=這是一個預發佈版本
|
||||
release.prerelease_helper=我們會告知用戶不建議將本發佈投入生產環境使用。
|
||||
release.cancel=Cancel
|
||||
release.cancel=取消
|
||||
release.publish=發佈版本
|
||||
release.save_draft=保在草稿
|
||||
release.save_draft=儲存草稿
|
||||
release.edit_release=編輯發佈信息
|
||||
release.delete_release=Delete This Release
|
||||
release.deletion=Release Deletion
|
||||
release.deletion_desc=Delete this release will delete corresponding Git tag. Do you want to continue?
|
||||
release.deletion_success=Release has been deleted successfully!
|
||||
release.delete_release=刪除此次發布
|
||||
release.deletion=刪除版本發布操作
|
||||
release.deletion_desc=刪除該版本發布將會移除相應的 Git 標籤。是否繼續?
|
||||
release.deletion_success=版本發布刪除成功!
|
||||
release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
|
||||
release.downloads=Downloads
|
||||
release.downloads=下載附件
|
||||
|
||||
[org]
|
||||
org_name_holder=組織名稱
|
||||
org_full_name_holder=Organization Full Name
|
||||
org_full_name_holder=組織全名
|
||||
org_name_helper=偉大的組織都有一個簡短而寓意深刻的名字。
|
||||
create_org=創建組織
|
||||
repo_updated=最後更新於
|
||||
@@ -691,8 +753,8 @@ settings.website=官方網站
|
||||
settings.location=所在地區
|
||||
settings.update_settings=更新組織設置
|
||||
settings.update_setting_success=組織設置更新成功!
|
||||
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=該操作將會影響到所有與該組織有關的鏈接
|
||||
settings.update_avatar_success=組織頭像更新成功!
|
||||
settings.delete=刪除組織
|
||||
settings.delete_account=刪除當前組織
|
||||
settings.delete_prompt=刪除操作會永久清除該組織的信息,並且 <strong>不可恢復</strong>!
|
||||
@@ -701,16 +763,17 @@ settings.delete_org_title=組織刪除操作
|
||||
settings.delete_org_desc=該組織將被永久性刪除,您確定要繼續操作嗎?
|
||||
settings.hooks_desc=在此處添加的 Web 鉤子將會應用到該組織下的 <strong>所有倉庫</strong>。
|
||||
|
||||
members.membership_visibility=成員可見性:
|
||||
members.public=公開成員
|
||||
members.public_helper=設為私有
|
||||
members.private=私有成員
|
||||
members.private_helper=設為公開
|
||||
members.member_role=成員角色:
|
||||
members.owner=管理員
|
||||
members.member=普通成員
|
||||
members.conceal=隱藏身份
|
||||
members.remove=移除成員
|
||||
members.leave=離開組織
|
||||
members.invite_desc=請輸入被邀請到組織 %s 的用戶名稱:
|
||||
members.invite_desc=邀請新的用戶加入 %s:
|
||||
members.invite_now=立即邀請
|
||||
|
||||
teams.join=加入團隊
|
||||
@@ -735,6 +798,7 @@ teams.read_permission_desc=該團隊擁有對所屬倉庫的 <strong>讀取</str
|
||||
teams.write_permission_desc=該團隊擁有對所屬倉庫的 <strong>讀取</strong> 和 <strong>寫入</strong> 的權限。
|
||||
teams.admin_permission_desc=該團隊擁有一定的 <strong>管理</strong> 權限,團隊成員可以讀取、複製、推送以及添加其它倉庫協作者。
|
||||
teams.repositories=團隊倉庫
|
||||
teams.search_repo_placeholder=搜索倉庫...
|
||||
teams.add_team_repository=添加團隊倉庫
|
||||
teams.remove_repo=移除倉庫
|
||||
teams.add_nonexistent_repo=您嘗試添加到團隊的倉庫不存在,請先創建倉庫!
|
||||
@@ -748,9 +812,9 @@ authentication=授權認證管理
|
||||
config=應用配置管理
|
||||
notices=系統提示管理
|
||||
monitor=應用監控面版
|
||||
first_page=First
|
||||
last_page=Last
|
||||
total=Total: %d
|
||||
first_page=首頁
|
||||
last_page=末頁
|
||||
total=總計:%d
|
||||
|
||||
dashboard.statistic=應用統計數據
|
||||
dashboard.operations=管理員操作
|
||||
@@ -765,14 +829,16 @@ dashboard.delete_inactivate_accounts=刪除所有未激活帳戶
|
||||
dashboard.delete_inactivate_accounts_success=所有未激活帳號清除成功!
|
||||
dashboard.delete_repo_archives=刪除所有倉庫存檔
|
||||
dashboard.delete_repo_archives_success=所有倉庫存檔清除成功!
|
||||
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=刪除所有丟失 Git 文件的倉庫記錄
|
||||
dashboard.delete_missing_repos_success=成功刪除所有丟失 Git 文件的倉庫記錄!
|
||||
dashboard.git_gc_repos=對倉庫進行垃圾回收
|
||||
dashboard.git_gc_repos_success=所有倉庫的垃圾回收已成功完成!
|
||||
dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件(警告:不是 Gogs 的密鑰也會被刪除)
|
||||
dashboard.resync_all_sshkeys_success=所有公鑰重新生成成功!
|
||||
dashboard.resync_all_update_hooks=重新生成所有倉庫的 Update 鈎子(用於被修改的自定義配置文件)
|
||||
dashboard.resync_all_update_hooks_success=已成功重新生成所有倉庫的 Update 鈎子!
|
||||
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.server_uptime=服務執行時間
|
||||
dashboard.current_goroutine=當前 Goroutines 數量
|
||||
@@ -811,24 +877,26 @@ users.activated=已激活
|
||||
users.admin=管理員
|
||||
users.repos=倉庫數
|
||||
users.created=創建時間
|
||||
users.send_register_notify=Send Registration Notification To User
|
||||
users.new_success=New account '%s' has been created successfully.
|
||||
users.send_register_notify=向用戶發送註冊通知郵件
|
||||
users.new_success=新用戶 '%s' 創建成功!
|
||||
users.edit=編輯
|
||||
users.auth_source=Authentication Source
|
||||
users.auth_source=認證源
|
||||
users.local=本地
|
||||
users.auth_login_name=Authentication Login Name
|
||||
users.password_helper=Leave it empty to remain unchanged.
|
||||
users.auth_login_name=認證登錄名稱
|
||||
users.password_helper=留空使其保持不變。
|
||||
users.update_profile_success=該用戶信息更新成功!
|
||||
users.edit_account=編輯用戶信息
|
||||
users.max_repo_creation=最大儲存庫新增限制
|
||||
users.max_repo_creation_desc=(設定 -1 使用全域預設限制)
|
||||
users.is_activated=該用戶已被激活
|
||||
users.is_admin=該用戶具有管理員權限
|
||||
users.allow_git_hook=該帳戶具有創建 Git 鉤子的權限
|
||||
users.allow_import_local=This account has permissions to import local repositories
|
||||
users.allow_import_local=該用戶具有導入本地倉庫的權限
|
||||
users.update_profile=更新用戶信息
|
||||
users.delete_account=刪除該用戶
|
||||
users.still_own_repo=該帳戶仍然是某些倉庫的擁有者,您必須先轉移或刪除它們才能執行刪除帳戶操作!
|
||||
users.still_has_org=該帳戶仍舊是某些組織的成員,您必須先使其離開或刪除組織。
|
||||
users.deletion_success=Account has been deleted successfully!
|
||||
users.deletion_success=用戶刪除成功!
|
||||
|
||||
orgs.org_manage_panel=組織管理面版
|
||||
orgs.name=組織名稱
|
||||
@@ -843,47 +911,52 @@ repos.watches=關註數
|
||||
repos.stars=讚好數
|
||||
repos.issues=問題數
|
||||
|
||||
auths.auth_manage_panel=Authentication Manage Panel
|
||||
auths.new=Add New Source
|
||||
auths.auth_manage_panel=認證管理面板
|
||||
auths.new=添加新認證源
|
||||
auths.name=認證名稱
|
||||
auths.type=認證類型
|
||||
auths.enabled=已啟用
|
||||
auths.updated=最後更新時間
|
||||
auths.auth_type=Authentication Type
|
||||
auths.auth_name=Authentication Name
|
||||
auths.auth_type=認證類型
|
||||
auths.auth_name=認證名稱
|
||||
auths.security_protocol=Security Protocol
|
||||
auths.domain=域名
|
||||
auths.host=主機地址
|
||||
auths.port=主機端口
|
||||
auths.bind_dn=綁定DN
|
||||
auths.bind_password=綁定密碼
|
||||
auths.bind_password_helper=Warning: This password is stored in plain text. Do not use a high privileged account.
|
||||
auths.user_base=User Search Base
|
||||
auths.bind_password_helper=警告:該密碼將會以明文的形式保存在數據庫中。請不要使用擁有高權限的帳戶!
|
||||
auths.user_base=用戶搜索基準
|
||||
auths.user_dn=User DN
|
||||
auths.attribute_username=用戶名屬性
|
||||
auths.attribute_username_placeholder=留空表示使用用戶登錄時所使用的用戶名
|
||||
auths.attribute_name=名子屬性
|
||||
auths.attribute_surname=姓氏屬性
|
||||
auths.attribute_mail=電子郵箱屬性
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=使用者篩選器
|
||||
auths.admin_filter=管理者篩選器
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP Authentication Type
|
||||
auths.smtp_auth=SMTP 驗證類型
|
||||
auths.smtphost=SMTP 主機地址
|
||||
auths.smtpport=SMTP 主機端口
|
||||
auths.allowed_domains=Allowed Domains
|
||||
auths.allowed_domains_helper=Leave it empty to not restrict any domains. Multiple domains should be separated by comma ','.
|
||||
auths.allowed_domains=域名白名單
|
||||
auths.allowed_domains_helper=留空表示不對域名做任何限制。多個域名之間需要使用逗號 ',' 分隔。
|
||||
auths.enable_tls=啟用 TLS 加密
|
||||
auths.skip_tls_verify=Skip TLS Verify
|
||||
auths.skip_tls_verify=忽略 TLS 驗證
|
||||
auths.pam_service_name=PAM 服務名稱
|
||||
auths.enable_auto_register=允許授權用戶自動註冊
|
||||
auths.tips=幫助提示
|
||||
auths.edit=Edit Authentication Setting
|
||||
auths.edit=編輯認證設置
|
||||
auths.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
|
||||
auths.delete=Delete This Authentication
|
||||
auths.delete_auth_title=Authentication Deletion
|
||||
auths.delete_auth_desc=This authentication is going to be deleted, do you want to continue?
|
||||
auths.deletion_success=Authentication has been deleted successfully!
|
||||
auths.new_success=新的認證源 "%s" 添加成功!
|
||||
auths.update_success=認證設置更新成功!
|
||||
auths.update=更新認證設置
|
||||
auths.delete=刪除該認證
|
||||
auths.delete_auth_title=刪除認證操作
|
||||
auths.delete_auth_desc=該認證將被刪除。是否繼續?
|
||||
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=認證源刪除成功!
|
||||
|
||||
config.server_config=服務器配置
|
||||
config.app_name=應用名稱
|
||||
@@ -899,6 +972,19 @@ config.static_file_root_path=靜態文件根目錄
|
||||
config.log_file_root_path=日志文件根目錄
|
||||
config.script_type=腳本類型
|
||||
config.reverse_auth_user=反向代理認證
|
||||
|
||||
config.ssh_config=SSH 配置
|
||||
config.ssh_enabled=已啟用
|
||||
config.ssh_start_builtin_server=啟動內建伺服器
|
||||
config.ssh_domain=Domain
|
||||
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=數據庫類型
|
||||
config.db_host=主機地址
|
||||
@@ -907,16 +993,15 @@ config.db_user=數據庫用戶
|
||||
config.db_ssl_mode=SSL 模式
|
||||
config.db_ssl_mode_helper=(僅限 "postgres" 使用)
|
||||
config.db_path=數據庫路徑
|
||||
config.db_path_helper=(for "sqlite3" and "tidb")
|
||||
config.db_path_helper=(用於 "sqlite3" 和 "tidb")
|
||||
config.service_config=服務配置
|
||||
config.register_email_confirm=註冊電子郵件確認
|
||||
config.disable_register=關閉註冊功能
|
||||
config.show_registration_button=顯示註冊按鈕
|
||||
config.require_sign_in_view=強制登錄瀏覽
|
||||
config.enable_cache_avatar=開啟緩存頭像
|
||||
config.mail_notify=郵件通知提醒
|
||||
config.disable_key_size_check=Disable Minimum Key Size Check
|
||||
config.enable_captcha=Enable Captcha
|
||||
config.disable_key_size_check=禁用密鑰最小長度檢查
|
||||
config.enable_captcha=啟用驗證碼服務
|
||||
config.active_code_lives=激活用戶連結有效期
|
||||
config.reset_password_code_lives=重置密碼連結有效期
|
||||
config.webhook_config=Web 鉤子配置
|
||||
@@ -929,6 +1014,9 @@ config.mailer_disable_helo=禁用 HELO 操作
|
||||
config.mailer_name=發送者名稱
|
||||
config.mailer_host=郵件主機地址
|
||||
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 配置
|
||||
@@ -962,6 +1050,13 @@ monitor.start=開始時間
|
||||
monitor.execute_time=已執行時間
|
||||
|
||||
notices.system_notice_list=系統提示管理
|
||||
notices.view_detail_header=查看提示詳情
|
||||
notices.actions=操作
|
||||
notices.select_all=選取全部
|
||||
notices.deselect_all=取消所有選取
|
||||
notices.inverse_selection=反向選取
|
||||
notices.delete_selected=刪除選取項
|
||||
notices.delete_all=刪除所有提示
|
||||
notices.type=提示類型
|
||||
notices.type_1=倉庫
|
||||
notices.desc=描述
|
||||
@@ -969,16 +1064,20 @@ notices.op=操作
|
||||
notices.delete_success=系統提示刪除成功!
|
||||
|
||||
[action]
|
||||
create_repo=創建了倉庫 <a href="%s">%s</a>
|
||||
rename_repo=renamed repository from <code>%[1]s</code> to <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/src/%[2]s">%[3]s</a> 分支的代碼到 <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`創建了問題 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`created pull request <a href="%s/pulls/%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>`
|
||||
create_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>`
|
||||
comment_issue=`評論了問題 <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=將倉庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
merge_pull_request=`合併了合併請求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=將儲存庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
push_tag=推送了標籤 <a href="%s/src/%s">%[2]s</a> 到 <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=查看 2 次提交的內容對比
|
||||
compare_commits=查看 %d 次提交的內容比對
|
||||
|
||||
[tool]
|
||||
ago=之前
|
||||
|
||||
1108
conf/locale/locale_zh-TW.ini
Normal file
1108
conf/locale/locale_zh-TW.ini
Normal file
File diff suppressed because it is too large
Load Diff
1956
config.codekit
1956
config.codekit
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
# 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
|
||||
|
||||
To keep your data out of Docker container, we do a volume(`/var/gogs` -> `/data`) here, and you can change it based on your situation.
|
||||
To keep your data out of Docker container, we do a volume (`/var/gogs` -> `/data`) here, and you can change it based on your situation.
|
||||
|
||||
```
|
||||
# Pull image from Docker Hub.
|
||||
@@ -20,6 +20,8 @@ $ docker run --name=gogs -p 10022:22 -p 10080:3000 -v /var/gogs:/data gogs/gogs
|
||||
$ docker start gogs
|
||||
```
|
||||
|
||||
Note: It is important to map the Gogs ssh service from the container to the host and set the appropriate SSH Port and URI settings when setting up Gogs for the first time. To access and clone Gogs Git repositories with the above configuration you would use: `git clone ssh://git@hostname:10022/username/myrepo.git` for example.
|
||||
|
||||
Files will be store in local path `/var/gogs` in my case.
|
||||
|
||||
Directory `/var/gogs` keeps Git repositories and Gogs data:
|
||||
@@ -33,7 +35,6 @@ Directory `/var/gogs` keeps Git repositories and Gogs data:
|
||||
|-- conf
|
||||
|-- data
|
||||
|-- log
|
||||
|-- templates
|
||||
|
||||
### Volume with data container
|
||||
|
||||
@@ -42,22 +43,57 @@ 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
|
||||
|
||||
```
|
||||
# Create docker volume.
|
||||
$ docker volume create --name gogs-data
|
||||
|
||||
# Use `docker run` for the first time.
|
||||
$ docker run --name=gogs -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
### Application
|
||||
|
||||
Most of settings are obvious and easy to understand, but there are some settings can be confusing by running Gogs inside Docker:
|
||||
|
||||
- **Repository Root Path**: keep it as default value `/home/git/gogs-repositories` because `start.sh` already made a symbolic link for you.
|
||||
- **Run User**: keep it as default value `git` because `start.sh` already setup a user with name `git`.
|
||||
- **Domain**: fill in with Docker container IP(e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
|
||||
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, but you expose it by `10022:22`, then use `10022` for this value.
|
||||
- **Domain**: fill in with Docker container IP (e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
|
||||
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, but you expose it by `10022:22`, then use `10022` for this value. **Builtin SSH server is not recommended inside Docker Container**
|
||||
- **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/`).
|
||||
- **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values (e.g. `http://192.168.99.100:10080/`).
|
||||
|
||||
Full documentation of settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
|
||||
Full documentation of application settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
|
||||
|
||||
### Container options
|
||||
|
||||
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
|
||||
|
||||
@@ -72,4 +108,4 @@ Steps to upgrade Gogs with Docker:
|
||||
|
||||
## Known Issues
|
||||
|
||||
- `.dockerignore` seems to be ignored during Docker Hub Automated build
|
||||
- The docker container can not currently be build on Raspberry 1 (armv6l) as our base image `alpine` does not have a `go` package available for this platform.
|
||||
|
||||
@@ -5,22 +5,31 @@ set -e
|
||||
# Set temp environment vars
|
||||
export GOPATH=/tmp/go
|
||||
export PATH=${PATH}:${GOPATH}/bin
|
||||
export GO15VENDOREXPERIMENT=1
|
||||
|
||||
# Install build deps
|
||||
apk -U --no-progress add linux-pam-dev go@community 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 redis memcache cert pam"
|
||||
go build -tags "sqlite redis memcache 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 linux-pam-dev go gcc musl-dev
|
||||
apk --no-progress del build-deps
|
||||
|
||||
# Create git user for Gogs
|
||||
adduser -H -D -g 'Gogs Git User' git -h /data/git -s /bin/bash && passwd -u git
|
||||
|
||||
16
docker/nsswitch.conf
Normal file
16
docker/nsswitch.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
# /etc/nsswitch.conf
|
||||
|
||||
passwd: compat
|
||||
group: compat
|
||||
shadow: compat
|
||||
|
||||
hosts: files dns
|
||||
networks: files
|
||||
|
||||
protocols: db files
|
||||
services: db files
|
||||
ethers: db files
|
||||
rpc: db files
|
||||
|
||||
netgroup: nis
|
||||
|
||||
0
docker/s6/crond/down
Normal file
0
docker/s6/crond/down
Normal file
9
docker/s6/crond/run
Executable file
9
docker/s6/crond/run
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Crontabs are located by default in /var/spool/cron/crontabs/
|
||||
# The default configuration is also calling all the scripts in /etc/periodic/${period}
|
||||
|
||||
if test -f ./setup; then
|
||||
source ./setup
|
||||
fi
|
||||
|
||||
exec gosu root /usr/sbin/crond -fS
|
||||
@@ -1,10 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check if host keys are present, else create them
|
||||
if ! test -f /data/ssh/ssh_host_key; then
|
||||
ssh-keygen -q -f /data/ssh/ssh_host_key -N '' -t rsa1
|
||||
fi
|
||||
|
||||
if ! test -f /data/ssh/ssh_host_rsa_key; then
|
||||
ssh-keygen -q -f /data/ssh/ssh_host_rsa_key -N '' -t rsa
|
||||
fi
|
||||
|
||||
@@ -4,7 +4,6 @@ ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
Protocol 2
|
||||
LogLevel INFO
|
||||
HostKey /data/ssh/ssh_host_key
|
||||
HostKey /data/ssh/ssh_host_rsa_key
|
||||
HostKey /data/ssh/ssh_host_dsa_key
|
||||
HostKey /data/ssh/ssh_host_ecdsa_key
|
||||
|
||||
@@ -48,6 +48,15 @@ else
|
||||
create_socat_links
|
||||
fi
|
||||
|
||||
CROND=$(echo "$RUN_CROND" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "$CROND" = "true" -o "$CROND" = "1" ]; then
|
||||
echo "init:crond | Cron Daemon (crond) will be run as requested by s6" 1>&2
|
||||
rm -f /app/gogs/docker/s6/crond/down
|
||||
else
|
||||
# Tell s6 not to run the crond service
|
||||
touch /app/gogs/docker/s6/crond/down
|
||||
fi
|
||||
|
||||
# Exec CMD or S6 by default if nothing present
|
||||
if [ $# -gt 0 ];then
|
||||
exec "$@"
|
||||
|
||||
148
glide.lock
generated
Normal file
148
glide.lock
generated
Normal file
@@ -0,0 +1,148 @@
|
||||
hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
|
||||
updated: 2016-06-12T17:35:14.27036884+08:00
|
||||
imports:
|
||||
- name: github.com/bradfitz/gomemcache
|
||||
version: fb1f79c6b65acda83063cbc69f6bba1522558bfc
|
||||
subpackages:
|
||||
- memcache
|
||||
- name: github.com/codegangsta/cli
|
||||
version: 1efa31f08b9333f1bd4882d61f9d668a70cd902e
|
||||
- name: github.com/go-macaron/binding
|
||||
version: 9440f336b443056c90d7d448a0a55ad8c7599880
|
||||
- name: github.com/go-macaron/cache
|
||||
version: 56173531277692bc2925924d51fda1cd0a6b8178
|
||||
subpackages:
|
||||
- memcache
|
||||
- redis
|
||||
- name: github.com/go-macaron/captcha
|
||||
version: 8aa5919789ab301e865595eb4b1114d6b9847deb
|
||||
- name: github.com/go-macaron/csrf
|
||||
version: 6a9a7df172cc1fcd81e4585f44b09200b6087cc0
|
||||
- name: github.com/go-macaron/gzip
|
||||
version: cad1c6580a07c56f5f6bc52d66002a05985c5854
|
||||
- name: github.com/go-macaron/i18n
|
||||
version: ef57533c3b0fc2d8581deda14937e52f11a203ab
|
||||
- name: github.com/go-macaron/inject
|
||||
version: c5ab7bf3a307593cd44cb272d1a5beea473dd072
|
||||
- name: github.com/go-macaron/session
|
||||
version: 66031fcb37a0fff002a1f028eb0b3a815c78306b
|
||||
subpackages:
|
||||
- redis
|
||||
- name: github.com/go-macaron/toolbox
|
||||
version: 82b511550b0aefc36b3a28062ad3a52e812bee38
|
||||
- name: github.com/go-sql-driver/mysql
|
||||
version: 3654d25ec346ee8ce71a68431025458d52a38ac0
|
||||
- name: github.com/go-xorm/core
|
||||
version: bc1b7f81f0e369289078424064634a5ee7d21051
|
||||
- name: github.com/go-xorm/xorm
|
||||
version: b8b1711cde4d9c68da95cd0ff8de0de0cb491df3
|
||||
- name: github.com/gogits/chardet
|
||||
version: 2404f777256163ea3eadb273dada5dcb037993c0
|
||||
- name: github.com/gogits/cron
|
||||
version: 96040e4fab17baa0391ce571694e4ccb5fce5dac
|
||||
- name: github.com/gogits/git-module
|
||||
version: db93fa550116997bbe0b62baa653b8e6f4135258
|
||||
- name: github.com/gogits/go-gogs-client
|
||||
version: ee68cd9eefff11615f336e9965762f6736eeecc8
|
||||
- name: github.com/issue9/identicon
|
||||
version: d36b54562f4cf70c83653e13dc95c220c79ef521
|
||||
- name: github.com/jaytaylor/html2text
|
||||
version: 52d9b785554a1918cb09909b89a1509a98b853fd
|
||||
- name: github.com/kardianos/minwinsvc
|
||||
version: cad6b2b879b0970e4245a20ebf1a81a756e2bb70
|
||||
- name: github.com/klauspost/compress
|
||||
version: 14eb9c4951195779ecfbec34431a976de7335b0a
|
||||
subpackages:
|
||||
- gzip
|
||||
- flate
|
||||
- name: github.com/klauspost/cpuid
|
||||
version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
|
||||
- name: github.com/klauspost/crc32
|
||||
version: 19b0b332c9e4516a6370a0456e6182c3b5036720
|
||||
- name: github.com/lib/pq
|
||||
version: ee1442bda7bd1b6a84e913bdb421cb1874ec629d
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/mattn/go-sqlite3
|
||||
version: 38ee283dabf11c9cbdb968eebd79b1fa7acbabe6
|
||||
- name: github.com/mcuadros/go-version
|
||||
version: d52711f8d6bea8dc01efafdb68ad95a4e2606630
|
||||
- name: github.com/microcosm-cc/bluemonday
|
||||
version: 4ac6f27528d0a3f2a59e0b0a6f6b3ff0bb89fe20
|
||||
- name: github.com/msteinert/pam
|
||||
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
|
||||
- name: github.com/nfnt/resize
|
||||
version: 4d93a29130b1b6aba503e2aa8b50f516213ea80e
|
||||
- name: github.com/russross/blackfriday
|
||||
version: 4e6f303e8d936855981ddcdbfc092b03d2b2b68e
|
||||
- name: github.com/satori/go.uuid
|
||||
version: 879c5887cd475cd7864858769793b2ceb0d44feb
|
||||
- name: github.com/sergi/go-diff
|
||||
version: ec7fdbb58eb3e300c8595ad5ac74a5aa50019cc7
|
||||
subpackages:
|
||||
- diffmatchpatch
|
||||
- name: github.com/shurcooL/sanitized_anchor_name
|
||||
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
||||
- name: github.com/Unknwon/cae
|
||||
version: 7f5e046bc8a6c3cde743c233b96ee4fd84ee6ecd
|
||||
subpackages:
|
||||
- zip
|
||||
- name: github.com/Unknwon/com
|
||||
version: 28b053d5a2923b87ce8c5a08f3af779894a72758
|
||||
- name: github.com/Unknwon/i18n
|
||||
version: 39d6f2727e0698b1021ceb6a77c1801aa92e7d5d
|
||||
- name: github.com/Unknwon/paginater
|
||||
version: 7748a72e01415173a27d79866b984328e7b0c12b
|
||||
- name: golang.org/x/crypto
|
||||
version: 77f4136a99ffb5ecdbdd0226bd5cb146cf56bc0e
|
||||
subpackages:
|
||||
- ssh
|
||||
- curve25519
|
||||
- ed25519
|
||||
- ed25519/internal/edwards25519
|
||||
- name: golang.org/x/net
|
||||
version: 3f122ce3dbbe488b7e6a8bdb26f41edec852a40b
|
||||
subpackages:
|
||||
- html
|
||||
- html/charset
|
||||
- html/atom
|
||||
- name: golang.org/x/sys
|
||||
version: 7f918dd405547ecb864d14a8ecbbfe205b5f930f
|
||||
subpackages:
|
||||
- windows/svc
|
||||
- windows
|
||||
- name: golang.org/x/text
|
||||
version: e4775119bd79944a15a741ac4be61e43509a70d9
|
||||
subpackages:
|
||||
- transform
|
||||
- language
|
||||
- encoding
|
||||
- encoding/charmap
|
||||
- encoding/htmlindex
|
||||
- internal/tag
|
||||
- encoding/internal/identifier
|
||||
- encoding/internal
|
||||
- encoding/japanese
|
||||
- encoding/korean
|
||||
- encoding/simplifiedchinese
|
||||
- encoding/traditionalchinese
|
||||
- encoding/unicode
|
||||
- internal/utf8internal
|
||||
- runes
|
||||
- name: gopkg.in/alexcesaro/quotedprintable.v3
|
||||
version: 2caba252f4dc53eaf6b553000885530023f54623
|
||||
- name: gopkg.in/asn1-ber.v1
|
||||
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
|
||||
- name: gopkg.in/bufio.v1
|
||||
version: 567b2bfa514e796916c4747494d6ff5132a1dfce
|
||||
- name: gopkg.in/gomail.v2
|
||||
version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
|
||||
- name: gopkg.in/ini.v1
|
||||
version: 72ba3e6b9e6b87e0c74c9a7a4dc86e8dd8ba4355
|
||||
- name: gopkg.in/ldap.v2
|
||||
version: 0e7db8eb77695b5a952f0e5d78df9ab160050c73
|
||||
- name: gopkg.in/macaron.v1
|
||||
version: 2133042f8d1022b8253e4e23f7940467941409ce
|
||||
- name: gopkg.in/redis.v2
|
||||
version: e6179049628164864e6e84e973cfb56335748dea
|
||||
devImports: []
|
||||
57
glide.yaml
Normal file
57
glide.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
package: github.com/gogits/gogs
|
||||
import:
|
||||
- package: github.com/Unknwon/cae
|
||||
subpackages:
|
||||
- zip
|
||||
- package: github.com/Unknwon/com
|
||||
- package: github.com/Unknwon/i18n
|
||||
- package: github.com/Unknwon/paginater
|
||||
- package: github.com/codegangsta/cli
|
||||
- package: github.com/go-macaron/binding
|
||||
- package: github.com/go-macaron/cache
|
||||
subpackages:
|
||||
- memcache
|
||||
- redis
|
||||
- package: github.com/go-macaron/captcha
|
||||
- package: github.com/go-macaron/csrf
|
||||
- package: github.com/go-macaron/gzip
|
||||
- package: github.com/go-macaron/i18n
|
||||
- package: github.com/go-macaron/session
|
||||
subpackages:
|
||||
- redis
|
||||
- package: github.com/go-macaron/toolbox
|
||||
- package: github.com/go-sql-driver/mysql
|
||||
- package: github.com/go-xorm/core
|
||||
- package: github.com/go-xorm/xorm
|
||||
- package: github.com/gogits/chardet
|
||||
- package: github.com/gogits/cron
|
||||
- package: github.com/gogits/git-module
|
||||
- package: github.com/gogits/go-gogs-client
|
||||
- package: github.com/issue9/identicon
|
||||
- package: github.com/kardianos/minwinsvc
|
||||
- package: github.com/lib/pq
|
||||
- package: github.com/mattn/go-sqlite3
|
||||
- package: github.com/mcuadros/go-version
|
||||
- package: github.com/microcosm-cc/bluemonday
|
||||
- package: github.com/msteinert/pam
|
||||
- package: github.com/nfnt/resize
|
||||
- package: github.com/russross/blackfriday
|
||||
- package: github.com/satori/go.uuid
|
||||
- package: github.com/sergi/go-diff
|
||||
subpackages:
|
||||
- diffmatchpatch
|
||||
- package: golang.org/x/crypto
|
||||
subpackages:
|
||||
- ssh
|
||||
- package: golang.org/x/net
|
||||
subpackages:
|
||||
- html
|
||||
- html/charset
|
||||
- package: golang.org/x/text
|
||||
subpackages:
|
||||
- transform
|
||||
- language
|
||||
- package: gopkg.in/gomail.v2
|
||||
- package: gopkg.in/ini.v1
|
||||
- package: gopkg.in/ldap.v2
|
||||
- package: gopkg.in/macaron.v1
|
||||
4
gogs.go
4
gogs.go
@@ -1,4 +1,4 @@
|
||||
// +build go1.3
|
||||
// +build go1.4
|
||||
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.7.19.1121 Beta"
|
||||
const APP_VER = "0.9.46.0717"
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
@@ -13,13 +13,40 @@ import (
|
||||
type AccessMode int
|
||||
|
||||
const (
|
||||
ACCESS_MODE_NONE AccessMode = iota
|
||||
ACCESS_MODE_READ
|
||||
ACCESS_MODE_WRITE
|
||||
ACCESS_MODE_ADMIN
|
||||
ACCESS_MODE_OWNER
|
||||
ACCESS_MODE_NONE AccessMode = iota // 0
|
||||
ACCESS_MODE_READ // 1
|
||||
ACCESS_MODE_WRITE // 2
|
||||
ACCESS_MODE_ADMIN // 3
|
||||
ACCESS_MODE_OWNER // 4
|
||||
)
|
||||
|
||||
func (mode AccessMode) String() string {
|
||||
switch mode {
|
||||
case ACCESS_MODE_READ:
|
||||
return "read"
|
||||
case ACCESS_MODE_WRITE:
|
||||
return "write"
|
||||
case ACCESS_MODE_ADMIN:
|
||||
return "admin"
|
||||
case ACCESS_MODE_OWNER:
|
||||
return "owner"
|
||||
default:
|
||||
return "none"
|
||||
}
|
||||
}
|
||||
|
||||
// ParseAccessMode returns corresponding access mode to given permission string.
|
||||
func ParseAccessMode(permission string) AccessMode {
|
||||
switch permission {
|
||||
case "write":
|
||||
return ACCESS_MODE_WRITE
|
||||
case "admin":
|
||||
return ACCESS_MODE_ADMIN
|
||||
default:
|
||||
return ACCESS_MODE_READ
|
||||
}
|
||||
}
|
||||
|
||||
// Access represents the highest access level of a user to the repository. The only access type
|
||||
// that is not in this table is the real owner of a repository. In case of an organization
|
||||
// repository, the members of the owners team are in this table.
|
||||
@@ -110,7 +137,7 @@ func (u *User) GetAccessibleRepositories() ([]*Repository, error) {
|
||||
repoIDs = append(repoIDs, access.RepoID)
|
||||
}
|
||||
repos := make([]*Repository, 0, len(repoIDs))
|
||||
return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated").Find(&repos)
|
||||
return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated_unix").Find(&repos)
|
||||
}
|
||||
|
||||
func maxAccessMode(modes ...AccessMode) AccessMode {
|
||||
@@ -151,15 +178,14 @@ func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]AccessMode
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: should be able to have read-only access.
|
||||
// Give all collaborators write access.
|
||||
// refreshCollaboratorAccesses retrieves repository collaborations with their access modes.
|
||||
func (repo *Repository) refreshCollaboratorAccesses(e Engine, accessMap map[int64]AccessMode) error {
|
||||
collaborators, err := repo.getCollaborators(e)
|
||||
collaborations, err := repo.getCollaborations(e)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getCollaborators: %v", err)
|
||||
return fmt.Errorf("getCollaborations: %v", err)
|
||||
}
|
||||
for _, c := range collaborators {
|
||||
accessMap[c.Id] = ACCESS_MODE_WRITE
|
||||
for _, c := range collaborations {
|
||||
accessMap[c.UserID] = c.Mode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
195
models/action.go
195
models/action.go
@@ -17,10 +17,10 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
@@ -28,17 +28,21 @@ import (
|
||||
type ActionType int
|
||||
|
||||
const (
|
||||
CREATE_REPO ActionType = iota + 1 // 1
|
||||
RENAME_REPO // 2
|
||||
STAR_REPO // 3
|
||||
FOLLOW_REPO // 4
|
||||
COMMIT_REPO // 5
|
||||
CREATE_ISSUE // 6
|
||||
CREATE_PULL_REQUEST // 7
|
||||
TRANSFER_REPO // 8
|
||||
PUSH_TAG // 9
|
||||
COMMENT_ISSUE // 10
|
||||
MERGE_PULL_REQUEST // 11
|
||||
ACTION_CREATE_REPO ActionType = iota + 1 // 1
|
||||
ACTION_RENAME_REPO // 2
|
||||
ACTION_STAR_REPO // 3
|
||||
ACTION_WATCH_REPO // 4
|
||||
ACTION_COMMIT_REPO // 5
|
||||
ACTION_CREATE_ISSUE // 6
|
||||
ACTION_CREATE_PULL_REQUEST // 7
|
||||
ACTION_TRANSFER_REPO // 8
|
||||
ACTION_PUSH_TAG // 9
|
||||
ACTION_COMMENT_ISSUE // 10
|
||||
ACTION_MERGE_PULL_REQUEST // 11
|
||||
ACTION_CLOSE_ISSUE // 12
|
||||
ACTION_REOPEN_ISSUE // 13
|
||||
ACTION_CLOSE_PULL_REQUEST // 14
|
||||
ACTION_REOPEN_PULL_REQUEST // 15
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -80,64 +84,85 @@ type Action struct {
|
||||
RefName string
|
||||
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Content string `xorm:"TEXT"`
|
||||
Created time.Time `xorm:"created"`
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (a *Action) BeforeInsert() {
|
||||
a.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created":
|
||||
a.Created = regulateTimeZone(a.Created)
|
||||
case "created_unix":
|
||||
a.Created = time.Unix(a.CreatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
func (a Action) GetOpType() int {
|
||||
func (a *Action) GetOpType() int {
|
||||
return int(a.OpType)
|
||||
}
|
||||
|
||||
func (a Action) GetActUserName() string {
|
||||
func (a *Action) GetActUserName() string {
|
||||
return a.ActUserName
|
||||
}
|
||||
|
||||
func (a Action) GetActEmail() string {
|
||||
func (a *Action) ShortActUserName() string {
|
||||
return base.EllipsisString(a.ActUserName, 20)
|
||||
}
|
||||
|
||||
func (a *Action) GetActEmail() string {
|
||||
return a.ActEmail
|
||||
}
|
||||
|
||||
func (a Action) GetRepoUserName() string {
|
||||
func (a *Action) GetRepoUserName() string {
|
||||
return a.RepoUserName
|
||||
}
|
||||
|
||||
func (a Action) GetRepoName() string {
|
||||
func (a *Action) ShortRepoUserName() string {
|
||||
return base.EllipsisString(a.RepoUserName, 20)
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoName() string {
|
||||
return a.RepoName
|
||||
}
|
||||
|
||||
func (a Action) GetRepoPath() string {
|
||||
func (a *Action) ShortRepoName() string {
|
||||
return base.EllipsisString(a.RepoName, 33)
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoPath() string {
|
||||
return path.Join(a.RepoUserName, a.RepoName)
|
||||
}
|
||||
|
||||
func (a Action) GetRepoLink() string {
|
||||
func (a *Action) ShortRepoPath() string {
|
||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoLink() string {
|
||||
if len(setting.AppSubUrl) > 0 {
|
||||
return path.Join(setting.AppSubUrl, a.GetRepoPath())
|
||||
}
|
||||
return "/" + a.GetRepoPath()
|
||||
}
|
||||
|
||||
func (a Action) GetBranch() string {
|
||||
func (a *Action) GetBranch() string {
|
||||
return a.RefName
|
||||
}
|
||||
|
||||
func (a Action) GetContent() string {
|
||||
func (a *Action) GetContent() string {
|
||||
return a.Content
|
||||
}
|
||||
|
||||
func (a Action) GetCreate() time.Time {
|
||||
func (a *Action) GetCreate() time.Time {
|
||||
return a.Created
|
||||
}
|
||||
|
||||
func (a Action) GetIssueInfos() []string {
|
||||
func (a *Action) GetIssueInfos() []string {
|
||||
return strings.SplitN(a.Content, "|", 2)
|
||||
}
|
||||
|
||||
func (a Action) GetIssueTitle() string {
|
||||
func (a *Action) GetIssueTitle() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
@@ -147,7 +172,7 @@ func (a Action) GetIssueTitle() string {
|
||||
return issue.Name
|
||||
}
|
||||
|
||||
func (a Action) GetIssueContent() string {
|
||||
func (a *Action) GetIssueContent() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
@@ -162,7 +187,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
|
||||
ActUserID: u.Id,
|
||||
ActUserName: u.Name,
|
||||
ActEmail: u.Email,
|
||||
OpType: CREATE_REPO,
|
||||
OpType: ACTION_CREATE_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -185,7 +210,7 @@ func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Reposit
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: RENAME_REPO,
|
||||
OpType: ACTION_RENAME_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -229,6 +254,28 @@ 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)
|
||||
if err == nil {
|
||||
author_username = author.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,
|
||||
},
|
||||
}
|
||||
}
|
||||
return commits
|
||||
}
|
||||
|
||||
// AvatarLink tries to match user in database with e-mail
|
||||
// in order to show custom avatar, and falls back to general avatar link.
|
||||
func (push *PushCommits) AvatarLink(email string) string {
|
||||
@@ -328,7 +375,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
continue
|
||||
}
|
||||
|
||||
if err = issue.ChangeStatus(u, true); err != nil {
|
||||
if err = issue.ChangeStatus(u, repo, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -368,7 +415,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
|
||||
continue
|
||||
}
|
||||
|
||||
if err = issue.ChangeStatus(u, false); err != nil {
|
||||
if err = issue.ChangeStatus(u, repo, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -405,23 +452,19 @@ func CommitRepoAction(
|
||||
}
|
||||
|
||||
isNewBranch := false
|
||||
opType := COMMIT_REPO
|
||||
opType := ACTION_COMMIT_REPO
|
||||
// Check it's tag push or branch.
|
||||
if strings.HasPrefix(refFullName, "refs/tags/") {
|
||||
opType = PUSH_TAG
|
||||
opType = ACTION_PUSH_TAG
|
||||
commit = &PushCommits{}
|
||||
} else {
|
||||
// if not the first commit, set the compareUrl
|
||||
if !strings.HasPrefix(oldCommitID, "0000000") {
|
||||
commit.CompareUrl = fmt.Sprintf("%s/%s/compare/%s...%s", repoUserName, repoName, oldCommitID, newCommitID)
|
||||
commit.CompareUrl = repo.ComposeCompareURL(oldCommitID, newCommitID)
|
||||
} else {
|
||||
isNewBranch = true
|
||||
}
|
||||
|
||||
// NOTE: limit to detect latest 100 commits.
|
||||
if len(commit.Commits) > 100 {
|
||||
commit.Commits = commit.Commits[len(commit.Commits)-100:]
|
||||
}
|
||||
if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil {
|
||||
log.Error(4, "updateIssuesCommit: %v", err)
|
||||
}
|
||||
@@ -446,29 +489,14 @@ func CommitRepoAction(
|
||||
Content: string(bs),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repoUserName,
|
||||
RepoName: repoName,
|
||||
RepoName: repo.Name,
|
||||
RefName: refName,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers: %v", err)
|
||||
|
||||
}
|
||||
|
||||
repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
|
||||
payloadRepo := &api.PayloadRepo{
|
||||
ID: repo.ID,
|
||||
Name: repo.LowerName,
|
||||
URL: repoLink,
|
||||
Description: repo.Description,
|
||||
Website: repo.Website,
|
||||
Watchers: repo.NumWatches,
|
||||
Owner: &api.PayloadAuthor{
|
||||
Name: repo.Owner.DisplayName(),
|
||||
Email: repo.Owner.Email,
|
||||
UserName: repo.Owner.Name,
|
||||
},
|
||||
Private: repo.IsPrivate,
|
||||
}
|
||||
payloadRepo := repo.ComposePayload()
|
||||
|
||||
pusher_email, pusher_name := "", ""
|
||||
pusher, err := GetUserByName(userName)
|
||||
@@ -479,35 +507,17 @@ func CommitRepoAction(
|
||||
payloadSender := &api.PayloadUser{
|
||||
UserName: pusher.Name,
|
||||
ID: pusher.Id,
|
||||
AvatarUrl: setting.AppUrl + pusher.RelAvatarLink(),
|
||||
AvatarUrl: pusher.AvatarLink(),
|
||||
}
|
||||
|
||||
switch opType {
|
||||
case COMMIT_REPO: // Push
|
||||
commits := make([]*api.PayloadCommit, len(commit.Commits))
|
||||
for i, cmt := range commit.Commits {
|
||||
author_username := ""
|
||||
author, err := GetUserByEmail(cmt.AuthorEmail)
|
||||
if err == nil {
|
||||
author_username = author.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,
|
||||
},
|
||||
}
|
||||
}
|
||||
case ACTION_COMMIT_REPO: // Push
|
||||
p := &api.PushPayload{
|
||||
Ref: refFullName,
|
||||
Before: oldCommitID,
|
||||
After: newCommitID,
|
||||
CompareUrl: setting.AppUrl + commit.CompareUrl,
|
||||
Commits: commits,
|
||||
Commits: commit.ToApiPayloadCommits(repo.FullLink()),
|
||||
Repo: payloadRepo,
|
||||
Pusher: &api.PayloadAuthor{
|
||||
Name: pusher_name,
|
||||
@@ -529,7 +539,7 @@ func CommitRepoAction(
|
||||
})
|
||||
}
|
||||
|
||||
case PUSH_TAG: // Create
|
||||
case ACTION_PUSH_TAG: // Create
|
||||
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
@@ -546,12 +556,12 @@ func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repos
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: TRANSFER_REPO,
|
||||
OpType: ACTION_TRANSFER_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: newOwner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
Content: path.Join(oldOwner.LowerName, repo.LowerName),
|
||||
Content: path.Join(oldOwner.Name, repo.Name),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("notify watchers '%d/%d': %v", actUser.Id, repo.ID, err)
|
||||
}
|
||||
@@ -577,7 +587,7 @@ func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Iss
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: MERGE_PULL_REQUEST,
|
||||
OpType: ACTION_MERGE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
@@ -592,12 +602,29 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
|
||||
}
|
||||
|
||||
// GetFeeds returns action list of given user in given context.
|
||||
func GetFeeds(uid, offset int64, isProfile bool) ([]*Action, error) {
|
||||
// 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) {
|
||||
actions := make([]*Action, 0, 20)
|
||||
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid)
|
||||
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", ctxUserID)
|
||||
if isProfile {
|
||||
sess.And("is_private=?", false).And("act_user_id=?", uid)
|
||||
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
|
||||
}
|
||||
|
||||
var repoIDs []int64
|
||||
for _, repo := range ctxUser.Repos {
|
||||
repoIDs = append(repoIDs, repo.ID)
|
||||
}
|
||||
|
||||
if len(repoIDs) > 0 {
|
||||
sess.In("repo_id", repoIDs)
|
||||
}
|
||||
}
|
||||
|
||||
err := sess.Find(&actions)
|
||||
return actions, err
|
||||
}
|
||||
|
||||
@@ -5,9 +5,18 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
type NoticeType int
|
||||
@@ -18,10 +27,22 @@ const (
|
||||
|
||||
// Notice represents a system notice for admin.
|
||||
type Notice struct {
|
||||
Id int64
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type NoticeType
|
||||
Description string `xorm:"TEXT"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (n *Notice) BeforeInsert() {
|
||||
n.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (n *Notice) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created_unix":
|
||||
n.Created = time.Unix(n.CreatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
// TrStr returns a translation format string.
|
||||
@@ -31,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,
|
||||
@@ -44,6 +70,30 @@ func CreateRepositoryNotice(desc string) error {
|
||||
return CreateNotice(NOTICE_REPOSITORY, desc)
|
||||
}
|
||||
|
||||
// RemoveAllWithNotice removes all directories in given path and
|
||||
// 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)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CountNotices returns number of notices.
|
||||
func CountNotices() int64 {
|
||||
count, _ := x.Count(new(Notice))
|
||||
@@ -61,3 +111,22 @@ func DeleteNotice(id int64) error {
|
||||
_, err := x.Id(id).Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteNotices deletes all notices with ID from start to end (inclusive).
|
||||
func DeleteNotices(start, end int64) error {
|
||||
sess := x.Where("id >= ?", start)
|
||||
if end > 0 {
|
||||
sess.And("id <= ?", end)
|
||||
}
|
||||
_, err := sess.Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteNoticesByIDs deletes notices by given IDs.
|
||||
func DeleteNoticesByIDs(ids []int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := x.Where("id IN (" + strings.Join(base.Int64sToStrings(ids), ",") + ")").Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/cron"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var c = cron.New()
|
||||
|
||||
func NewContext() {
|
||||
var (
|
||||
entry *cron.Entry
|
||||
err error
|
||||
)
|
||||
if setting.Cron.UpdateMirror.Enabled {
|
||||
entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Update mirrors]: %v", err)
|
||||
}
|
||||
if setting.Cron.UpdateMirror.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.MirrorUpdate()
|
||||
}
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.Enabled {
|
||||
entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Repository health check]: %v", err)
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.GitFsck()
|
||||
}
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.Enabled {
|
||||
entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Check repository statistics]: %v", err)
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.CheckRepoStats()
|
||||
}
|
||||
}
|
||||
c.Start()
|
||||
}
|
||||
|
||||
// ListTasks returns all running cron tasks.
|
||||
func ListTasks() []*cron.Entry {
|
||||
return c.Entries()
|
||||
}
|
||||
122
models/error.go
122
models/error.go
@@ -107,6 +107,39 @@ func (err ErrUserHasOrgs) Error() string {
|
||||
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID)
|
||||
}
|
||||
|
||||
type ErrReachLimitOfRepo struct {
|
||||
Limit int
|
||||
}
|
||||
|
||||
func IsErrReachLimitOfRepo(err error) bool {
|
||||
_, ok := err.(ErrReachLimitOfRepo)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrReachLimitOfRepo) Error() string {
|
||||
return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit)
|
||||
}
|
||||
|
||||
// __ __.__ __ .__
|
||||
// / \ / \__| | _|__|
|
||||
// \ \/\/ / | |/ / |
|
||||
// \ /| | <| |
|
||||
// \__/\ / |__|__|_ \__|
|
||||
// \/ \/
|
||||
|
||||
type ErrWikiAlreadyExist struct {
|
||||
Title string
|
||||
}
|
||||
|
||||
func IsErrWikiAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrWikiAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrWikiAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("wiki page already exists [title: %s]", err.Title)
|
||||
}
|
||||
|
||||
// __________ ___. .__ .__ ____ __.
|
||||
// \______ \__ _\_ |__ | | |__| ____ | |/ _|____ ___.__.
|
||||
// | ___/ | \ __ \| | | |/ ___\ | <_/ __ < | |
|
||||
@@ -168,6 +201,22 @@ func (err ErrKeyNameAlreadyUsed) Error() string {
|
||||
return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name)
|
||||
}
|
||||
|
||||
type ErrKeyAccessDenied struct {
|
||||
UserID int64
|
||||
KeyID int64
|
||||
Note string
|
||||
}
|
||||
|
||||
func IsErrKeyAccessDenied(err error) bool {
|
||||
_, ok := err.(ErrKeyAccessDenied)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrKeyAccessDenied) Error() string {
|
||||
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]",
|
||||
err.UserID, err.KeyID, err.Note)
|
||||
}
|
||||
|
||||
type ErrDeployKeyNotExist struct {
|
||||
ID int64
|
||||
KeyID int64
|
||||
@@ -231,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")
|
||||
}
|
||||
|
||||
// ________ .__ __ .__
|
||||
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
|
||||
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
|
||||
@@ -343,6 +404,26 @@ func (err ErrReleaseNotExist) Error() string {
|
||||
return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
// \______ \____________ ____ ____ | |__
|
||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||
// | | \ | | \// __ \| | \ \___| Y \
|
||||
// |______ / |__| (____ /___| /\___ >___| /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type ErrBranchNotExist struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrBranchNotExist(err error) bool {
|
||||
_, ok := err.(ErrBranchNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrBranchNotExist) Error() string {
|
||||
return fmt.Sprintf("Branch does not exist [name: %s]", err.Name)
|
||||
}
|
||||
|
||||
// __ __ ___. .__ __
|
||||
// / \ / \ ____\_ |__ | |__ ____ ____ | | __
|
||||
// \ \/\/ // __ \| __ \| | \ / _ \ / _ \| |/ /
|
||||
@@ -492,3 +573,44 @@ func IsErrAttachmentNotExist(err error) bool {
|
||||
func (err ErrAttachmentNotExist) Error() string {
|
||||
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
||||
}
|
||||
|
||||
// _____ __ .__ __ .__ __ .__
|
||||
// / _ \ __ ___/ |_| |__ ____ _____/ |_|__| ____ _____ _/ |_|__| ____ ____
|
||||
// / /_\ \| | \ __\ | \_/ __ \ / \ __\ |/ ___\\__ \\ __\ |/ _ \ / \
|
||||
// / | \ | /| | | Y \ ___/| | \ | | \ \___ / __ \| | | ( <_> ) | \
|
||||
// \____|__ /____/ |__| |___| /\___ >___| /__| |__|\___ >____ /__| |__|\____/|___| /
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
|
||||
type ErrAuthenticationNotExist struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func IsErrAuthenticationNotExist(err error) bool {
|
||||
_, ok := err.(ErrAuthenticationNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrAuthenticationNotExist) Error() string {
|
||||
return fmt.Sprintf("authentication does not exist [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
// ___________
|
||||
// \__ ___/___ _____ _____
|
||||
// | |_/ __ \\__ \ / \
|
||||
// | |\ ___/ / __ \| Y Y \
|
||||
// |____| \___ >____ /__|_| /
|
||||
// \/ \/ \/
|
||||
|
||||
type ErrTeamAlreadyExist struct {
|
||||
OrgID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrTeamAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrTeamAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrTeamAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
|
||||
}
|
||||
|
||||
@@ -8,33 +8,40 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"golang.org/x/net/html/charset"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/template/highlight"
|
||||
)
|
||||
|
||||
// Diff line types.
|
||||
type DiffLineType uint8
|
||||
|
||||
const (
|
||||
DIFF_LINE_PLAIN = iota + 1
|
||||
DIFF_LINE_PLAIN DiffLineType = iota + 1
|
||||
DIFF_LINE_ADD
|
||||
DIFF_LINE_DEL
|
||||
DIFF_LINE_SECTION
|
||||
)
|
||||
|
||||
type DiffFileType uint8
|
||||
|
||||
const (
|
||||
DIFF_FILE_ADD = iota + 1
|
||||
DIFF_FILE_ADD DiffFileType = iota + 1
|
||||
DIFF_FILE_CHANGE
|
||||
DIFF_FILE_DEL
|
||||
DIFF_FILE_RENAME
|
||||
@@ -43,12 +50,12 @@ const (
|
||||
type DiffLine struct {
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
}
|
||||
|
||||
func (d DiffLine) GetType() int {
|
||||
return d.Type
|
||||
func (d *DiffLine) GetType() int {
|
||||
return int(d.Type)
|
||||
}
|
||||
|
||||
type DiffSection struct {
|
||||
@@ -56,22 +63,119 @@ type DiffSection struct {
|
||||
Lines []*DiffLine
|
||||
}
|
||||
|
||||
var (
|
||||
addedCodePrefix = []byte("<span class=\"added-code\">")
|
||||
removedCodePrefix = []byte("<span class=\"removed-code\">")
|
||||
codeTagSuffix = []byte("</span>")
|
||||
)
|
||||
|
||||
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
|
||||
var buf bytes.Buffer
|
||||
for i := range diffs {
|
||||
if 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 {
|
||||
buf.Write(removedCodePrefix)
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
buf.Write(codeTagSuffix)
|
||||
} else if diffs[i].Type == diffmatchpatch.DiffEqual {
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
}
|
||||
}
|
||||
|
||||
return template.HTML(buf.Bytes())
|
||||
}
|
||||
|
||||
// get an specific line by type (add or del) and file line number
|
||||
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
|
||||
difference := 0
|
||||
|
||||
for _, diffLine := range diffSection.Lines {
|
||||
if diffLine.Type == DIFF_LINE_PLAIN {
|
||||
// get the difference of line numbers between ADD and DEL versions
|
||||
difference = diffLine.RightIdx - diffLine.LeftIdx
|
||||
continue
|
||||
}
|
||||
|
||||
if lineType == DIFF_LINE_DEL {
|
||||
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
|
||||
return diffLine
|
||||
}
|
||||
} else if lineType == DIFF_LINE_ADD {
|
||||
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
|
||||
return diffLine
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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()
|
||||
}
|
||||
|
||||
// try to find equivalent diff line. ignore, otherwise
|
||||
if diffLine.Type == DIFF_LINE_ADD {
|
||||
compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
|
||||
if compareDiffLine == nil {
|
||||
return getDefaultReturn()
|
||||
}
|
||||
diff1 = compareDiffLine.Content
|
||||
diff2 = diffLine.Content
|
||||
} else {
|
||||
compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
|
||||
if compareDiffLine == nil {
|
||||
return getDefaultReturn()
|
||||
}
|
||||
diff1 = diffLine.Content
|
||||
diff2 = compareDiffLine.Content
|
||||
}
|
||||
|
||||
dmp := diffmatchpatch.New()
|
||||
diffRecord := dmp.DiffMain(diff1[1:], diff2[1:], true)
|
||||
diffRecord = dmp.DiffCleanupSemantic(diffRecord)
|
||||
|
||||
return diffToHTML(diffRecord, diffLine.Type)
|
||||
}
|
||||
|
||||
type DiffFile struct {
|
||||
Name string
|
||||
OldName string
|
||||
Index int
|
||||
Addition, Deletion int
|
||||
Type int
|
||||
Type DiffFileType
|
||||
IsCreated bool
|
||||
IsDeleted bool
|
||||
IsBin bool
|
||||
IsRenamed bool
|
||||
Sections []*DiffSection
|
||||
IsIncomplete bool
|
||||
}
|
||||
|
||||
func (diffFile *DiffFile) GetType() int {
|
||||
return int(diffFile.Type)
|
||||
}
|
||||
|
||||
func (diffFile *DiffFile) GetHighlightClass() string {
|
||||
return highlight.FileNameToHighlightClass(diffFile.Name)
|
||||
}
|
||||
|
||||
type Diff struct {
|
||||
TotalAddition, TotalDeletion int
|
||||
Files []*DiffFile
|
||||
IsIncomplete bool
|
||||
}
|
||||
|
||||
func (diff *Diff) NumFiles() int {
|
||||
@@ -80,39 +184,47 @@ func (diff *Diff) NumFiles() int {
|
||||
|
||||
const DIFF_HEAD = "diff --git "
|
||||
|
||||
func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
|
||||
var (
|
||||
diff = &Diff{Files: make([]*DiffFile, 0)}
|
||||
|
||||
curFile *DiffFile
|
||||
curSection = &DiffSection{
|
||||
Lines: make([]*DiffLine, 0, 10),
|
||||
}
|
||||
|
||||
leftLine, rightLine int
|
||||
// FIXME: Should use cache in the future.
|
||||
buf bytes.Buffer
|
||||
lineCount int
|
||||
curFileLinesCount int
|
||||
)
|
||||
|
||||
diff := &Diff{Files: make([]*DiffFile, 0)}
|
||||
var i int
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
input := bufio.NewReader(reader)
|
||||
isEOF := false
|
||||
for !isEOF {
|
||||
line, err := input.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
isEOF = true
|
||||
} else {
|
||||
return nil, fmt.Errorf("ReadString: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
|
||||
if len(line) > 0 && line[len(line)-1] == '\n' {
|
||||
// Remove line break.
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
i = i + 1
|
||||
curFileLinesCount++
|
||||
lineCount++
|
||||
|
||||
// Diff data too large, we only show the first about maxlines lines
|
||||
if i >= maxlines {
|
||||
log.Warn("Diff data too large")
|
||||
diff.Files = nil
|
||||
return diff, nil
|
||||
if curFileLinesCount >= maxLines || len(line) >= maxLineCharacteres {
|
||||
curFile.IsIncomplete = true
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -187,19 +299,34 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
||||
Sections: make([]*DiffSection, 0, 10),
|
||||
}
|
||||
diff.Files = append(diff.Files, curFile)
|
||||
if len(diff.Files) >= maxFiles {
|
||||
diff.IsIncomplete = true
|
||||
io.Copy(ioutil.Discard, reader)
|
||||
break
|
||||
}
|
||||
curFileLinesCount = 0
|
||||
|
||||
// Check file diff type.
|
||||
for scanner.Scan() {
|
||||
for {
|
||||
line, err := input.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
isEOF = true
|
||||
} else {
|
||||
return nil, fmt.Errorf("ReadString: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(scanner.Text(), "new file"):
|
||||
case strings.HasPrefix(line, "new file"):
|
||||
curFile.Type = DIFF_FILE_ADD
|
||||
curFile.IsCreated = true
|
||||
case strings.HasPrefix(scanner.Text(), "deleted"):
|
||||
case strings.HasPrefix(line, "deleted"):
|
||||
curFile.Type = DIFF_FILE_DEL
|
||||
curFile.IsDeleted = true
|
||||
case strings.HasPrefix(scanner.Text(), "index"):
|
||||
case strings.HasPrefix(line, "index"):
|
||||
curFile.Type = DIFF_FILE_CHANGE
|
||||
case strings.HasPrefix(scanner.Text(), "similarity index 100%"):
|
||||
case strings.HasPrefix(line, "similarity index 100%"):
|
||||
curFile.Type = DIFF_FILE_RENAME
|
||||
curFile.IsRenamed = true
|
||||
curFile.OldName = curFile.Name
|
||||
@@ -212,6 +339,8 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: detect encoding while parsing.
|
||||
var buf bytes.Buffer
|
||||
for _, f := range diff.Files {
|
||||
buf.Reset()
|
||||
for _, sec := range f.Sections {
|
||||
@@ -238,63 +367,57 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) {
|
||||
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
|
||||
repo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commit, err := repo.GetCommit(afterCommitId)
|
||||
commit, err := repo.GetCommit(afterCommitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rd, wr := io.Pipe()
|
||||
var cmd *exec.Cmd
|
||||
// if "after" commit given
|
||||
if beforeCommitId == "" {
|
||||
if len(beforeCommitID) == 0 {
|
||||
// First commit of repository.
|
||||
if commit.ParentCount() == 0 {
|
||||
cmd = exec.Command("git", "show", afterCommitId)
|
||||
cmd = exec.Command("git", "show", afterCommitID)
|
||||
} else {
|
||||
c, _ := commit.Parent(0)
|
||||
cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitId)
|
||||
cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitID)
|
||||
}
|
||||
} else {
|
||||
cmd = exec.Command("git", "diff", "-M", beforeCommitId, afterCommitId)
|
||||
cmd = exec.Command("git", "diff", "-M", beforeCommitID, afterCommitID)
|
||||
}
|
||||
cmd.Dir = repoPath
|
||||
cmd.Stdout = wr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
cmd.Start()
|
||||
done <- cmd.Wait()
|
||||
wr.Close()
|
||||
}()
|
||||
defer rd.Close()
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("StdoutPipe: %v", err)
|
||||
}
|
||||
|
||||
desc := fmt.Sprintf("GetDiffRange(%s)", repoPath)
|
||||
pid := process.Add(desc, cmd)
|
||||
go func() {
|
||||
// In case process became zombie.
|
||||
select {
|
||||
case <-time.After(5 * time.Minute):
|
||||
if errKill := process.Kill(pid); errKill != nil {
|
||||
log.Error(4, "git_diff.ParsePatch(Kill): %v", err)
|
||||
}
|
||||
<-done
|
||||
// return "", ErrExecTimeout.Error(), ErrExecTimeout
|
||||
case err = <-done:
|
||||
process.Remove(pid)
|
||||
}
|
||||
}()
|
||||
if err = cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("Start: %v", err)
|
||||
}
|
||||
|
||||
return ParsePatch(pid, maxlines, cmd, rd)
|
||||
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
|
||||
defer process.Remove(pid)
|
||||
|
||||
diff, err := ParsePatch(maxLines, maxLineCharacteres, maxFiles, stdout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ParsePatch: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("Wait: %v", err)
|
||||
}
|
||||
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {
|
||||
return GetDiffRange(repoPath, "", commitId, maxlines)
|
||||
func GetDiffCommit(repoPath, commitId string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
|
||||
return GetDiffRange(repoPath, "", commitId, maxLines, maxLineCharacteres, maxFiles)
|
||||
}
|
||||
|
||||
70
models/git_diff_test.go
Normal file
70
models/git_diff_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
"html/template"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertEqual(t *testing.T, s1 string, s2 template.HTML) {
|
||||
if s1 != string(s2) {
|
||||
t.Errorf("%s should be equal %s", s2, s1)
|
||||
}
|
||||
}
|
||||
|
||||
func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) {
|
||||
if d1 != d2 {
|
||||
t.Errorf("%v should be equal %v", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffToHTML(t *testing.T) {
|
||||
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{
|
||||
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])
|
||||
}
|
||||
949
models/issue.go
949
models/issue.go
File diff suppressed because it is too large
Load Diff
347
models/issue_comment.go
Normal file
347
models/issue_comment.go
Normal file
@@ -0,0 +1,347 @@
|
||||
// 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"
|
||||
|
||||
"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.
|
||||
type CommentType int
|
||||
|
||||
const (
|
||||
// Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
|
||||
COMMENT_TYPE_COMMENT CommentType = iota
|
||||
COMMENT_TYPE_REOPEN
|
||||
COMMENT_TYPE_CLOSE
|
||||
|
||||
// References.
|
||||
COMMENT_TYPE_ISSUE_REF
|
||||
// Reference from a commit (not part of a pull request)
|
||||
COMMENT_TYPE_COMMIT_REF
|
||||
// Reference from a comment
|
||||
COMMENT_TYPE_COMMENT_REF
|
||||
// Reference from a pull request
|
||||
COMMENT_TYPE_PULL_REF
|
||||
)
|
||||
|
||||
type CommentTag int
|
||||
|
||||
const (
|
||||
COMMENT_TAG_NONE CommentTag = iota
|
||||
COMMENT_TAG_POSTER
|
||||
COMMENT_TAG_WRITER
|
||||
COMMENT_TAG_OWNER
|
||||
)
|
||||
|
||||
// Comment represents a comment in commit and issue page.
|
||||
type Comment struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type CommentType
|
||||
PosterID int64
|
||||
Poster *User `xorm:"-"`
|
||||
IssueID int64 `xorm:"INDEX"`
|
||||
CommitID int64
|
||||
Line int64
|
||||
Content string `xorm:"TEXT"`
|
||||
RenderedContent string `xorm:"-"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
|
||||
// Reference issue in commit message
|
||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||
|
||||
Attachments []*Attachment `xorm:"-"`
|
||||
|
||||
// For view issue page.
|
||||
ShowTag CommentTag `xorm:"-"`
|
||||
}
|
||||
|
||||
func (c *Comment) BeforeInsert() {
|
||||
c.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
|
||||
var err error
|
||||
switch colName {
|
||||
case "id":
|
||||
c.Attachments, err = GetAttachmentsByCommentID(c.ID)
|
||||
if err != nil {
|
||||
log.Error(3, "GetAttachmentsByCommentID[%d]: %v", c.ID, err)
|
||||
}
|
||||
|
||||
case "poster_id":
|
||||
c.Poster, err = GetUserByID(c.PosterID)
|
||||
if err != nil {
|
||||
if IsErrUserNotExist(err) {
|
||||
c.PosterID = -1
|
||||
c.Poster = NewFakeUser()
|
||||
} else {
|
||||
log.Error(3, "GetUserByID[%d]: %v", c.ID, err)
|
||||
}
|
||||
}
|
||||
case "created_unix":
|
||||
c.Created = time.Unix(c.CreatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Comment) AfterDelete() {
|
||||
_, err := DeleteAttachmentsByComment(c.ID, true)
|
||||
|
||||
if err != nil {
|
||||
log.Info("Could not delete files for comment %d on issue #%d: %s", c.ID, c.IssueID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// HashTag returns unique hash tag for comment.
|
||||
func (c *Comment) HashTag() string {
|
||||
return "issuecomment-" + com.ToStr(c.ID)
|
||||
}
|
||||
|
||||
// EventTag returns unique event hash tag for comment.
|
||||
func (c *Comment) EventTag() string {
|
||||
return "event-" + com.ToStr(c.ID)
|
||||
}
|
||||
|
||||
// MailParticipants sends new comment emails to repository watchers
|
||||
// and mentioned people.
|
||||
func (cmt *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) {
|
||||
mentions := markdown.FindAllMentions(cmt.Content)
|
||||
if err = UpdateIssueMentions(cmt.IssueID, mentions); err != nil {
|
||||
return fmt.Errorf("UpdateIssueMentions [%d]: %v", cmt.IssueID, err)
|
||||
}
|
||||
|
||||
switch opType {
|
||||
case ACTION_COMMENT_ISSUE:
|
||||
issue.Content = cmt.Content
|
||||
case ACTION_CLOSE_ISSUE:
|
||||
issue.Content = fmt.Sprintf("Closed #%d", issue.Index)
|
||||
case ACTION_REOPEN_ISSUE:
|
||||
issue.Content = fmt.Sprintf("Reopened #%d", issue.Index)
|
||||
}
|
||||
if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil {
|
||||
log.Error(4, "mailIssueCommentToParticipants: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
||||
comment := &Comment{
|
||||
Type: opts.Type,
|
||||
PosterID: opts.Doer.Id,
|
||||
Poster: opts.Doer,
|
||||
IssueID: opts.Issue.ID,
|
||||
CommitID: opts.CommitID,
|
||||
CommitSHA: opts.CommitSHA,
|
||||
Line: opts.LineNum,
|
||||
Content: opts.Content,
|
||||
}
|
||||
if _, err = e.Insert(comment); err != nil {
|
||||
return nil, 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,
|
||||
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,
|
||||
RepoName: opts.Repo.Name,
|
||||
IsPrivate: opts.Repo.IsPrivate,
|
||||
}
|
||||
|
||||
// Check comment type.
|
||||
switch opts.Type {
|
||||
case COMMENT_TYPE_COMMENT:
|
||||
act.OpType = ACTION_COMMENT_ISSUE
|
||||
|
||||
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check attachments
|
||||
attachments := make([]*Attachment, 0, len(opts.Attachments))
|
||||
for _, uuid := range opts.Attachments {
|
||||
attach, err := getAttachmentByUUID(e, uuid)
|
||||
if err != nil {
|
||||
if IsErrAttachmentNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("getAttachmentByUUID [%s]: %v", uuid, err)
|
||||
}
|
||||
attachments = append(attachments, attach)
|
||||
}
|
||||
|
||||
for i := range attachments {
|
||||
attachments[i].IssueID = opts.Issue.ID
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
case COMMENT_TYPE_REOPEN:
|
||||
act.OpType = ACTION_REOPEN_ISSUE
|
||||
if opts.Issue.IsPull {
|
||||
act.OpType = ACTION_REOPEN_PULL_REQUEST
|
||||
}
|
||||
|
||||
if opts.Issue.IsPull {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
|
||||
} else {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case COMMENT_TYPE_CLOSE:
|
||||
act.OpType = ACTION_CLOSE_ISSUE
|
||||
if opts.Issue.IsPull {
|
||||
act.OpType = ACTION_CLOSE_PULL_REQUEST
|
||||
}
|
||||
|
||||
if opts.Issue.IsPull {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
|
||||
} else {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 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
|
||||
}
|
||||
|
||||
func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
|
||||
cmtType := COMMENT_TYPE_CLOSE
|
||||
if !issue.IsClosed {
|
||||
cmtType = COMMENT_TYPE_REOPEN
|
||||
}
|
||||
return createComment(e, &CreateCommentOptions{
|
||||
Type: cmtType,
|
||||
Doer: doer,
|
||||
Repo: repo,
|
||||
Issue: issue,
|
||||
})
|
||||
}
|
||||
|
||||
type CreateCommentOptions struct {
|
||||
Type CommentType
|
||||
Doer *User
|
||||
Repo *Repository
|
||||
Issue *Issue
|
||||
|
||||
CommitID int64
|
||||
CommitSHA string
|
||||
LineNum int64
|
||||
Content string
|
||||
Attachments []string // UUIDs of attachments
|
||||
}
|
||||
|
||||
// CreateComment creates comment of issue or commit.
|
||||
func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment, err = createComment(sess, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return comment, sess.Commit()
|
||||
}
|
||||
|
||||
// CreateIssueComment creates a plain issue comment.
|
||||
func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content string, attachments []string) (*Comment, error) {
|
||||
return CreateComment(&CreateCommentOptions{
|
||||
Type: COMMENT_TYPE_COMMENT,
|
||||
Doer: doer,
|
||||
Repo: repo,
|
||||
Issue: issue,
|
||||
Content: content,
|
||||
Attachments: attachments,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateRefComment creates a commit reference comment to issue.
|
||||
func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commitSHA string) error {
|
||||
if len(commitSHA) == 0 {
|
||||
return fmt.Errorf("cannot create reference with empty commit SHA")
|
||||
}
|
||||
|
||||
// Check if same reference from same commit has already existed.
|
||||
has, err := x.Get(&Comment{
|
||||
Type: COMMENT_TYPE_COMMIT_REF,
|
||||
IssueID: issue.ID,
|
||||
CommitSHA: commitSHA,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("check reference comment: %v", err)
|
||||
} else if has {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = CreateComment(&CreateCommentOptions{
|
||||
Type: COMMENT_TYPE_COMMIT_REF,
|
||||
Doer: doer,
|
||||
Repo: repo,
|
||||
Issue: issue,
|
||||
CommitSHA: commitSHA,
|
||||
Content: content,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetCommentByID returns the comment by given ID.
|
||||
func GetCommentByID(id int64) (*Comment, error) {
|
||||
c := new(Comment)
|
||||
has, err := x.Id(id).Get(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrCommentNotExist{id}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetCommentsByIssueID returns all comments of issue by given ID.
|
||||
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
||||
comments := make([]*Comment, 0, 10)
|
||||
return comments, x.Where("issue_id=?", issueID).Asc("created_unix").Find(&comments)
|
||||
}
|
||||
|
||||
// UpdateComment updates information of comment.
|
||||
func UpdateComment(c *Comment) error {
|
||||
_, err := x.Id(c.ID).AllCols().Update(c)
|
||||
return err
|
||||
}
|
||||
234
models/issue_label.go
Normal file
234
models/issue_label.go
Normal file
@@ -0,0 +1,234 @@
|
||||
// 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"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
// Label represents a label of repository for issues.
|
||||
type Label struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
Name string
|
||||
Color string `xorm:"VARCHAR(7)"`
|
||||
NumIssues int
|
||||
NumClosedIssues int
|
||||
NumOpenIssues int `xorm:"-"`
|
||||
IsChecked bool `xorm:"-"`
|
||||
}
|
||||
|
||||
// CalOpenIssues calculates the open issues of label.
|
||||
func (m *Label) CalOpenIssues() {
|
||||
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
||||
}
|
||||
|
||||
// ForegroundColor calculates the text color for labels based
|
||||
// on their background color.
|
||||
func (l *Label) ForegroundColor() template.CSS {
|
||||
if strings.HasPrefix(l.Color, "#") {
|
||||
if color, err := strconv.ParseUint(l.Color[1:], 16, 64); err == nil {
|
||||
r := float32(0xFF & (color >> 16))
|
||||
g := float32(0xFF & (color >> 8))
|
||||
b := float32(0xFF & color)
|
||||
luminance := (0.2126*r + 0.7152*g + 0.0722*b) / 255
|
||||
|
||||
if luminance < 0.5 {
|
||||
return template.CSS("#fff")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default to black
|
||||
return template.CSS("#000")
|
||||
}
|
||||
|
||||
// NewLabel creates new label of repository.
|
||||
func NewLabel(l *Label) error {
|
||||
_, err := x.Insert(l)
|
||||
return err
|
||||
}
|
||||
|
||||
func getLabelByID(e Engine, id int64) (*Label, error) {
|
||||
if id <= 0 {
|
||||
return nil, ErrLabelNotExist{id}
|
||||
}
|
||||
|
||||
l := &Label{ID: id}
|
||||
has, err := x.Get(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrLabelNotExist{l.ID}
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetLabelByID returns a label by given ID.
|
||||
func GetLabelByID(id int64) (*Label, error) {
|
||||
return getLabelByID(x, id)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
|
||||
issueLabels, err := getIssueLabels(e, issueID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getIssueLabels: %v", err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
|
||||
func GetLabelsByIssueID(issueID int64) ([]*Label, error) {
|
||||
return getLabelsByIssueID(x, issueID)
|
||||
}
|
||||
|
||||
func updateLabel(e Engine, l *Label) error {
|
||||
_, err := e.Id(l.ID).AllCols().Update(l)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateLabel updates label information.
|
||||
func UpdateLabel(l *Label) error {
|
||||
return updateLabel(x, l)
|
||||
}
|
||||
|
||||
// DeleteLabel delete a label of given repository.
|
||||
func DeleteLabel(repoID, labelID int64) error {
|
||||
l, err := GetLabelByID(labelID)
|
||||
if err != nil {
|
||||
if IsErrLabelNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = x.Where("label_id=?", labelID).Delete(new(IssueLabel)); err != nil {
|
||||
return err
|
||||
} else if _, err = sess.Delete(l); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// .___ .____ ___. .__
|
||||
// | | ______ ________ __ ____ | | _____ \_ |__ ____ | |
|
||||
// | |/ ___// ___/ | \_/ __ \| | \__ \ | __ \_/ __ \| |
|
||||
// | |\___ \ \___ \| | /\ ___/| |___ / __ \| \_\ \ ___/| |__
|
||||
// |___/____ >____ >____/ \___ >_______ (____ /___ /\___ >____/
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
|
||||
// IssueLabel represetns an issue-lable relation.
|
||||
type IssueLabel struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
IssueID int64 `xorm:"UNIQUE(s)"`
|
||||
LabelID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
func hasIssueLabel(e Engine, issueID, labelID int64) bool {
|
||||
has, _ := e.Where("issue_id=? AND label_id=?", issueID, labelID).Get(new(IssueLabel))
|
||||
return has
|
||||
}
|
||||
|
||||
// HasIssueLabel returns true if issue has been labeled.
|
||||
func HasIssueLabel(issueID, labelID int64) bool {
|
||||
return hasIssueLabel(x, issueID, labelID)
|
||||
}
|
||||
|
||||
func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||
if _, err = e.Insert(&IssueLabel{
|
||||
IssueID: issue.ID,
|
||||
LabelID: label.ID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
label.NumIssues++
|
||||
if issue.IsClosed {
|
||||
label.NumClosedIssues++
|
||||
}
|
||||
return updateLabel(e, label)
|
||||
}
|
||||
|
||||
// NewIssueLabel creates a new issue-label relation.
|
||||
func NewIssueLabel(issue *Issue, label *Label) (err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = newIssueLabel(sess, issue, label); 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)
|
||||
}
|
||||
|
||||
// GetIssueLabels returns all issue-label relations of given issue by ID.
|
||||
func GetIssueLabels(issueID int64) ([]*IssueLabel, error) {
|
||||
return getIssueLabels(x, issueID)
|
||||
}
|
||||
|
||||
func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||
if _, err = e.Delete(&IssueLabel{
|
||||
IssueID: issue.ID,
|
||||
LabelID: label.ID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
label.NumIssues--
|
||||
if issue.IsClosed {
|
||||
label.NumClosedIssues--
|
||||
}
|
||||
return updateLabel(e, label)
|
||||
}
|
||||
|
||||
// DeleteIssueLabel deletes issue-label relation.
|
||||
func DeleteIssueLabel(issue *Issue, label *Label) (err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = deleteIssueLabel(sess, issue, label); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
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.Name, issue.Index)
|
||||
}
|
||||
|
||||
// mailIssueCommentToParticipants can be used for both new issue creation and comment.
|
||||
func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error {
|
||||
if !setting.Service.EnableNotifyMail {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mail wahtcers.
|
||||
watchers, err := GetWatchers(issue.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetWatchers [%d]: %v", issue.RepoID, err)
|
||||
}
|
||||
|
||||
tos := make([]string, 0, len(watchers)) // List of email addresses.
|
||||
names := make([]string, 0, len(watchers))
|
||||
for i := range watchers {
|
||||
if watchers[i].UserID == doer.Id {
|
||||
continue
|
||||
}
|
||||
|
||||
to, err := GetUserByID(watchers[i].UserID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID [%d]: %v", watchers[i].UserID, err)
|
||||
}
|
||||
if to.IsOrganization() {
|
||||
continue
|
||||
}
|
||||
|
||||
tos = append(tos, to.Email)
|
||||
names = append(names, to.Name)
|
||||
}
|
||||
SendIssueCommentMail(issue, doer, tos)
|
||||
|
||||
// Mail mentioned people and exclude watchers.
|
||||
names = append(names, doer.Name)
|
||||
tos = make([]string, 0, len(mentions)) // list of user names.
|
||||
for i := range mentions {
|
||||
if com.IsSliceContainsStr(names, mentions[i]) {
|
||||
continue
|
||||
}
|
||||
|
||||
tos = append(tos, mentions[i])
|
||||
}
|
||||
SendIssueMentionMail(issue, doer, GetUserEmailsByNames(tos))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MailParticipants sends new issue thread created emails to repository watchers
|
||||
// and mentioned people.
|
||||
func (issue *Issue) MailParticipants() (err error) {
|
||||
mentions := markdown.FindAllMentions(issue.Content)
|
||||
if err = UpdateIssueMentions(issue.ID, mentions); err != nil {
|
||||
return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
||||
}
|
||||
|
||||
if err = mailIssueCommentToParticipants(issue, issue.Poster, mentions); err != nil {
|
||||
log.Error(4, "mailIssueCommentToParticipants: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
190
models/login.go
190
models/login.go
@@ -10,10 +10,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"net/textproto"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-xorm/core"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
@@ -22,29 +24,34 @@ import (
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
|
||||
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
|
||||
)
|
||||
|
||||
type LoginType int
|
||||
|
||||
// Note: new type must be added at the end of list to maintain compatibility.
|
||||
const (
|
||||
NOTYPE LoginType = iota
|
||||
PLAIN
|
||||
LDAP
|
||||
SMTP
|
||||
PAM
|
||||
DLDAP
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
|
||||
ErrAuthenticationNotExist = errors.New("Authentication does not exist")
|
||||
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
|
||||
LOGIN_NOTYPE LoginType = iota
|
||||
LOGIN_PLAIN // 1
|
||||
LOGIN_LDAP // 2
|
||||
LOGIN_SMTP // 3
|
||||
LOGIN_PAM // 4
|
||||
LOGIN_DLDAP // 5
|
||||
)
|
||||
|
||||
var LoginNames = map[LoginType]string{
|
||||
LDAP: "LDAP (via BindDN)",
|
||||
DLDAP: "LDAP (simple auth)",
|
||||
SMTP: "SMTP",
|
||||
PAM: "PAM",
|
||||
LOGIN_LDAP: "LDAP (via BindDN)",
|
||||
LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind
|
||||
LOGIN_SMTP: "SMTP",
|
||||
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.
|
||||
@@ -66,6 +73,10 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
|
||||
return json.Marshal(cfg)
|
||||
}
|
||||
|
||||
func (cfg *LDAPConfig) SecurityProtocolName() string {
|
||||
return SecurityProtocolNames[cfg.SecurityProtocol]
|
||||
}
|
||||
|
||||
type SMTPConfig struct {
|
||||
Auth string
|
||||
Host string
|
||||
@@ -101,19 +112,42 @@ type LoginSource struct {
|
||||
Name string `xorm:"UNIQUE"`
|
||||
IsActived bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Cfg core.Conversion `xorm:"TEXT"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time `xorm:"UPDATED"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
Updated time.Time `xorm:"-"`
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (s *LoginSource) BeforeInsert() {
|
||||
s.CreatedUnix = time.Now().UTC().Unix()
|
||||
s.UpdatedUnix = s.CreatedUnix
|
||||
}
|
||||
|
||||
func (s *LoginSource) BeforeUpdate() {
|
||||
s.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
// Cell2Int64 converts a xorm.Cell type to int64,
|
||||
// and handles possible irregular cases.
|
||||
func Cell2Int64(val xorm.Cell) int64 {
|
||||
switch (*val).(type) {
|
||||
case []uint8:
|
||||
log.Trace("Cell2Int64 ([]uint8): %v", *val)
|
||||
return com.StrTo(string((*val).([]uint8))).MustInt64()
|
||||
}
|
||||
return (*val).(int64)
|
||||
}
|
||||
|
||||
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
||||
switch colName {
|
||||
case "type":
|
||||
switch LoginType((*val).(int64)) {
|
||||
case LDAP, DLDAP:
|
||||
switch LoginType(Cell2Int64(val)) {
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
source.Cfg = new(LDAPConfig)
|
||||
case SMTP:
|
||||
case LOGIN_SMTP:
|
||||
source.Cfg = new(SMTPConfig)
|
||||
case PAM:
|
||||
case LOGIN_PAM:
|
||||
source.Cfg = new(PAMConfig)
|
||||
default:
|
||||
panic("unrecognized login source type: " + com.ToStr(*val))
|
||||
@@ -121,31 +155,46 @@ 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]
|
||||
}
|
||||
|
||||
func (source *LoginSource) IsLDAP() bool {
|
||||
return source.Type == LDAP
|
||||
return source.Type == LOGIN_LDAP
|
||||
}
|
||||
|
||||
func (source *LoginSource) IsDLDAP() bool {
|
||||
return source.Type == DLDAP
|
||||
return source.Type == LOGIN_DLDAP
|
||||
}
|
||||
|
||||
func (source *LoginSource) IsSMTP() bool {
|
||||
return source.Type == SMTP
|
||||
return source.Type == LOGIN_SMTP
|
||||
}
|
||||
|
||||
func (source *LoginSource) IsPAM() bool {
|
||||
return source.Type == PAM
|
||||
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 LDAP, DLDAP:
|
||||
return source.LDAP().UseSSL
|
||||
case SMTP:
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
return source.LDAP().SecurityProtocol != ldap.SECURITY_PROTOCOL_UNENCRYPTED
|
||||
case LOGIN_SMTP:
|
||||
return source.SMTP().TLS
|
||||
}
|
||||
|
||||
@@ -154,9 +203,9 @@ func (source *LoginSource) UseTLS() bool {
|
||||
|
||||
func (source *LoginSource) SkipVerify() bool {
|
||||
switch source.Type {
|
||||
case LDAP, DLDAP:
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
return source.LDAP().SkipVerify
|
||||
case SMTP:
|
||||
case LOGIN_SMTP:
|
||||
return source.SMTP().SkipVerify
|
||||
}
|
||||
|
||||
@@ -191,13 +240,14 @@ func LoginSources() ([]*LoginSource, error) {
|
||||
return auths, x.Find(&auths)
|
||||
}
|
||||
|
||||
// GetLoginSourceByID returns login source by given ID.
|
||||
func GetLoginSourceByID(id int64) (*LoginSource, error) {
|
||||
source := new(LoginSource)
|
||||
has, err := x.Id(id).Get(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrAuthenticationNotExist
|
||||
return nil, ErrAuthenticationNotExist{id}
|
||||
}
|
||||
return source, nil
|
||||
}
|
||||
@@ -225,16 +275,16 @@ func DeleteSource(source *LoginSource) error {
|
||||
// |_______ \/_______ /\____|__ /____|
|
||||
// \/ \/ \/
|
||||
|
||||
// LoginUserLDAPSource queries if name/passwd can login against the LDAP directory pool,
|
||||
// LoginUserLDAPSource queries if loginName/passwd can login against the LDAP directory pool,
|
||||
// and create a local user if success when enabled.
|
||||
// It returns the same LoginUserPlain semantic.
|
||||
func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
func LoginUserLDAPSource(u *User, loginName, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
cfg := source.Cfg.(*LDAPConfig)
|
||||
directBind := (source.Type == DLDAP)
|
||||
fn, sn, mail, admin, logged := cfg.SearchEntry(name, passwd, directBind)
|
||||
directBind := (source.Type == LOGIN_DLDAP)
|
||||
username, fn, sn, mail, isAdmin, logged := cfg.SearchEntry(loginName, passwd, directBind)
|
||||
if !logged {
|
||||
// User not in LDAP, do nothing
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
return nil, ErrUserNotExist{0, loginName}
|
||||
}
|
||||
|
||||
if !autoRegister {
|
||||
@@ -242,24 +292,45 @@ func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, auto
|
||||
}
|
||||
|
||||
// Fallback.
|
||||
if len(username) == 0 {
|
||||
username = loginName
|
||||
}
|
||||
// Validate username make sure it satisfies requirement.
|
||||
if !binding.AlphaDashDotPattern.MatchString(username) {
|
||||
return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", username)
|
||||
}
|
||||
|
||||
if len(mail) == 0 {
|
||||
mail = fmt.Sprintf("%s@localhost", name)
|
||||
mail = fmt.Sprintf("%s@localhost", username)
|
||||
}
|
||||
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(name),
|
||||
Name: name,
|
||||
FullName: strings.TrimSpace(fn + " " + sn),
|
||||
LowerName: strings.ToLower(username),
|
||||
Name: username,
|
||||
FullName: composeFullName(fn, sn, username),
|
||||
LoginType: source.Type,
|
||||
LoginSource: source.ID,
|
||||
LoginName: name,
|
||||
LoginName: loginName,
|
||||
Email: mail,
|
||||
IsAdmin: admin,
|
||||
IsAdmin: isAdmin,
|
||||
IsActive: true,
|
||||
}
|
||||
return u, CreateUser(u)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// _________ __________________________
|
||||
// / _____/ / \__ ___/\______ \
|
||||
// \_____ \ / \ / \| | | ___/
|
||||
@@ -334,7 +405,7 @@ func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
|
||||
// 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) {
|
||||
func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
|
||||
// Verify allowed domains.
|
||||
if len(cfg.AllowedDomains) > 0 {
|
||||
idx := strings.Index(name, "@")
|
||||
@@ -355,7 +426,11 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTP
|
||||
}
|
||||
|
||||
if err := SMTPAuth(auth, cfg); err != nil {
|
||||
if strings.Contains(err.Error(), "Username and Password not accepted") {
|
||||
// Check standard error format first,
|
||||
// then fallback to worse case.
|
||||
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, err
|
||||
@@ -374,8 +449,8 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTP
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(loginName),
|
||||
Name: strings.ToLower(loginName),
|
||||
LoginType: SMTP,
|
||||
LoginSource: sourceId,
|
||||
LoginType: LOGIN_SMTP,
|
||||
LoginSource: sourceID,
|
||||
LoginName: name,
|
||||
IsActive: true,
|
||||
Passwd: passwd,
|
||||
@@ -395,7 +470,7 @@ 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) {
|
||||
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 {
|
||||
if strings.Contains(err.Error(), "Authentication failure") {
|
||||
return nil, ErrUserNotExist{0, name}
|
||||
@@ -410,16 +485,15 @@ func LoginUserPAMSource(u *User, name, passwd string, sourceId int64, cfg *PAMCo
|
||||
// fake a local user creation
|
||||
u = &User{
|
||||
LowerName: strings.ToLower(name),
|
||||
Name: strings.ToLower(name),
|
||||
LoginType: PAM,
|
||||
LoginSource: sourceId,
|
||||
Name: name,
|
||||
LoginType: LOGIN_PAM,
|
||||
LoginSource: sourceID,
|
||||
LoginName: name,
|
||||
IsActive: true,
|
||||
Passwd: passwd,
|
||||
Email: name,
|
||||
}
|
||||
err := CreateUser(u)
|
||||
return u, err
|
||||
return u, CreateUser(u)
|
||||
}
|
||||
|
||||
func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
|
||||
@@ -428,11 +502,11 @@ func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRe
|
||||
}
|
||||
|
||||
switch source.Type {
|
||||
case LDAP, DLDAP:
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
return LoginUserLDAPSource(u, name, passwd, source, autoRegister)
|
||||
case SMTP:
|
||||
case LOGIN_SMTP:
|
||||
return LoginUserSMTPSource(u, name, passwd, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
|
||||
case PAM:
|
||||
case LOGIN_PAM:
|
||||
return LoginUserPAMSource(u, name, passwd, source.ID, source.Cfg.(*PAMConfig), autoRegister)
|
||||
}
|
||||
|
||||
@@ -443,7 +517,7 @@ func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRe
|
||||
func UserSignIn(uname, passwd string) (*User, error) {
|
||||
var u *User
|
||||
if strings.Contains(uname, "@") {
|
||||
u = &User{Email: uname}
|
||||
u = &User{Email: strings.ToLower(uname)}
|
||||
} else {
|
||||
u = &User{LowerName: strings.ToLower(uname)}
|
||||
}
|
||||
@@ -455,7 +529,7 @@ func UserSignIn(uname, passwd string) (*User, error) {
|
||||
|
||||
if userExists {
|
||||
switch u.LoginType {
|
||||
case NOTYPE, PLAIN:
|
||||
case LOGIN_NOTYPE, LOGIN_PLAIN:
|
||||
if u.ValidatePassword(passwd) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
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.FullLink(),
|
||||
}
|
||||
body, err := mailRender.HTMLString(string(MAIL_NOTIFY_COLLABORATOR), data)
|
||||
if err != nil {
|
||||
log.Error(3, "HTMLString: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
msg := mailer.NewMessage([]string{u.Email}, subject, body)
|
||||
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.Id)
|
||||
|
||||
mailer.SendAsync(msg)
|
||||
}
|
||||
|
||||
func composeTplData(subject, body, link string) map[string]interface{} {
|
||||
data := make(map[string]interface{}, 10)
|
||||
data["Subject"] = subject
|
||||
data["Body"] = body
|
||||
data["Link"] = link
|
||||
return data
|
||||
}
|
||||
|
||||
func composeIssueMessage(issue *Issue, doer *User, tplName base.TplName, tos []string, info string) *mailer.Message {
|
||||
subject := issue.MailSubject()
|
||||
body := string(markdown.RenderSpecialLink([]byte(issue.Content), issue.Repo.FullLink(), issue.Repo.ComposeMetas()))
|
||||
data := composeTplData(subject, body, issue.FullLink())
|
||||
data["Doer"] = doer
|
||||
content, err := mailRender.HTMLString(string(tplName), data)
|
||||
if err != nil {
|
||||
log.Error(3, "HTMLString (%s): %v", tplName, err)
|
||||
}
|
||||
msg := mailer.NewMessage(tos, subject, content)
|
||||
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
|
||||
return msg
|
||||
}
|
||||
|
||||
// SendIssueCommentMail composes and sends issue comment emails to target receivers.
|
||||
func SendIssueCommentMail(issue *Issue, doer *User, tos []string) {
|
||||
if len(tos) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_COMMENT, tos, "issue comment"))
|
||||
}
|
||||
|
||||
// SendIssueMentionMail composes and sends issue mention emails to target receivers.
|
||||
func SendIssueMentionMail(issue *Issue, doer *User, tos []string) {
|
||||
if len(tos) == 0 {
|
||||
return
|
||||
}
|
||||
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_MENTION, tos, "issue mention"))
|
||||
}
|
||||
@@ -17,14 +17,15 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
gouuid "github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
const _MIN_DB_VER = 0
|
||||
const _MIN_DB_VER = 4
|
||||
|
||||
type Migration interface {
|
||||
Description() string
|
||||
@@ -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,16 +59,15 @@ type Version struct {
|
||||
// If you want to "retire" a migration, remove it from the top of the list and
|
||||
// update _MIN_VER_DB accordingly
|
||||
var migrations = []Migration{
|
||||
NewMigration("generate collaboration from access", accessToCollaboration), // V0 -> V1:v0.5.13
|
||||
NewMigration("make authorize 4 if team is owners", ownerTeamUpdate), // V1 -> V2:v0.5.13
|
||||
NewMigration("refactor access table to use id's", accessRefactor), // V2 -> V3:v0.5.13
|
||||
NewMigration("generate team-repo from team", teamToTeamRepo), // V3 -> V4:v0.5.13
|
||||
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("fix locale file load panic", fixLocaleFileLoadPanic), // V4 -> V5:v0.6.0
|
||||
NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix), // V5 -> V6:v0.6.3
|
||||
NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4
|
||||
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
|
||||
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
|
||||
NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20
|
||||
NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
|
||||
NewMigration("convert date to unix timestamp", convertDateToUnix), // V11 -> V12:v0.9.2
|
||||
NewMigration("convert LDAP UseSSL option to SecurityProtocol", ldapUseSSLToSecurityProtocol), // V12 -> V13:v0.9.37
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
@@ -76,29 +76,14 @@ 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)
|
||||
} else if !has {
|
||||
// If the user table does not exist it is a fresh installation and we
|
||||
// can skip all migrations.
|
||||
needsMigration, err := x.IsTableExist("user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if needsMigration {
|
||||
isEmpty, err := x.IsTableEmpty("user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If the user table is empty it is a fresh installation and we can
|
||||
// skip all migrations.
|
||||
needsMigration = !isEmpty
|
||||
}
|
||||
if !needsMigration {
|
||||
currentVersion.Version = int64(_MIN_DB_VER + len(migrations))
|
||||
}
|
||||
// If the version record does not exist we think
|
||||
// it is a fresh installation and we can skip all migrations.
|
||||
currentVersion.Version = int64(_MIN_DB_VER + len(migrations))
|
||||
|
||||
if _, err = x.InsertOne(currentVersion); err != nil {
|
||||
return fmt.Errorf("insert: %v", err)
|
||||
@@ -106,6 +91,12 @@ func Migrate(x *xorm.Engine) error {
|
||||
}
|
||||
|
||||
v := currentVersion.Version
|
||||
if _MIN_DB_VER > v {
|
||||
log.Fatal(4, `Gogs no longer supports auto-migration from your previously installed version.
|
||||
Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to current version.`)
|
||||
return nil
|
||||
}
|
||||
|
||||
if int(v-_MIN_DB_VER) > len(migrations) {
|
||||
// User downgraded Gogs.
|
||||
currentVersion.Version = int64(len(migrations) + _MIN_DB_VER)
|
||||
@@ -132,276 +123,6 @@ func sessionRelease(sess *xorm.Session) {
|
||||
sess.Close()
|
||||
}
|
||||
|
||||
func accessToCollaboration(x *xorm.Engine) (err error) {
|
||||
type Collaboration struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
Created time.Time
|
||||
}
|
||||
|
||||
if err = x.Sync(new(Collaboration)); err != nil {
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
results, err := x.Query("SELECT u.id AS `uid`, a.repo_name AS `repo`, a.mode AS `mode`, a.created as `created` FROM `access` a JOIN `user` u ON a.user_name=u.lower_name")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such column") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offset := strings.Split(time.Now().String(), " ")[2]
|
||||
for _, result := range results {
|
||||
mode := com.StrTo(result["mode"]).MustInt64()
|
||||
// Collaborators must have write access.
|
||||
if mode < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
userID := com.StrTo(result["uid"]).MustInt64()
|
||||
repoRefName := string(result["repo"])
|
||||
|
||||
var created time.Time
|
||||
switch {
|
||||
case setting.UseSQLite3:
|
||||
created, _ = time.Parse(time.RFC3339, string(result["created"]))
|
||||
case setting.UseMySQL:
|
||||
created, _ = time.Parse("2006-01-02 15:04:05-0700", string(result["created"])+offset)
|
||||
case setting.UsePostgreSQL:
|
||||
created, _ = time.Parse("2006-01-02T15:04:05Z-0700", string(result["created"])+offset)
|
||||
}
|
||||
|
||||
// find owner of repository
|
||||
parts := strings.SplitN(repoRefName, "/", 2)
|
||||
ownerName := parts[0]
|
||||
repoName := parts[1]
|
||||
|
||||
results, err := sess.Query("SELECT u.id as `uid`, ou.uid as `memberid` FROM `user` u LEFT JOIN org_user ou ON ou.org_id=u.id WHERE u.lower_name=?", ownerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
ownerID := com.StrTo(results[0]["uid"]).MustInt64()
|
||||
if ownerID == userID {
|
||||
continue
|
||||
}
|
||||
|
||||
// test if user is member of owning organization
|
||||
isMember := false
|
||||
for _, member := range results {
|
||||
memberID := com.StrTo(member["memberid"]).MustInt64()
|
||||
// We can skip all cases that a user is member of the owning organization
|
||||
if memberID == userID {
|
||||
isMember = true
|
||||
}
|
||||
}
|
||||
if isMember {
|
||||
continue
|
||||
}
|
||||
|
||||
results, err = sess.Query("SELECT id FROM `repository` WHERE owner_id=? AND lower_name=?", ownerID, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(results) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
collaboration := &Collaboration{
|
||||
UserID: userID,
|
||||
RepoID: com.StrTo(results[0]["id"]).MustInt64(),
|
||||
}
|
||||
has, err := sess.Get(collaboration)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
continue
|
||||
}
|
||||
|
||||
collaboration.Created = created
|
||||
if _, err = sess.InsertOne(collaboration); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func ownerTeamUpdate(x *xorm.Engine) (err error) {
|
||||
if _, err := x.Exec("UPDATE `team` SET authorize=4 WHERE lower_name=?", "owners"); err != nil {
|
||||
return fmt.Errorf("update owner team table: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func accessRefactor(x *xorm.Engine) (err error) {
|
||||
type (
|
||||
AccessMode int
|
||||
Access struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
Mode AccessMode
|
||||
}
|
||||
UserRepo struct {
|
||||
UserID int64
|
||||
RepoID int64
|
||||
}
|
||||
)
|
||||
|
||||
// We consiously don't start a session yet as we make only reads for now, no writes
|
||||
|
||||
accessMap := make(map[UserRepo]AccessMode, 50)
|
||||
|
||||
results, err := x.Query("SELECT r.id AS `repo_id`, r.is_private AS `is_private`, r.owner_id AS `owner_id`, u.type AS `owner_type` FROM `repository` r LEFT JOIN `user` u ON r.owner_id=u.id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("select repositories: %v", err)
|
||||
}
|
||||
for _, repo := range results {
|
||||
repoID := com.StrTo(repo["repo_id"]).MustInt64()
|
||||
isPrivate := com.StrTo(repo["is_private"]).MustInt() > 0
|
||||
ownerID := com.StrTo(repo["owner_id"]).MustInt64()
|
||||
ownerIsOrganization := com.StrTo(repo["owner_type"]).MustInt() > 0
|
||||
|
||||
results, err := x.Query("SELECT `user_id` FROM `collaboration` WHERE repo_id=?", repoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("select collaborators: %v", err)
|
||||
}
|
||||
for _, user := range results {
|
||||
userID := com.StrTo(user["user_id"]).MustInt64()
|
||||
accessMap[UserRepo{userID, repoID}] = 2 // WRITE ACCESS
|
||||
}
|
||||
|
||||
if !ownerIsOrganization {
|
||||
continue
|
||||
}
|
||||
|
||||
// The minimum level to add a new access record,
|
||||
// because public repository has implicit open access.
|
||||
minAccessLevel := AccessMode(0)
|
||||
if !isPrivate {
|
||||
minAccessLevel = 1
|
||||
}
|
||||
|
||||
repoString := "$" + string(repo["repo_id"]) + "|"
|
||||
|
||||
results, err = x.Query("SELECT `id`,`authorize`,`repo_ids` FROM `team` WHERE org_id=? AND authorize>? ORDER BY `authorize` ASC", ownerID, int(minAccessLevel))
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such column") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("select teams from org: %v", err)
|
||||
}
|
||||
|
||||
for _, team := range results {
|
||||
if !strings.Contains(string(team["repo_ids"]), repoString) {
|
||||
continue
|
||||
}
|
||||
teamID := com.StrTo(team["id"]).MustInt64()
|
||||
mode := AccessMode(com.StrTo(team["authorize"]).MustInt())
|
||||
|
||||
results, err := x.Query("SELECT `uid` FROM `team_user` WHERE team_id=?", teamID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("select users from team: %v", err)
|
||||
}
|
||||
for _, user := range results {
|
||||
userID := com.StrTo(user["uid"]).MustInt64()
|
||||
accessMap[UserRepo{userID, repoID}] = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop table can't be in a session (at least not in sqlite)
|
||||
if _, err = x.Exec("DROP TABLE `access`"); err != nil {
|
||||
return fmt.Errorf("drop access table: %v", err)
|
||||
}
|
||||
|
||||
// Now we start writing so we make a session
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sess.Sync2(new(Access)); err != nil {
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
accesses := make([]*Access, 0, len(accessMap))
|
||||
for ur, mode := range accessMap {
|
||||
accesses = append(accesses, &Access{UserID: ur.UserID, RepoID: ur.RepoID, Mode: mode})
|
||||
}
|
||||
|
||||
if _, err = sess.Insert(accesses); err != nil {
|
||||
return fmt.Errorf("insert accesses: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func teamToTeamRepo(x *xorm.Engine) error {
|
||||
type TeamRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
teamRepos := make([]*TeamRepo, 0, 50)
|
||||
|
||||
results, err := x.Query("SELECT `id`,`org_id`,`repo_ids` FROM `team`")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such column") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("select teams: %v", err)
|
||||
}
|
||||
for _, team := range results {
|
||||
orgID := com.StrTo(team["org_id"]).MustInt64()
|
||||
teamID := com.StrTo(team["id"]).MustInt64()
|
||||
|
||||
// #1032: legacy code can have duplicated IDs for same repository.
|
||||
mark := make(map[int64]bool)
|
||||
for _, idStr := range strings.Split(string(team["repo_ids"]), "|") {
|
||||
repoID := com.StrTo(strings.TrimPrefix(idStr, "$")).MustInt64()
|
||||
if repoID == 0 || mark[repoID] {
|
||||
continue
|
||||
}
|
||||
|
||||
mark[repoID] = true
|
||||
teamRepos = append(teamRepos, &TeamRepo{
|
||||
OrgID: orgID,
|
||||
TeamID: teamID,
|
||||
RepoID: repoID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sess.Sync2(new(TeamRepo)); err != nil {
|
||||
return fmt.Errorf("sync2: %v", err)
|
||||
} else if _, err = sess.Insert(teamRepos); err != nil {
|
||||
return fmt.Errorf("insert team-repos: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func fixLocaleFileLoadPanic(_ *xorm.Engine) error {
|
||||
cfg, err := ini.Load(setting.CustomConf)
|
||||
if err != nil {
|
||||
@@ -489,7 +210,8 @@ func issueToIssueLabel(x *xorm.Engine) error {
|
||||
issueLabels := make([]*IssueLabel, 0, 50)
|
||||
results, err := x.Query("SELECT `id`,`label_ids` FROM `issue`")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such column") {
|
||||
if strings.Contains(err.Error(), "no such column") ||
|
||||
strings.Contains(err.Error(), "Unknown column") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("select issues: %v", err)
|
||||
@@ -648,6 +370,9 @@ func renamePullRequestFields(x *xorm.Engine) (err error) {
|
||||
Index: com.StrTo(pr["pull_index"]).MustInt64(),
|
||||
HeadBranch: string(pr["head_barcnh"]),
|
||||
}
|
||||
if pull.Index == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err = sess.Id(pull.ID).Update(pull); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -702,3 +427,251 @@ func cleanUpMigrateRepoInfo(x *xorm.Engine) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
|
||||
type User struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Rands string `xorm:"VARCHAR(10)"`
|
||||
Salt string `xorm:"VARCHAR(10)"`
|
||||
}
|
||||
|
||||
orgs := make([]*User, 0, 10)
|
||||
if err = x.Where("type=1").And("rands=''").Find(&orgs); err != nil {
|
||||
return fmt.Errorf("select all organizations: %v", err)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
org.Rands = base.GetRandomString(10)
|
||||
org.Salt = base.GetRandomString(10)
|
||||
if _, err = sess.Id(org.ID).Update(org); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
type TAction struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TAction) TableName() string { return "action" }
|
||||
|
||||
type TNotice struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TNotice) TableName() string { return "notice" }
|
||||
|
||||
type TComment struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TComment) TableName() string { return "comment" }
|
||||
|
||||
type TIssue struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
DeadlineUnix int64
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TIssue) TableName() string { return "issue" }
|
||||
|
||||
type TMilestone struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
DeadlineUnix int64
|
||||
ClosedDateUnix int64
|
||||
}
|
||||
|
||||
func (t *TMilestone) TableName() string { return "milestone" }
|
||||
|
||||
type TAttachment struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TAttachment) TableName() string { return "attachment" }
|
||||
|
||||
type TLoginSource struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TLoginSource) TableName() string { return "login_source" }
|
||||
|
||||
type TPull struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
MergedUnix int64
|
||||
}
|
||||
|
||||
func (t *TPull) TableName() string { return "pull_request" }
|
||||
|
||||
type TRelease struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TRelease) TableName() string { return "release" }
|
||||
|
||||
type TRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TRepo) TableName() string { return "repository" }
|
||||
|
||||
type TMirror struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UpdatedUnix int64
|
||||
NextUpdateUnix int64
|
||||
}
|
||||
|
||||
func (t *TMirror) TableName() string { return "mirror" }
|
||||
|
||||
type TPublicKey struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TPublicKey) TableName() string { return "public_key" }
|
||||
|
||||
type TDeployKey struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TDeployKey) TableName() string { return "deploy_key" }
|
||||
|
||||
type TAccessToken struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TAccessToken) TableName() string { return "access_token" }
|
||||
|
||||
type TUser struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TUser) TableName() string { return "user" }
|
||||
|
||||
type TWebhook struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
CreatedUnix int64
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (t *TWebhook) TableName() string { return "webhook" }
|
||||
|
||||
func convertDateToUnix(x *xorm.Engine) (err error) {
|
||||
log.Info("This migration could take up to minutes, please be patient.")
|
||||
type Bean struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
Merged time.Time
|
||||
Deadline time.Time
|
||||
ClosedDate time.Time
|
||||
NextUpdate time.Time
|
||||
}
|
||||
|
||||
var tables = []struct {
|
||||
name string
|
||||
cols []string
|
||||
bean interface{}
|
||||
}{
|
||||
{"action", []string{"created"}, new(TAction)},
|
||||
{"notice", []string{"created"}, new(TNotice)},
|
||||
{"comment", []string{"created"}, new(TComment)},
|
||||
{"issue", []string{"deadline", "created", "updated"}, new(TIssue)},
|
||||
{"milestone", []string{"deadline", "closed_date"}, new(TMilestone)},
|
||||
{"attachment", []string{"created"}, new(TAttachment)},
|
||||
{"login_source", []string{"created", "updated"}, new(TLoginSource)},
|
||||
{"pull_request", []string{"merged"}, new(TPull)},
|
||||
{"release", []string{"created"}, new(TRelease)},
|
||||
{"repository", []string{"created", "updated"}, new(TRepo)},
|
||||
{"mirror", []string{"updated", "next_update"}, new(TMirror)},
|
||||
{"public_key", []string{"created", "updated"}, new(TPublicKey)},
|
||||
{"deploy_key", []string{"created", "updated"}, new(TDeployKey)},
|
||||
{"access_token", []string{"created", "updated"}, new(TAccessToken)},
|
||||
{"user", []string{"created", "updated"}, new(TUser)},
|
||||
{"webhook", []string{"created", "updated"}, new(TWebhook)},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
log.Info("Converting table: %s", table.name)
|
||||
if err = x.Sync2(table.bean); err != nil {
|
||||
return fmt.Errorf("Sync [table: %s]: %v", table.name, err)
|
||||
}
|
||||
|
||||
offset := 0
|
||||
for {
|
||||
beans := make([]*Bean, 0, 100)
|
||||
if err = x.Sql(fmt.Sprintf("SELECT * FROM `%s` ORDER BY id ASC LIMIT 100 OFFSET %d",
|
||||
table.name, offset)).Find(&beans); err != nil {
|
||||
return fmt.Errorf("select beans [table: %s, offset: %d]: %v", table.name, offset, err)
|
||||
}
|
||||
log.Trace("Table [%s]: offset: %d, beans: %d", table.name, offset, len(beans))
|
||||
if len(beans) == 0 {
|
||||
break
|
||||
}
|
||||
offset += 100
|
||||
|
||||
baseSQL := "UPDATE `" + table.name + "` SET "
|
||||
for _, bean := range beans {
|
||||
valSQLs := make([]string, 0, len(table.cols))
|
||||
for _, col := range table.cols {
|
||||
fieldSQL := ""
|
||||
fieldSQL += col + "_unix = "
|
||||
|
||||
switch col {
|
||||
case "deadline":
|
||||
if bean.Deadline.IsZero() {
|
||||
continue
|
||||
}
|
||||
fieldSQL += com.ToStr(bean.Deadline.UTC().Unix())
|
||||
case "created":
|
||||
fieldSQL += com.ToStr(bean.Created.UTC().Unix())
|
||||
case "updated":
|
||||
fieldSQL += com.ToStr(bean.Updated.UTC().Unix())
|
||||
case "closed_date":
|
||||
fieldSQL += com.ToStr(bean.ClosedDate.UTC().Unix())
|
||||
case "merged":
|
||||
fieldSQL += com.ToStr(bean.Merged.UTC().Unix())
|
||||
case "next_update":
|
||||
fieldSQL += com.ToStr(bean.NextUpdate.UTC().Unix())
|
||||
}
|
||||
|
||||
valSQLs = append(valSQLs, fieldSQL)
|
||||
}
|
||||
|
||||
if len(valSQLs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = x.Exec(baseSQL + strings.Join(valSQLs, ",") + " WHERE id = " + com.ToStr(bean.ID)); err != nil {
|
||||
return fmt.Errorf("update bean [table: %s, id: %d]: %v", table.name, bean.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
52
models/migrations/v13.go
Normal file
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()
|
||||
}
|
||||
@@ -11,16 +11,13 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/go-xorm/core"
|
||||
"github.com/go-xorm/xorm"
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/gogits/gogs/models/migrations"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -44,27 +41,6 @@ func sessionRelease(sess *xorm.Session) {
|
||||
sess.Close()
|
||||
}
|
||||
|
||||
// Note: get back time.Time from database Go sees it at UTC where they are really Local.
|
||||
// So this function makes correct timezone offset.
|
||||
func regulateTimeZone(t time.Time) time.Time {
|
||||
if !setting.UseMySQL {
|
||||
return t
|
||||
}
|
||||
|
||||
zone := t.Local().Format("-0700")
|
||||
if len(zone) != 5 {
|
||||
log.Error(4, "Unprocessable timezone: %s - %s", t.Local(), zone)
|
||||
return t
|
||||
}
|
||||
hour := com.StrTo(zone[2:3]).MustInt()
|
||||
minutes := com.StrTo(zone[3:5]).MustInt()
|
||||
|
||||
if zone[0] == '-' {
|
||||
return t.Add(time.Duration(hour) * time.Hour).Add(time.Duration(minutes) * time.Minute)
|
||||
}
|
||||
return t.Add(-1 * time.Duration(hour) * time.Hour).Add(-1 * time.Duration(minutes) * time.Minute)
|
||||
}
|
||||
|
||||
var (
|
||||
x *xorm.Engine
|
||||
tables []interface{}
|
||||
@@ -121,14 +97,18 @@ func LoadConfigs() {
|
||||
|
||||
func getEngine() (*xorm.Engine, error) {
|
||||
cnnstr := ""
|
||||
var Param string = "?"
|
||||
if strings.Contains(DbCfg.Name,Param) {
|
||||
Param="&"
|
||||
}
|
||||
switch DbCfg.Type {
|
||||
case "mysql":
|
||||
if DbCfg.Host[0] == '/' { // looks like a unix socket
|
||||
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s?charset=utf8&parseTime=true",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
|
||||
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8&parseTime=true",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
|
||||
} else {
|
||||
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
|
||||
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8&parseTime=true",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
|
||||
}
|
||||
case "postgres":
|
||||
var host, port = "127.0.0.1", "5432"
|
||||
@@ -139,8 +119,8 @@ func getEngine() (*xorm.Engine, error) {
|
||||
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
|
||||
port = fields[1]
|
||||
}
|
||||
cnnstr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s",
|
||||
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, DbCfg.SSLMode)
|
||||
cnnstr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
|
||||
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
|
||||
case "sqlite3":
|
||||
if !EnableSQLite3 {
|
||||
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
|
||||
@@ -191,12 +171,7 @@ func SetEngine() (err error) {
|
||||
return fmt.Errorf("Fail to create xorm.log: %v", err)
|
||||
}
|
||||
x.SetLogger(xorm.NewSimpleLogger(f))
|
||||
|
||||
x.ShowSQL = true
|
||||
x.ShowInfo = true
|
||||
x.ShowDebug = true
|
||||
x.ShowErr = true
|
||||
x.ShowWarn = true
|
||||
x.ShowSQL(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
712
models/org.go
712
models/org.go
@@ -10,14 +10,13 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOrgNotExist = errors.New("Organization does not exist")
|
||||
ErrTeamAlreadyExist = errors.New("Team already exist")
|
||||
ErrTeamNotExist = errors.New("Team does not exist")
|
||||
ErrTeamNameIllegal = errors.New("Team name contains illegal characters")
|
||||
ErrOrgNotExist = errors.New("Organization does not exist")
|
||||
ErrTeamNotExist = errors.New("Team does not exist")
|
||||
)
|
||||
|
||||
// IsOwnedBy returns true if given user is in the owner team.
|
||||
@@ -59,7 +58,7 @@ func (org *User) GetTeams() error {
|
||||
|
||||
// GetMembers returns all members of organization.
|
||||
func (org *User) GetMembers() error {
|
||||
ous, err := GetOrgUsersByOrgId(org.Id)
|
||||
ous, err := GetOrgUsersByOrgID(org.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -108,7 +107,10 @@ func CreateOrganization(org, owner *User) (err error) {
|
||||
|
||||
org.LowerName = strings.ToLower(org.Name)
|
||||
org.FullName = org.Name
|
||||
org.Rands = GetUserSalt()
|
||||
org.Salt = GetUserSalt()
|
||||
org.UseCustomAvatar = true
|
||||
org.MaxRepoCreation = -1
|
||||
org.NumTeams = 1
|
||||
org.NumMembers = 1
|
||||
|
||||
@@ -167,7 +169,7 @@ func GetOrgByName(name string) (*User, error) {
|
||||
}
|
||||
u := &User{
|
||||
LowerName: strings.ToLower(name),
|
||||
Type: ORGANIZATION,
|
||||
Type: USER_TYPE_ORGANIZATION,
|
||||
}
|
||||
has, err := x.Get(u)
|
||||
if err != nil {
|
||||
@@ -252,6 +254,27 @@ func IsPublicMembership(orgId, uid int64) bool {
|
||||
return has
|
||||
}
|
||||
|
||||
func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) {
|
||||
orgs := make([]*User, 0, 10)
|
||||
if !showAll {
|
||||
sess.And("`org_user`.is_public=?", true)
|
||||
}
|
||||
return orgs, sess.And("`org_user`.uid=?", userID).
|
||||
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
|
||||
}
|
||||
|
||||
// GetOrgsByUserID returns a list of organizations that the given user ID
|
||||
// has joined.
|
||||
func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
|
||||
return getOrgsByUserID(x.NewSession(), userID, showAll)
|
||||
}
|
||||
|
||||
// GetOrgsByUserIDDesc returns a list of organizations that the given user ID
|
||||
// has joined, ordered descending by the given condition.
|
||||
func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) {
|
||||
return getOrgsByUserID(x.NewSession().Desc(desc), userID, showAll)
|
||||
}
|
||||
|
||||
func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
|
||||
orgs := make([]*User, 0, 10)
|
||||
return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
|
||||
@@ -265,23 +288,28 @@ func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
|
||||
}
|
||||
|
||||
// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
|
||||
// given user ID and descring order by given condition.
|
||||
// given user ID, ordered descending by the given condition.
|
||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
||||
sess := x.NewSession()
|
||||
return getOwnedOrgsByUserID(sess.Desc(desc), userID)
|
||||
}
|
||||
|
||||
// GetOrgUsersByUserId returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
|
||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
|
||||
ous := make([]*OrgUser, 0, 10)
|
||||
err := x.Where("uid=?", uid).Find(&ous)
|
||||
sess := x.Where("uid=?", uid)
|
||||
if !all {
|
||||
// Only show public organizations
|
||||
sess.And("is_public=?", true)
|
||||
}
|
||||
err := sess.Find(&ous)
|
||||
return ous, err
|
||||
}
|
||||
|
||||
// GetOrgUsersByOrgId returns all organization-user relations by organization ID.
|
||||
func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
|
||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
||||
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
|
||||
ous := make([]*OrgUser, 0, 10)
|
||||
err := x.Where("org_id=?", orgId).Find(&ous)
|
||||
err := x.Where("org_id=?", orgID).Find(&ous)
|
||||
return ous, err
|
||||
}
|
||||
|
||||
@@ -398,611 +426,6 @@ func RemoveOrgUser(orgId, uid int64) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// ___________
|
||||
// \__ ___/___ _____ _____
|
||||
// | |_/ __ \\__ \ / \
|
||||
// | |\ ___/ / __ \| Y Y \
|
||||
// |____| \___ >____ /__|_| /
|
||||
// \/ \/ \/
|
||||
|
||||
const OWNER_TEAM = "Owners"
|
||||
|
||||
// Team represents a organization team.
|
||||
type Team struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
LowerName string
|
||||
Name string
|
||||
Description string
|
||||
Authorize AccessMode
|
||||
Repos []*Repository `xorm:"-"`
|
||||
Members []*User `xorm:"-"`
|
||||
NumRepos int
|
||||
NumMembers int
|
||||
}
|
||||
|
||||
// IsOwnerTeam returns true if team is owner team.
|
||||
func (t *Team) IsOwnerTeam() bool {
|
||||
return t.Name == OWNER_TEAM
|
||||
}
|
||||
|
||||
// IsTeamMember returns true if given user is a member of team.
|
||||
func (t *Team) IsMember(uid int64) bool {
|
||||
return IsTeamMember(t.OrgID, t.ID, uid)
|
||||
}
|
||||
|
||||
func (t *Team) getRepositories(e Engine) (err error) {
|
||||
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
|
||||
if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
|
||||
return fmt.Errorf("get team-repos: %v", err)
|
||||
}
|
||||
|
||||
t.Repos = make([]*Repository, 0, len(teamRepos))
|
||||
for i := range teamRepos {
|
||||
repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
|
||||
}
|
||||
t.Repos = append(t.Repos, repo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRepositories returns all repositories in team of organization.
|
||||
func (t *Team) GetRepositories() error {
|
||||
return t.getRepositories(x)
|
||||
}
|
||||
|
||||
func (t *Team) getMembers(e Engine) (err error) {
|
||||
t.Members, err = getTeamMembers(e, t.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetMembers returns all members in team of organization.
|
||||
func (t *Team) GetMembers() (err error) {
|
||||
return t.getMembers(x)
|
||||
}
|
||||
|
||||
// AddMember adds new member to team of organization.
|
||||
func (t *Team) AddMember(uid int64) error {
|
||||
return AddTeamMember(t.OrgID, t.ID, uid)
|
||||
}
|
||||
|
||||
// RemoveMember removes member from team of organization.
|
||||
func (t *Team) RemoveMember(uid int64) error {
|
||||
return RemoveTeamMember(t.OrgID, t.ID, uid)
|
||||
}
|
||||
|
||||
func (t *Team) hasRepository(e Engine, repoID int64) bool {
|
||||
return hasTeamRepo(e, t.OrgID, t.ID, repoID)
|
||||
}
|
||||
|
||||
// HasRepository returns true if given repository belong to team.
|
||||
func (t *Team) HasRepository(repoID int64) bool {
|
||||
return t.hasRepository(x, repoID)
|
||||
}
|
||||
|
||||
func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
|
||||
if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.NumRepos++
|
||||
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
|
||||
return fmt.Errorf("update team: %v", err)
|
||||
}
|
||||
|
||||
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
|
||||
return fmt.Errorf("recalculateAccesses: %v", err)
|
||||
}
|
||||
|
||||
if err = t.getMembers(e); err != nil {
|
||||
return fmt.Errorf("getMembers: %v", err)
|
||||
}
|
||||
for _, u := range t.Members {
|
||||
if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
|
||||
return fmt.Errorf("watchRepo: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRepository adds new repository to team of organization.
|
||||
func (t *Team) AddRepository(repo *Repository) (err error) {
|
||||
if repo.OwnerID != t.OrgID {
|
||||
return errors.New("Repository does not belong to organization")
|
||||
} else if t.HasRepository(repo.ID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = t.addRepository(sess, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
|
||||
if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.NumRepos--
|
||||
if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Don't need to recalculate when delete a repository from organization.
|
||||
if recalculate {
|
||||
if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = t.getMembers(e); err != nil {
|
||||
return fmt.Errorf("get team members: %v", err)
|
||||
}
|
||||
for _, u := range t.Members {
|
||||
has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveRepository removes repository from team of organization.
|
||||
func (t *Team) RemoveRepository(repoID int64) error {
|
||||
if !t.HasRepository(repoID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByID(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = t.removeRepository(sess, repo, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// NewTeam creates a record of new team.
|
||||
// It's caller's responsibility to assign organization ID.
|
||||
func NewTeam(t *Team) (err error) {
|
||||
if err = IsUsableName(t.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 err = IsUsableName(t.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
|
||||
return fmt.Errorf("update: %v", err)
|
||||
}
|
||||
|
||||
// Update access for team members if needed.
|
||||
if authChanged {
|
||||
if err = t.getRepositories(sess); err != nil {
|
||||
return fmt.Errorf("getRepositories:%v", err)
|
||||
}
|
||||
|
||||
for _, repo := range t.Repos {
|
||||
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
|
||||
return fmt.Errorf("recalculateTeamAccesses: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// DeleteTeam deletes given team.
|
||||
// It's caller's responsibility to assign organization ID.
|
||||
func DeleteTeam(t *Team) error {
|
||||
if err := t.GetRepositories(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get organization.
|
||||
org, err := GetUserByID(t.OrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete all accesses.
|
||||
for _, repo := range t.Repos {
|
||||
if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete team-user.
|
||||
if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete team.
|
||||
if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Update organization number of teams.
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// ___________ ____ ___
|
||||
// \__ ___/___ _____ _____ | | \______ ___________
|
||||
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
|
||||
// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
|
||||
// |____| \___ >____ /__|_| /______//____ >\___ >__|
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
// TeamUser represents an team-user relation.
|
||||
type TeamUser struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
||||
Uid int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
|
||||
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
|
||||
return has
|
||||
}
|
||||
|
||||
// IsTeamMember returns true if given user is a member of team.
|
||||
func IsTeamMember(orgID, teamID, uid int64) bool {
|
||||
return isTeamMember(x, orgID, teamID, uid)
|
||||
}
|
||||
|
||||
func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
|
||||
teamUsers := make([]*TeamUser, 0, 10)
|
||||
if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
|
||||
return nil, fmt.Errorf("get team-users: %v", err)
|
||||
}
|
||||
members := make([]*User, 0, len(teamUsers))
|
||||
for i := range teamUsers {
|
||||
member := new(User)
|
||||
if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
|
||||
return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
|
||||
}
|
||||
members = append(members, member)
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
// GetTeamMembers returns all members in given team of organization.
|
||||
func GetTeamMembers(teamID int64) ([]*User, error) {
|
||||
return getTeamMembers(x, teamID)
|
||||
}
|
||||
|
||||
func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
|
||||
tus := make([]*TeamUser, 0, 5)
|
||||
if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts := make([]*Team, len(tus))
|
||||
for i, tu := range tus {
|
||||
t := new(Team)
|
||||
has, err := e.Id(tu.TeamID).Get(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrTeamNotExist
|
||||
}
|
||||
ts[i] = t
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// GetUserTeams returns all teams that user belongs to in given organization.
|
||||
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
|
||||
return getUserTeams(x, orgId, uid)
|
||||
}
|
||||
|
||||
// AddTeamMember adds new member to given team of given organization.
|
||||
func AddTeamMember(orgId, teamId, uid int64) error {
|
||||
if IsTeamMember(orgId, teamId, uid) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := AddOrgUser(orgId, uid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get team and its repositories.
|
||||
t, err := GetTeamById(teamId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.NumMembers++
|
||||
|
||||
if err = t.GetRepositories(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tu := &TeamUser{
|
||||
Uid: uid,
|
||||
OrgID: orgId,
|
||||
TeamID: teamId,
|
||||
}
|
||||
if _, err = sess.Insert(tu); err != nil {
|
||||
return err
|
||||
} else if _, err = sess.Id(t.ID).Update(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Give access to team repositories.
|
||||
for _, repo := range t.Repos {
|
||||
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// We make sure it exists before.
|
||||
ou := new(OrgUser)
|
||||
if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
|
||||
return err
|
||||
}
|
||||
ou.NumTeams++
|
||||
if t.IsOwnerTeam() {
|
||||
ou.IsOwner = true
|
||||
}
|
||||
if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
|
||||
if !isTeamMember(e, orgId, teamId, uid) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get team and its repositories.
|
||||
t, err := getTeamById(e, teamId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the user to delete is the last member in owner team.
|
||||
if t.IsOwnerTeam() && t.NumMembers == 1 {
|
||||
return ErrLastOrgOwner{UID: uid}
|
||||
}
|
||||
|
||||
t.NumMembers--
|
||||
|
||||
if err = t.getRepositories(e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get organization.
|
||||
org, err := getUserByID(e, orgId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tu := &TeamUser{
|
||||
Uid: uid,
|
||||
OrgID: orgId,
|
||||
TeamID: teamId,
|
||||
}
|
||||
if _, err := e.Delete(tu); err != nil {
|
||||
return err
|
||||
} else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete access to team repositories.
|
||||
for _, repo := range t.Repos {
|
||||
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// This must exist.
|
||||
ou := new(OrgUser)
|
||||
_, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ou.NumTeams--
|
||||
if t.IsOwnerTeam() {
|
||||
ou.IsOwner = false
|
||||
}
|
||||
if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTeamMember removes member from given team of given organization.
|
||||
func RemoveTeamMember(orgId, teamId, uid int64) error {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// ___________ __________
|
||||
// \__ ___/___ _____ _____\______ \ ____ ______ ____
|
||||
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
|
||||
// | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
|
||||
// |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
|
||||
// \/ \/ \/ \/ \/|__|
|
||||
|
||||
// TeamRepo represents an team-repository relation.
|
||||
type TeamRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
|
||||
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
|
||||
return has
|
||||
}
|
||||
|
||||
// HasTeamRepo returns true if given repository belongs to team.
|
||||
func HasTeamRepo(orgID, teamID, repoID int64) bool {
|
||||
return hasTeamRepo(x, orgID, teamID, repoID)
|
||||
}
|
||||
|
||||
func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
|
||||
_, err := e.InsertOne(&TeamRepo{
|
||||
OrgID: orgID,
|
||||
TeamID: teamID,
|
||||
RepoID: repoID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTeamRepo adds new repository relation to team.
|
||||
func AddTeamRepo(orgID, teamID, repoID int64) error {
|
||||
return addTeamRepo(x, orgID, teamID, repoID)
|
||||
}
|
||||
|
||||
func removeTeamRepo(e Engine, teamID, repoID int64) error {
|
||||
_, err := e.Delete(&TeamRepo{
|
||||
TeamID: teamID,
|
||||
RepoID: repoID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveTeamRepo deletes repository relation to team.
|
||||
func RemoveTeamRepo(teamID, repoID int64) error {
|
||||
return removeTeamRepo(x, teamID, repoID)
|
||||
}
|
||||
|
||||
func removeOrgRepo(e Engine, orgID, repoID int64) error {
|
||||
_, err := e.Delete(&TeamRepo{
|
||||
OrgID: orgID,
|
||||
@@ -1015,3 +438,56 @@ func removeOrgRepo(e Engine, orgID, repoID int64) error {
|
||||
func RemoveOrgRepo(orgID, repoID int64) error {
|
||||
return removeOrgRepo(x, orgID, repoID)
|
||||
}
|
||||
|
||||
// GetUserRepositories gets all repositories of an organization,
|
||||
// that the user with the given userID has access to.
|
||||
func (org *User) GetUserRepositories(userID int64) (err error) {
|
||||
teams := make([]*Team, 0, org.NumTeams)
|
||||
if err = x.Sql(`SELECT team.id FROM team
|
||||
INNER JOIN team_user ON team_user.team_id = team.id
|
||||
WHERE team_user.org_id = ? AND team_user.uid = ?`, org.Id, userID).Find(&teams); err != nil {
|
||||
return fmt.Errorf("get teams: %v", err)
|
||||
}
|
||||
|
||||
teamIDs := make([]string, len(teams))
|
||||
for i := range teams {
|
||||
teamIDs[i] = com.ToStr(teams[i].ID)
|
||||
}
|
||||
if len(teamIDs) == 0 {
|
||||
// user has no team but "IN ()" is invalid SQL
|
||||
teamIDs = append(teamIDs, "-1") // there is no repo with id=-1
|
||||
}
|
||||
|
||||
repos := make([]*Repository, 0, 5)
|
||||
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
|
||||
INNER JOIN team_repo ON team_repo.repo_id = repository.id
|
||||
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
|
||||
GROUP BY repository.id`, strings.Join(teamIDs, ",")), org.Id, false).Find(&repos); err != nil {
|
||||
return fmt.Errorf("get repositories: %v", err)
|
||||
}
|
||||
org.Repos = repos
|
||||
|
||||
// FIXME: should I change this value inside method,
|
||||
// or only in location of caller where it's really needed?
|
||||
org.NumRepos = len(org.Repos)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTeams returns all teams that belong to organization,
|
||||
// and that the user has joined.
|
||||
func (org *User) GetUserTeams(userID int64) error {
|
||||
teams := make([]*Team, 0, 5)
|
||||
if err := x.Sql(`SELECT team.* FROM team
|
||||
INNER JOIN team_user ON team_user.team_id = team.id
|
||||
WHERE team_user.org_id = ? AND team_user.uid = ?`,
|
||||
org.Id, userID).Find(&teams); err != nil {
|
||||
return fmt.Errorf("get teams: %v", err)
|
||||
}
|
||||
|
||||
org.Teams = teams
|
||||
|
||||
// FIXME: should I change this value inside method,
|
||||
// or only in location of caller where it's really needed?
|
||||
org.NumTeams = len(org.Teams)
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
145
models/pull.go
145
models/pull.go
@@ -14,7 +14,9 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
@@ -56,20 +58,25 @@ type PullRequest struct {
|
||||
|
||||
HasMerged bool
|
||||
MergedCommitID string `xorm:"VARCHAR(40)"`
|
||||
Merged time.Time
|
||||
MergerID int64
|
||||
Merger *User `xorm:"-"`
|
||||
Merger *User `xorm:"-"`
|
||||
Merged time.Time `xorm:"-"`
|
||||
MergedUnix int64
|
||||
}
|
||||
|
||||
func (pr *PullRequest) BeforeUpdate() {
|
||||
pr.MergedUnix = pr.Merged.UTC().Unix()
|
||||
}
|
||||
|
||||
// Note: don't try to get Pull because will end up recursive querying.
|
||||
func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "merged":
|
||||
case "merged_unix":
|
||||
if !pr.HasMerged {
|
||||
return
|
||||
}
|
||||
|
||||
pr.Merged = regulateTimeZone(pr.Merged)
|
||||
pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,28 +131,30 @@ func (pr *PullRequest) CanAutoMerge() bool {
|
||||
|
||||
// Merge merges pull request to base repository.
|
||||
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
|
||||
if err = pr.GetHeadRepo(); err != nil {
|
||||
return fmt.Errorf("GetHeadRepo: %v", err)
|
||||
} else if err = pr.GetBaseRepo(); err != nil {
|
||||
return fmt.Errorf("GetBaseRepo: %v", err)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = pr.Issue.changeStatus(sess, doer, true); err != nil {
|
||||
if err = pr.Issue.changeStatus(sess, doer, pr.Issue.Repo, true); err != nil {
|
||||
return fmt.Errorf("Issue.changeStatus: %v", err)
|
||||
}
|
||||
|
||||
if err = pr.getHeadRepo(sess); err != nil {
|
||||
return fmt.Errorf("getHeadRepo: %v", err)
|
||||
}
|
||||
|
||||
headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
pr.MergedCommitID, err = headGitRepo.GetCommitIdOfBranch(pr.HeadBranch)
|
||||
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetCommitIdOfBranch: %v", err)
|
||||
return fmt.Errorf("GetBranchCommitID: %v", err)
|
||||
}
|
||||
|
||||
if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
|
||||
@@ -213,7 +222,38 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||
return fmt.Errorf("git push: %s", stderr)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
if err = sess.Commit(); err != nil {
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
}
|
||||
|
||||
// Compose commit repository action
|
||||
l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBetween: %v", err)
|
||||
}
|
||||
p := &api.PushPayload{
|
||||
Ref: "refs/heads/" + pr.BaseBranch,
|
||||
Before: pr.MergeBase,
|
||||
After: pr.MergedCommitID,
|
||||
CompareUrl: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullLink()),
|
||||
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(),
|
||||
},
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// patchConflicts is a list of conflit description from Git.
|
||||
@@ -221,6 +261,7 @@ var patchConflicts = []string{
|
||||
"patch does not apply",
|
||||
"already exists in working directory",
|
||||
"unrecognized input",
|
||||
"error:",
|
||||
}
|
||||
|
||||
// testPatch checks if patch can be merged to base repository without conflit.
|
||||
@@ -244,7 +285,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Trace("PullRequest[%d].testPatch(patchPath): %s", pr.ID, patchPath)
|
||||
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
|
||||
|
||||
if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopy: %v", err)
|
||||
@@ -252,7 +293,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
|
||||
// Checkout base branch.
|
||||
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("PullRequest.Merge(git checkout): %s", pr.BaseRepo.ID),
|
||||
fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID),
|
||||
"git", "checkout", pr.BaseBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git checkout: %s", stderr)
|
||||
@@ -260,12 +301,12 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
|
||||
pr.Status = PULL_REQUEST_STATUS_CHECKING
|
||||
_, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("testPatch(git apply --check): %d", pr.BaseRepo.ID),
|
||||
fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
|
||||
"git", "apply", "--check", patchPath)
|
||||
if err != nil {
|
||||
for i := range patchConflicts {
|
||||
if strings.Contains(stderr, patchConflicts[i]) {
|
||||
log.Trace("PullRequest[%d].testPatch(apply): has conflit", pr.ID)
|
||||
log.Trace("PullRequest[%d].testPatch (apply): has conflit", pr.ID)
|
||||
fmt.Println(stderr)
|
||||
pr.Status = PULL_REQUEST_STATUS_CONFLICT
|
||||
return nil
|
||||
@@ -294,16 +335,13 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
ActUserID: pull.Poster.Id,
|
||||
ActUserName: pull.Poster.Name,
|
||||
ActEmail: pull.Poster.Email,
|
||||
OpType: CREATE_PULL_REQUEST,
|
||||
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 {
|
||||
@@ -323,7 +361,17 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
return fmt.Errorf("insert pull repo: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
if err = sess.Commit(); err != nil {
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
}
|
||||
|
||||
if err = NotifyWatchers(act); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %v", err)
|
||||
} else if err = pull.MailParticipants(); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUnmergedPullRequest returnss a pull request that is open and has not been merged
|
||||
@@ -411,23 +459,16 @@ func (pr *PullRequest) UpdatePatch() (err error) {
|
||||
|
||||
if err = pr.GetBaseRepo(); err != nil {
|
||||
return fmt.Errorf("GetBaseRepo: %v", err)
|
||||
} else if err = pr.BaseRepo.GetOwner(); err != nil {
|
||||
return fmt.Errorf("GetOwner: %v", err)
|
||||
}
|
||||
|
||||
headRepoPath, err := pr.HeadRepo.RepoPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("HeadRepo.RepoPath: %v", err)
|
||||
}
|
||||
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
// Add a temporary remote.
|
||||
tmpRemote := com.ToStr(time.Now().UnixNano())
|
||||
if err = headGitRepo.AddRemote(tmpRemote, RepoPath(pr.BaseRepo.Owner.Name, pr.BaseRepo.Name)); err != nil {
|
||||
if err = headGitRepo.AddRemote(tmpRemote, RepoPath(pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name), true); err != nil {
|
||||
return fmt.Errorf("AddRemote: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
@@ -453,6 +494,37 @@ func (pr *PullRequest) UpdatePatch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PushToBaseRepo pushes commits from branches of head repository to
|
||||
// corresponding branches of base repository.
|
||||
// FIXME: Only push branches that are actually updates?
|
||||
func (pr *PullRequest) PushToBaseRepo() (err error) {
|
||||
log.Trace("PushToBaseRepo[%d]: pushing commits to base repo 'refs/pull/%d/head'", pr.BaseRepoID, pr.Index)
|
||||
|
||||
headRepoPath := pr.HeadRepo.RepoPath()
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
tmpRemoteName := fmt.Sprintf("tmp-pull-%d", pr.ID)
|
||||
if err = headGitRepo.AddRemote(tmpRemoteName, pr.BaseRepo.RepoPath(), false); err != nil {
|
||||
return fmt.Errorf("headGitRepo.AddRemote: %v", err)
|
||||
}
|
||||
// Make sure to remove the remote even if the push fails
|
||||
defer headGitRepo.RemoveRemote(tmpRemoteName)
|
||||
|
||||
headFile := fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
||||
|
||||
// Remove head in case there is a conflict.
|
||||
os.Remove(path.Join(pr.BaseRepo.RepoPath(), headFile))
|
||||
|
||||
if err = git.Push(headRepoPath, tmpRemoteName, fmt.Sprintf("%s:%s", pr.HeadBranch, headFile)); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddToTaskQueue adds itself to pull request test task queue.
|
||||
func (pr *PullRequest) AddToTaskQueue() {
|
||||
go PullRequestQueue.AddFunc(pr.ID, func() {
|
||||
@@ -469,6 +541,9 @@ func addHeadRepoTasks(prs []*PullRequest) {
|
||||
if err := pr.UpdatePatch(); err != nil {
|
||||
log.Error(4, "UpdatePatch: %v", err)
|
||||
continue
|
||||
} else if err := pr.PushToBaseRepo(); err != nil {
|
||||
log.Error(4, "PushToBaseRepo: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
pr.AddToTaskQueue()
|
||||
@@ -497,6 +572,14 @@ func AddTestPullRequestTask(repoID int64, branch string) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeUsernameInPullRequests(oldUserName, newUserName string) error {
|
||||
pr := PullRequest{
|
||||
HeadUserName: strings.ToLower(newUserName),
|
||||
}
|
||||
_, err := x.Cols("head_user_name").Where("head_user_name = ?", strings.ToLower(oldUserName)).Update(pr)
|
||||
return err
|
||||
}
|
||||
|
||||
// checkAndUpdateStatus checks if pull request is possible to levaing checking status,
|
||||
// and set to be either conflict or mergeable.
|
||||
func (pr *PullRequest) checkAndUpdateStatus() {
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
)
|
||||
|
||||
@@ -27,18 +28,24 @@ type Release struct {
|
||||
Target string
|
||||
Title string
|
||||
Sha1 string `xorm:"VARCHAR(40)"`
|
||||
NumCommits int
|
||||
NumCommitsBehind int `xorm:"-"`
|
||||
NumCommits int64
|
||||
NumCommitsBehind int64 `xorm:"-"`
|
||||
Note string `xorm:"TEXT"`
|
||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsPrerelease bool
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (r *Release) BeforeInsert() {
|
||||
r.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (r *Release) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created":
|
||||
r.Created = regulateTimeZone(r.Created)
|
||||
case "created_unix":
|
||||
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,23 +62,25 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
|
||||
// Only actual create when publish.
|
||||
if !rel.IsDraft {
|
||||
if !gitRepo.IsTagExist(rel.TagName) {
|
||||
commit, err := gitRepo.GetCommitOfBranch(rel.Target)
|
||||
commit, err := gitRepo.GetBranchCommit(rel.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
||||
}
|
||||
|
||||
// Trim '--' prefix to prevent command line argument vulnerability
|
||||
rel.TagName = strings.TrimPrefix(rel.TagName, "--")
|
||||
if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
commit, err := gitRepo.GetCommitOfTag(rel.TagName)
|
||||
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("GetTagCommit: %v", err)
|
||||
}
|
||||
|
||||
rel.NumCommits, err = commit.CommitsCount()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +133,7 @@ func GetReleaseByID(id int64) (*Release, error) {
|
||||
|
||||
// GetReleasesByRepoID returns a list of releases of repository.
|
||||
func GetReleasesByRepoID(repoID int64) (rels []*Release, err error) {
|
||||
err = x.Desc("created").Find(&rels, Release{RepoID: repoID})
|
||||
err = x.Desc("created_unix").Find(&rels, Release{RepoID: repoID})
|
||||
return rels, err
|
||||
}
|
||||
|
||||
@@ -175,12 +184,8 @@ func DeleteReleaseByID(id int64) error {
|
||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||
}
|
||||
|
||||
repoPath, err := repo.RepoPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("RepoPath: %v", err)
|
||||
}
|
||||
|
||||
_, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
|
||||
_, stderr, err := process.ExecDir(-1, repo.RepoPath(),
|
||||
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
|
||||
"git", "tag", "-d", rel.TagName)
|
||||
if err != nil && !strings.Contains(stderr, "not found") {
|
||||
return fmt.Errorf("git tag -d: %v - %s", err, stderr)
|
||||
|
||||
910
models/repo.go
910
models/repo.go
File diff suppressed because it is too large
Load Diff
57
models/repo_branch.go
Normal file
57
models/repo_branch.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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 (
|
||||
"github.com/gogits/git-module"
|
||||
)
|
||||
|
||||
type Branch struct {
|
||||
Path string
|
||||
Name string
|
||||
}
|
||||
|
||||
func GetBranchesByPath(path string) ([]*Branch, error) {
|
||||
gitRepo, err := git.OpenRepository(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
brs, err := gitRepo.GetBranches()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
branches := make([]*Branch, len(brs))
|
||||
for i := range brs {
|
||||
branches[i] = &Branch{
|
||||
Path: path,
|
||||
Name: brs[i],
|
||||
}
|
||||
}
|
||||
return branches, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) GetBranch(br string) (*Branch, error) {
|
||||
if !git.IsBranchExist(repo.RepoPath(), br) {
|
||||
return nil, &ErrBranchNotExist{br}
|
||||
}
|
||||
return &Branch{
|
||||
Path: repo.RepoPath(),
|
||||
Name: br,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) GetBranches() ([]*Branch, error) {
|
||||
return GetBranchesByPath(repo.RepoPath())
|
||||
}
|
||||
|
||||
func (br *Branch) GetCommit() (*git.Commit, error) {
|
||||
gitRepo, err := git.OpenRepository(br.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gitRepo.GetBranchCommit(br.Name)
|
||||
}
|
||||
160
models/repo_collaboration.go
Normal file
160
models/repo_collaboration.go
Normal file
@@ -0,0 +1,160 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
func (c *Collaboration) ModeI18nKey() string {
|
||||
switch c.Mode {
|
||||
case ACCESS_MODE_READ:
|
||||
return "repo.settings.collaboration.read"
|
||||
case ACCESS_MODE_WRITE:
|
||||
return "repo.settings.collaboration.write"
|
||||
case ACCESS_MODE_ADMIN:
|
||||
return "repo.settings.collaboration.admin"
|
||||
default:
|
||||
return "repo.settings.collaboration.undefined"
|
||||
}
|
||||
}
|
||||
|
||||
// AddCollaborator adds new collaboration relation between an individual and a repository.
|
||||
func (repo *Repository) AddCollaborator(u *User) error {
|
||||
collaboration := &Collaboration{
|
||||
RepoID: repo.ID,
|
||||
UserID: u.Id,
|
||||
}
|
||||
|
||||
has, err := x.Get(collaboration)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
return nil
|
||||
}
|
||||
collaboration.Mode = ACCESS_MODE_WRITE
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.InsertOne(collaboration); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repo.Owner.IsOrganization() {
|
||||
err = repo.recalculateTeamAccesses(sess, 0)
|
||||
} else {
|
||||
err = repo.recalculateAccesses(sess)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("recalculateAccesses 'team=%v': %v", repo.Owner.IsOrganization(), err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func (repo *Repository) getCollaborations(e Engine) ([]*Collaboration, error) {
|
||||
collaborations := make([]*Collaboration, 0)
|
||||
return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID})
|
||||
}
|
||||
|
||||
// Collaborator represents a user with collaboration details.
|
||||
type Collaborator struct {
|
||||
*User
|
||||
Collaboration *Collaboration
|
||||
}
|
||||
|
||||
func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) {
|
||||
collaborations, err := repo.getCollaborations(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getCollaborations: %v", err)
|
||||
}
|
||||
|
||||
collaborators := make([]*Collaborator, len(collaborations))
|
||||
for i, c := range collaborations {
|
||||
user, err := getUserByID(e, c.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
collaborators[i] = &Collaborator{
|
||||
User: user,
|
||||
Collaboration: c,
|
||||
}
|
||||
}
|
||||
return collaborators, nil
|
||||
}
|
||||
|
||||
// GetCollaborators returns the collaborators for a repository
|
||||
func (repo *Repository) GetCollaborators() ([]*Collaborator, error) {
|
||||
return repo.getCollaborators(x)
|
||||
}
|
||||
|
||||
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
|
||||
func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode) error {
|
||||
// Discard invalid input
|
||||
if mode <= ACCESS_MODE_NONE || mode > ACCESS_MODE_OWNER {
|
||||
return nil
|
||||
}
|
||||
|
||||
collaboration := &Collaboration{
|
||||
RepoID: repo.ID,
|
||||
UserID: uid,
|
||||
}
|
||||
has, err := x.Get(collaboration)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get collaboration: %v", err)
|
||||
} else if !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
collaboration.Mode = mode
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.Id(collaboration.ID).AllCols().Update(collaboration); err != nil {
|
||||
return fmt.Errorf("update collaboration: %v", err)
|
||||
} else if _, err = sess.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil {
|
||||
return fmt.Errorf("update access table: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// DeleteCollaboration removes collaboration relation between the user and repository.
|
||||
func (repo *Repository) DeleteCollaboration(uid int64) (err error) {
|
||||
collaboration := &Collaboration{
|
||||
RepoID: repo.ID,
|
||||
UserID: uid,
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has, err := sess.Delete(collaboration); err != nil || has == 0 {
|
||||
return err
|
||||
} else if err = repo.recalculateAccesses(sess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
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}")
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
@@ -33,24 +35,6 @@ const (
|
||||
)
|
||||
|
||||
var sshOpLocker = sync.Mutex{}
|
||||
var SSHPath string // SSH directory.
|
||||
|
||||
// homeDir returns the home directory of current user.
|
||||
func homeDir() string {
|
||||
home, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get home directory: %v", err)
|
||||
}
|
||||
return home
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Determine and create .ssh path.
|
||||
SSHPath = filepath.Join(homeDir(), ".ssh")
|
||||
if err := os.MkdirAll(SSHPath, 0700); err != nil {
|
||||
log.Fatal(4, "fail to create '%s': %v", SSHPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
type KeyType int
|
||||
|
||||
@@ -61,22 +45,36 @@ const (
|
||||
|
||||
// PublicKey represents a SSH or deploy key.
|
||||
type PublicKey struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||
Name string `xorm:"NOT NULL"`
|
||||
Fingerprint string `xorm:"NOT NULL"`
|
||||
Content string `xorm:"TEXT NOT NULL"`
|
||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time // Note: Updated must below Created for AfterSet.
|
||||
HasRecentActivity bool `xorm:"-"`
|
||||
HasUsed bool `xorm:"-"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||
Name string `xorm:"NOT NULL"`
|
||||
Fingerprint string `xorm:"NOT NULL"`
|
||||
Content string `xorm:"TEXT NOT NULL"`
|
||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
|
||||
UpdatedUnix int64
|
||||
HasRecentActivity bool `xorm:"-"`
|
||||
HasUsed bool `xorm:"-"`
|
||||
}
|
||||
|
||||
func (k *PublicKey) BeforeInsert() {
|
||||
k.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (k *PublicKey) BeforeUpdate() {
|
||||
k.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created":
|
||||
case "created_unix":
|
||||
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
||||
case "updated_unix":
|
||||
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
||||
k.HasUsed = k.Updated.After(k.Created)
|
||||
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
||||
}
|
||||
@@ -95,19 +93,18 @@ func (key *PublicKey) GetAuthorizedString() string {
|
||||
func extractTypeFromBase64Key(key string) (string, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(key)
|
||||
if err != nil || len(b) < 4 {
|
||||
return "", errors.New("Invalid key format")
|
||||
return "", fmt.Errorf("Invalid key format: %v", err)
|
||||
}
|
||||
|
||||
keyLength := int(binary.BigEndian.Uint32(b))
|
||||
|
||||
if len(b) < 4+keyLength {
|
||||
return "", errors.New("Invalid key format")
|
||||
return "", fmt.Errorf("Invalid key format: not enough length")
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -170,8 +167,115 @@ func parseKeyString(content string) (string, error) {
|
||||
return keyType + " " + keyContent + " " + keyComment, nil
|
||||
}
|
||||
|
||||
// writeTmpKeyFile writes key content to a temporary file
|
||||
// and returns the name of that file, along with any possible errors.
|
||||
func writeTmpKeyFile(content string) (string, error) {
|
||||
tmpFile, err := ioutil.TempFile(setting.SSH.KeyTestPath, "gogs_keytest")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("TempFile: %v", err)
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
if _, err = tmpFile.WriteString(content); err != nil {
|
||||
return "", fmt.Errorf("tmpFile.WriteString: %v", err)
|
||||
}
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
|
||||
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
|
||||
// The ssh-keygen in Windows does not print key type, so no need go further.
|
||||
if setting.IsWindows {
|
||||
return "", 0, nil
|
||||
}
|
||||
|
||||
tmpName, err := writeTmpKeyFile(key)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("writeTmpKeyFile: %v", err)
|
||||
}
|
||||
defer os.Remove(tmpName)
|
||||
|
||||
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)
|
||||
}
|
||||
if strings.Contains(stdout, "is not a public key file") {
|
||||
return "", 0, ErrKeyUnableVerify{stdout}
|
||||
}
|
||||
|
||||
fields := strings.Split(stdout, " ")
|
||||
if len(fields) < 4 {
|
||||
return "", 0, fmt.Errorf("Invalid public key line: %s", stdout)
|
||||
}
|
||||
|
||||
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
|
||||
return strings.ToLower(keyType), com.StrTo(fields[0]).MustInt(), nil
|
||||
}
|
||||
|
||||
// SSHNativeParsePublicKey extracts the key type and length using the golang SSH library.
|
||||
// NOTE: ed25519 is not supported.
|
||||
func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
|
||||
fields := strings.Fields(keyLine)
|
||||
if len(fields) < 2 {
|
||||
return "", 0, fmt.Errorf("not enough fields in public key line: %s", string(keyLine))
|
||||
}
|
||||
|
||||
raw, err := base64.StdEncoding.DecodeString(fields[1])
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
pkey, err := ssh.ParsePublicKey(raw)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "ssh: unknown key algorithm") {
|
||||
return "", 0, ErrKeyUnableVerify{err.Error()}
|
||||
}
|
||||
return "", 0, fmt.Errorf("ssh.ParsePublicKey: %v", err)
|
||||
}
|
||||
|
||||
// The ssh library can parse the key, so next we find out what key exactly we have.
|
||||
switch pkey.Type() {
|
||||
case ssh.KeyAlgoDSA:
|
||||
rawPub := struct {
|
||||
Name string
|
||||
P, Q, G, Y *big.Int
|
||||
}{}
|
||||
if err := ssh.Unmarshal(pkey.Marshal(), &rawPub); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
// as per https://bugzilla.mindrot.org/show_bug.cgi?id=1647 we should never
|
||||
// see dsa keys != 1024 bit, but as it seems to work, we will not check here
|
||||
return "dsa", rawPub.P.BitLen(), nil // use P as per crypto/dsa/dsa.go (is L)
|
||||
case ssh.KeyAlgoRSA:
|
||||
rawPub := struct {
|
||||
Name string
|
||||
E *big.Int
|
||||
N *big.Int
|
||||
}{}
|
||||
if err := ssh.Unmarshal(pkey.Marshal(), &rawPub); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
return "rsa", rawPub.N.BitLen(), nil // use N as per crypto/rsa/rsa.go (is bits)
|
||||
case ssh.KeyAlgoECDSA256:
|
||||
return "ecdsa", 256, nil
|
||||
case ssh.KeyAlgoECDSA384:
|
||||
return "ecdsa", 384, nil
|
||||
case ssh.KeyAlgoECDSA521:
|
||||
return "ecdsa", 521, nil
|
||||
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())
|
||||
}
|
||||
|
||||
// CheckPublicKeyString checks if the given public key string is recognized by SSH.
|
||||
//
|
||||
// The function 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")
|
||||
}
|
||||
|
||||
content, err = parseKeyString(content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -182,50 +286,32 @@ func CheckPublicKeyString(content string) (_ string, err error) {
|
||||
return "", errors.New("only a single line with a single key please")
|
||||
}
|
||||
|
||||
// write the key to a file…
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "keytest")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpPath := tmpFile.Name()
|
||||
defer os.Remove(tmpPath)
|
||||
tmpFile.WriteString(content)
|
||||
tmpFile.Close()
|
||||
// remove any unnecessary whitespace now
|
||||
content = strings.TrimSpace(content)
|
||||
|
||||
// Check if ssh-keygen recognizes its contents.
|
||||
stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-lf", tmpPath)
|
||||
if err != nil {
|
||||
return "", errors.New("ssh-keygen -lf: " + stderr)
|
||||
} else if len(stdout) < 2 {
|
||||
return "", errors.New("ssh-keygen returned not enough output to evaluate the key: " + stdout)
|
||||
var (
|
||||
keyType string
|
||||
length int
|
||||
)
|
||||
if setting.SSH.StartBuiltinServer {
|
||||
keyType, length, err = SSHNativeParsePublicKey(content)
|
||||
} else {
|
||||
keyType, length, err = SSHKeyGenParsePublicKey(content)
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ParsePublicKey: %v", err)
|
||||
}
|
||||
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
|
||||
|
||||
// The ssh-keygen in Windows does not print key type, so no need go further.
|
||||
if setting.IsWindows {
|
||||
if !setting.SSH.MinimumKeySizeCheck {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
sshKeygenOutput := strings.Split(stdout, " ")
|
||||
if len(sshKeygenOutput) < 4 {
|
||||
return content, ErrKeyUnableVerify{stdout}
|
||||
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)
|
||||
}
|
||||
|
||||
// Check if key type and key size match.
|
||||
if !setting.Service.DisableMinimumKeySizeCheck {
|
||||
keySize := com.StrTo(sshKeygenOutput[0]).MustInt()
|
||||
if keySize == 0 {
|
||||
return "", errors.New("cannot get key size of the given key")
|
||||
}
|
||||
|
||||
keyType := strings.Trim(sshKeygenOutput[len(sshKeygenOutput)-1], " ()\n")
|
||||
if minimumKeySize := setting.Service.MinimumKeySizes[keyType]; minimumKeySize == 0 {
|
||||
return "", fmt.Errorf("unrecognized public key type: %s", keyType)
|
||||
} else if keySize < minimumKeySize {
|
||||
return "", fmt.Errorf("the minimum accepted size of a public key %s is %d", keyType, minimumKeySize)
|
||||
}
|
||||
}
|
||||
|
||||
return content, nil
|
||||
return "", fmt.Errorf("Key type is not allowed: %s", keyType)
|
||||
}
|
||||
|
||||
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
|
||||
@@ -233,7 +319,7 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
|
||||
sshOpLocker.Lock()
|
||||
defer sshOpLocker.Unlock()
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
|
||||
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -289,7 +375,7 @@ func addKey(e Engine, key *PublicKey) (err error) {
|
||||
}
|
||||
stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
|
||||
if err != nil {
|
||||
return errors.New("ssh-keygen -lf: " + stderr)
|
||||
return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
|
||||
} else if len(stdout) < 2 {
|
||||
return errors.New("not enough output for calculating fingerprint: " + stdout)
|
||||
}
|
||||
@@ -299,27 +385,33 @@ func addKey(e Engine, key *PublicKey) (err error) {
|
||||
if _, err = e.Insert(key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Don't need to rewrite this file if builtin SSH server is enabled.
|
||||
if setting.SSH.StartBuiltinServer {
|
||||
return nil
|
||||
}
|
||||
return saveAuthorizedKeyFile(key)
|
||||
}
|
||||
|
||||
// AddPublicKey adds new public key to database and authorized_keys file.
|
||||
func AddPublicKey(ownerID int64, name, content string) (err error) {
|
||||
if err = checkKeyContent(content); err != nil {
|
||||
return err
|
||||
func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
|
||||
log.Trace(content)
|
||||
if err := checkKeyContent(content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Key name of same user cannot be duplicated.
|
||||
has, err := x.Where("owner_id=? AND name=?", ownerID, name).Get(new(PublicKey))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
} else if has {
|
||||
return ErrKeyNameAlreadyUsed{ownerID, name}
|
||||
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := &PublicKey{
|
||||
@@ -330,10 +422,10 @@ func AddPublicKey(ownerID int64, name, content string) (err error) {
|
||||
Type: KEY_TYPE_USER,
|
||||
}
|
||||
if err = addKey(sess, key); err != nil {
|
||||
return fmt.Errorf("addKey: %v", err)
|
||||
return nil, fmt.Errorf("addKey: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
return key, sess.Commit()
|
||||
}
|
||||
|
||||
// GetPublicKeyByID returns public key by given ID.
|
||||
@@ -414,6 +506,11 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isFound {
|
||||
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -439,8 +536,13 @@ func deletePublicKey(e *xorm.Session, keyID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
|
||||
// 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 {
|
||||
@@ -450,12 +552,18 @@ func deletePublicKey(e *xorm.Session, keyID int64) error {
|
||||
}
|
||||
|
||||
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
||||
func DeletePublicKey(id int64) (err error) {
|
||||
has, err := x.Id(id).Get(new(PublicKey))
|
||||
func DeletePublicKey(doer *User, id int64) (err error) {
|
||||
key, err := GetPublicKeyByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return nil
|
||||
if IsErrKeyNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("GetPublicKeyByID: %v", err)
|
||||
}
|
||||
|
||||
// Check if user has access to delete this key.
|
||||
if !doer.IsAdmin && doer.Id != key.OwnerID {
|
||||
return ErrKeyAccessDenied{doer.Id, key.ID, "public"}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
@@ -476,7 +584,8 @@ func RewriteAllPublicKeys() error {
|
||||
sshOpLocker.Lock()
|
||||
defer sshOpLocker.Unlock()
|
||||
|
||||
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
|
||||
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
|
||||
tmpPath := fpath + ".tmp"
|
||||
f, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -492,7 +601,6 @@ func RewriteAllPublicKeys() error {
|
||||
return err
|
||||
}
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
if com.IsExist(fpath) {
|
||||
if err = os.Remove(fpath); err != nil {
|
||||
return err
|
||||
@@ -514,21 +622,35 @@ func RewriteAllPublicKeys() error {
|
||||
|
||||
// DeployKey represents deploy key information and its relation with repository.
|
||||
type DeployKey struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
KeyID int64 `xorm:"UNIQUE(s) INDEX"`
|
||||
RepoID int64 `xorm:"UNIQUE(s) INDEX"`
|
||||
Name string
|
||||
Fingerprint string
|
||||
Content string `xorm:"-"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time // Note: Updated must below Created for AfterSet.
|
||||
HasRecentActivity bool `xorm:"-"`
|
||||
HasUsed bool `xorm:"-"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
KeyID int64 `xorm:"UNIQUE(s) INDEX"`
|
||||
RepoID int64 `xorm:"UNIQUE(s) INDEX"`
|
||||
Name string
|
||||
Fingerprint string
|
||||
Content string `xorm:"-"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
|
||||
UpdatedUnix int64
|
||||
HasRecentActivity bool `xorm:"-"`
|
||||
HasUsed bool `xorm:"-"`
|
||||
}
|
||||
|
||||
func (k *DeployKey) BeforeInsert() {
|
||||
k.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (k *DeployKey) BeforeUpdate() {
|
||||
k.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created":
|
||||
case "created_unix":
|
||||
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
||||
case "updated_unix":
|
||||
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
||||
k.HasUsed = k.Updated.After(k.Created)
|
||||
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
||||
}
|
||||
@@ -656,13 +778,27 @@ func UpdateDeployKey(key *DeployKey) error {
|
||||
}
|
||||
|
||||
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
||||
func DeleteDeployKey(id int64) error {
|
||||
key := &DeployKey{ID: id}
|
||||
has, err := x.Id(key.ID).Get(key)
|
||||
func DeleteDeployKey(doer *User, id int64) error {
|
||||
key, err := GetDeployKeyByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return nil
|
||||
if IsErrDeployKeyNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("GetDeployKeyByID: %v", err)
|
||||
}
|
||||
|
||||
// Check if user has access to delete this key.
|
||||
if !doer.IsAdmin {
|
||||
repo, err := GetRepositoryByID(key.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||
}
|
||||
yes, err := HasAccess(doer, repo, ACCESS_MODE_ADMIN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HasAccess: %v", err)
|
||||
} else if !yes {
|
||||
return ErrKeyAccessDenied{doer.Id, key.ID, "deploy"}
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
@@ -676,7 +812,7 @@ func DeleteDeployKey(id int64) error {
|
||||
}
|
||||
|
||||
// Check if this is the last reference to same key content.
|
||||
has, err = sess.Where("key_id=?", key.KeyID).Get(new(DeployKey))
|
||||
has, err := sess.Where("key_id=?", key.KeyID).Get(new(DeployKey))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
45
models/ssh_key_test.go
Normal file
45
models/ssh_key_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
func init() {
|
||||
setting.NewContext()
|
||||
}
|
||||
|
||||
func Test_SSHParsePublicKey(t *testing.T) {
|
||||
testKeys := map[string]struct {
|
||||
typeName string
|
||||
length int
|
||||
content string
|
||||
}{
|
||||
"dsa-1024": {"dsa", 1024, "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment"},
|
||||
"rsa-1024": {"rsa", 1024, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n"},
|
||||
"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"},
|
||||
}
|
||||
|
||||
Convey("Parse public keys in both native and ssh-keygen", t, func() {
|
||||
for name, key := range testKeys {
|
||||
fmt.Println("\nTesting key:", name)
|
||||
|
||||
keyTypeN, lengthN, errN := SSHNativeParsePublicKey(key.content)
|
||||
So(errN, ShouldBeNil)
|
||||
So(keyTypeN, ShouldEqual, key.typeName)
|
||||
So(lengthN, ShouldEqual, key.length)
|
||||
|
||||
keyTypeK, lengthK, errK := SSHKeyGenParsePublicKey(key.content)
|
||||
So(errK, ShouldBeNil)
|
||||
So(keyTypeK, ShouldEqual, key.typeName)
|
||||
So(lengthK, ShouldEqual, key.length)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -7,31 +7,58 @@ package models
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
// AccessToken represents a personal access token.
|
||||
type AccessToken struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UID int64 `xorm:"INDEX"`
|
||||
Name string
|
||||
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UID int64 `xorm:"INDEX"`
|
||||
Name string
|
||||
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
|
||||
UpdatedUnix int64
|
||||
HasRecentActivity bool `xorm:"-"`
|
||||
HasUsed bool `xorm:"-"`
|
||||
}
|
||||
|
||||
func (t *AccessToken) BeforeInsert() {
|
||||
t.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (t *AccessToken) BeforeUpdate() {
|
||||
t.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created_unix":
|
||||
t.Created = time.Unix(t.CreatedUnix, 0).Local()
|
||||
case "updated_unix":
|
||||
t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
|
||||
t.HasUsed = t.Updated.After(t.Created)
|
||||
t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
// NewAccessToken creates new access token.
|
||||
func NewAccessToken(t *AccessToken) error {
|
||||
t.Sha1 = base.EncodeSha1(uuid.NewV4().String())
|
||||
t.Sha1 = base.EncodeSha1(gouuid.NewV4().String())
|
||||
_, err := x.Insert(t)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -45,20 +72,11 @@ 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)
|
||||
}
|
||||
|
||||
// UpdateAccessToekn updates information of access token.
|
||||
func UpdateAccessToekn(t *AccessToken) error {
|
||||
// UpdateAccessToken updates information of access token.
|
||||
func UpdateAccessToken(t *AccessToken) error {
|
||||
_, err := x.Id(t.ID).AllCols().Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
193
models/update.go
193
models/update.go
@@ -10,7 +10,8 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
git "github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
)
|
||||
|
||||
@@ -46,92 +47,7 @@ func DeleteUpdateTaskByUUID(uuid string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName string, userID int64) error {
|
||||
isNew := strings.HasPrefix(oldCommitID, "0000000")
|
||||
if isNew &&
|
||||
strings.HasPrefix(newCommitID, "0000000") {
|
||||
return fmt.Errorf("old rev and new rev both 000000")
|
||||
}
|
||||
|
||||
f := RepoPath(repoUserName, repoName)
|
||||
|
||||
gitUpdate := exec.Command("git", "update-server-info")
|
||||
gitUpdate.Dir = f
|
||||
gitUpdate.Run()
|
||||
|
||||
isDel := strings.HasPrefix(newCommitID, "0000000")
|
||||
if isDel {
|
||||
log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.Open repoId: %v", err)
|
||||
}
|
||||
|
||||
user, err := GetUserByName(repoUserName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.GetUserByName: %v", err)
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(user.Id, repoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err)
|
||||
}
|
||||
|
||||
// Push tags.
|
||||
if strings.HasPrefix(refName, "refs/tags/") {
|
||||
tagName := git.RefEndName(refName)
|
||||
tag, err := gitRepo.GetTag(tagName)
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err)
|
||||
}
|
||||
|
||||
var actEmail string
|
||||
if tag.Tagger != nil {
|
||||
actEmail = tag.Tagger.Email
|
||||
} else {
|
||||
cmt, err := tag.Commit()
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(4, "runUpdate.GetTag Commit: %v", err)
|
||||
}
|
||||
actEmail = cmt.Committer.Email
|
||||
}
|
||||
|
||||
commit := &PushCommits{}
|
||||
|
||||
if err = CommitRepoAction(userID, user.Id, userName, actEmail,
|
||||
repo.ID, repoUserName, repoName, refName, commit, oldCommitID, newCommitID); err != nil {
|
||||
log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
newCommit, err := gitRepo.GetCommit(newCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
|
||||
}
|
||||
|
||||
// Push new branch.
|
||||
var l *list.List
|
||||
if isNew {
|
||||
l, err = newCommit.CommitsBefore()
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBefore: %v", err)
|
||||
}
|
||||
} else {
|
||||
l, err = newCommit.CommitsBeforeUntil(oldCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBeforeUntil: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.Commit repoId: %v", err)
|
||||
}
|
||||
|
||||
// Push commits.
|
||||
func ListToPushCommits(l *list.List) *PushCommits {
|
||||
commits := make([]*PushCommit, 0)
|
||||
var actEmail string
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
@@ -146,10 +62,107 @@ func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName
|
||||
commit.Author.Name,
|
||||
})
|
||||
}
|
||||
return &PushCommits{l.Len(), commits, "", nil}
|
||||
}
|
||||
|
||||
if err = CommitRepoAction(userID, user.Id, userName, actEmail,
|
||||
repo.ID, repoUserName, repoName, refName, &PushCommits{l.Len(), commits, "", nil}, oldCommitID, newCommitID); err != nil {
|
||||
return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||
type PushUpdateOptions struct {
|
||||
RefName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
PusherID int64
|
||||
PusherName string
|
||||
RepoUserName string
|
||||
RepoName 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")
|
||||
if isNewRef && isDelRef {
|
||||
return fmt.Errorf("Old and new revisions both start with 000000")
|
||||
}
|
||||
|
||||
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
||||
|
||||
gitUpdate := exec.Command("git", "update-server-info")
|
||||
gitUpdate.Dir = repoPath
|
||||
if err = gitUpdate.Run(); err != nil {
|
||||
return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
|
||||
}
|
||||
|
||||
if isDelRef {
|
||||
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d",
|
||||
opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
||||
return nil
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
repoUser, err := GetUserByName(opts.RepoUserName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByName: %v", err)
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(repoUser.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 {
|
||||
return fmt.Errorf("CommitRepoAction (tag): %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gitRepo.GetCommit: %v", err)
|
||||
}
|
||||
|
||||
// Push new branch.
|
||||
var l *list.List
|
||||
if isNewRef {
|
||||
l, err = newCommit.CommitsBeforeLimit(10)
|
||||
if err != nil {
|
||||
return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
|
||||
}
|
||||
} else {
|
||||
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, repoUser.Email,
|
||||
repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, ListToPushCommits(l),
|
||||
opts.OldCommitID, opts.NewCommitID); err != nil {
|
||||
return fmt.Errorf("CommitRepoAction (branch): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
520
models/user.go
520
models/user.go
@@ -16,7 +16,6 @@ import (
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -25,18 +24,20 @@ import (
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/markdown"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
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 (
|
||||
@@ -55,7 +56,7 @@ type User struct {
|
||||
LowerName string `xorm:"UNIQUE NOT NULL"`
|
||||
Name string `xorm:"UNIQUE NOT NULL"`
|
||||
FullName string
|
||||
// Email is the primary email address (to be used for communication).
|
||||
// Email is the primary email address (to be used for communication)
|
||||
Email string `xorm:"NOT NULL"`
|
||||
Passwd string `xorm:"NOT NULL"`
|
||||
LoginType LoginType
|
||||
@@ -67,32 +68,38 @@ 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
|
||||
// Maximum repository creation limit, -1 means use gloabl default
|
||||
MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
|
||||
|
||||
// Permissions.
|
||||
IsActive bool
|
||||
// Permissions
|
||||
IsActive bool // Activate primary email
|
||||
IsAdmin bool
|
||||
AllowGitHook bool
|
||||
AllowImportLocal bool // Allow migrate repository by local path
|
||||
ProhibitLogin bool
|
||||
|
||||
// Avatar.
|
||||
// Avatar
|
||||
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
|
||||
AvatarEmail string `xorm:"NOT NULL"`
|
||||
UseCustomAvatar bool
|
||||
|
||||
// Counters.
|
||||
NumFollowers int
|
||||
NumFollowings int
|
||||
NumStars int
|
||||
NumRepos int
|
||||
// Counters
|
||||
NumFollowers int
|
||||
NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
|
||||
NumStars int
|
||||
NumRepos int
|
||||
|
||||
// For organization.
|
||||
// For organization
|
||||
Description string
|
||||
NumTeams int
|
||||
NumMembers int
|
||||
@@ -100,21 +107,57 @@ type User struct {
|
||||
Members []*User `xorm:"-"`
|
||||
}
|
||||
|
||||
func (u *User) BeforeInsert() {
|
||||
u.CreatedUnix = time.Now().UTC().Unix()
|
||||
u.UpdatedUnix = u.CreatedUnix
|
||||
}
|
||||
|
||||
func (u *User) BeforeUpdate() {
|
||||
if u.MaxRepoCreation < -1 {
|
||||
u.MaxRepoCreation = -1
|
||||
}
|
||||
u.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (u *User) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "full_name":
|
||||
u.FullName = base.Sanitizer.Sanitize(u.FullName)
|
||||
case "created":
|
||||
u.Created = regulateTimeZone(u.Created)
|
||||
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
|
||||
case "created_unix":
|
||||
u.Created = time.Unix(u.CreatedUnix, 0).Local()
|
||||
case "updated_unix":
|
||||
u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if user login type is LOGIN_PLAIN.
|
||||
func (u *User) IsLocal() bool {
|
||||
return u.LoginType <= LOGIN_PLAIN
|
||||
}
|
||||
|
||||
// HasForkedRepo checks if user has already forked a repository with given ID.
|
||||
func (u *User) HasForkedRepo(repoID int64) bool {
|
||||
_, has := HasForkedRepo(u.Id, repoID)
|
||||
return has
|
||||
}
|
||||
|
||||
func (u *User) RepoCreationNum() int {
|
||||
if u.MaxRepoCreation <= -1 {
|
||||
return setting.Repository.MaxCreationLimit
|
||||
}
|
||||
return u.MaxRepoCreation
|
||||
}
|
||||
|
||||
func (u *User) CanCreateRepo() bool {
|
||||
if u.MaxRepoCreation <= -1 {
|
||||
if setting.Repository.MaxCreationLimit <= -1 {
|
||||
return true
|
||||
}
|
||||
return u.NumRepos < setting.Repository.MaxCreationLimit
|
||||
}
|
||||
return u.NumRepos < u.MaxRepoCreation
|
||||
}
|
||||
|
||||
// CanEditGitHook returns true if user can edit Git hooks.
|
||||
func (u *User) CanEditGitHook() bool {
|
||||
return u.IsAdmin || u.AllowGitHook
|
||||
@@ -125,16 +168,6 @@ func (u *User) CanImportLocal() bool {
|
||||
return u.IsAdmin || u.AllowImportLocal
|
||||
}
|
||||
|
||||
// EmailAdresses is the list of all email addresses of a user. Can contain the
|
||||
// primary email address, but is not obligatory
|
||||
type EmailAddress struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UID int64 `xorm:"INDEX NOT NULL"`
|
||||
Email string `xorm:"UNIQUE NOT NULL"`
|
||||
IsActivated bool
|
||||
IsPrimary bool `xorm:"-"`
|
||||
}
|
||||
|
||||
// DashboardLink returns the user dashboard page link.
|
||||
func (u *User) DashboardLink() string {
|
||||
if u.IsOrganization() {
|
||||
@@ -145,9 +178,6 @@ func (u *User) DashboardLink() string {
|
||||
|
||||
// HomeLink returns the user or organization home page link.
|
||||
func (u *User) HomeLink() string {
|
||||
if u.IsOrganization() {
|
||||
return setting.AppSubUrl + "/org/" + u.Name
|
||||
}
|
||||
return setting.AppSubUrl + "/" + u.Name
|
||||
}
|
||||
|
||||
@@ -183,7 +213,7 @@ func (u *User) GenerateRandomAvatar() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("RandomImage: %v", err)
|
||||
}
|
||||
if err = os.MkdirAll(path.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
|
||||
if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("MkdirAll: %v", err)
|
||||
}
|
||||
fw, err := os.Create(u.CustomAvatarPath())
|
||||
@@ -201,7 +231,7 @@ func (u *User) GenerateRandomAvatar() error {
|
||||
}
|
||||
|
||||
func (u *User) RelAvatarLink() string {
|
||||
defaultImgUrl := "/img/avatar_default.jpg"
|
||||
defaultImgUrl := "/img/avatar_default.png"
|
||||
if u.Id == -1 {
|
||||
return defaultImgUrl
|
||||
}
|
||||
@@ -220,21 +250,47 @@ func (u *User) RelAvatarLink() string {
|
||||
}
|
||||
|
||||
return "/avatars/" + com.ToStr(u.Id)
|
||||
case setting.Service.EnableCacheAvatar:
|
||||
return "/avatar/" + u.Avatar
|
||||
}
|
||||
return setting.GravatarSource + u.Avatar
|
||||
}
|
||||
|
||||
// AvatarLink returns user gravatar link.
|
||||
// AvatarLink returns user avatar link.
|
||||
func (u *User) AvatarLink() string {
|
||||
link := u.RelAvatarLink()
|
||||
if link[0] == '/' && link[1] != '/' {
|
||||
return setting.AppSubUrl + link
|
||||
return strings.TrimSuffix(setting.AppUrl, "/") + link
|
||||
}
|
||||
return link
|
||||
}
|
||||
|
||||
// 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)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "follow", "user.id=follow.user_id")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
func (u *User) IsFollowing(followID int64) bool {
|
||||
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)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "follow", "user.id=follow.follow_id")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
// NewGitSig generates and returns the signature of given user.
|
||||
func (u *User) NewGitSig() *git.Signature {
|
||||
return &git.Signature{
|
||||
@@ -292,28 +348,39 @@ func (u *User) UploadAvatar(data []byte) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// DeleteAvatar deletes the user's custom avatar.
|
||||
func (u *User) DeleteAvatar() error {
|
||||
log.Trace("DeleteAvatar[%d]: %s", u.Id, u.CustomAvatarPath())
|
||||
os.Remove(u.CustomAvatarPath())
|
||||
|
||||
u.UseCustomAvatar = false
|
||||
if err := UpdateUser(u); err != nil {
|
||||
return fmt.Errorf("UpdateUser: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsAdminOfRepo returns true if user has admin or higher access of repository.
|
||||
func (u *User) IsAdminOfRepo(repo *Repository) bool {
|
||||
if err := repo.GetOwner(); err != nil {
|
||||
log.Error(3, "GetOwner: %v", err)
|
||||
return false
|
||||
has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
|
||||
if err != nil {
|
||||
log.Error(3, "HasAccess: %v", err)
|
||||
}
|
||||
return has
|
||||
}
|
||||
|
||||
if repo.Owner.IsOrganization() {
|
||||
has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
|
||||
if err != nil {
|
||||
log.Error(3, "HasAccess: %v", err)
|
||||
return false
|
||||
}
|
||||
return has
|
||||
// IsWriterOfRepo returns true if user has write access to given repository.
|
||||
func (u *User) IsWriterOfRepo(repo *Repository) bool {
|
||||
has, err := HasAccess(u, repo, ACCESS_MODE_WRITE)
|
||||
if err != nil {
|
||||
log.Error(3, "HasAccess: %v", err)
|
||||
}
|
||||
|
||||
return repo.IsOwnedBy(u.Id)
|
||||
return has
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -348,8 +415,8 @@ func (u *User) GetOwnedOrganizations() (err error) {
|
||||
}
|
||||
|
||||
// GetOrganizations returns all organizations that user belongs to.
|
||||
func (u *User) GetOrganizations() error {
|
||||
ous, err := GetOrgUsersByUserId(u.Id)
|
||||
func (u *User) GetOrganizations(all bool) error {
|
||||
ous, err := GetOrgUsersByUserID(u.Id, all)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -373,13 +440,8 @@ func (u *User) DisplayName() string {
|
||||
return u.Name
|
||||
}
|
||||
|
||||
// ShortName returns shorted user name with given maximum length,
|
||||
// it adds "..." at the end if user name has more length than maximum.
|
||||
func (u *User) ShortName(length int) string {
|
||||
if len(u.Name) < length {
|
||||
return u.Name
|
||||
}
|
||||
return u.Name[:length] + "..."
|
||||
return base.EllipsisString(u.Name, length)
|
||||
}
|
||||
|
||||
// IsUserExist checks if given user name exist,
|
||||
@@ -393,19 +455,6 @@ func IsUserExist(uid int64, name string) (bool, error) {
|
||||
return x.Where("id!=?", uid).Get(&User{LowerName: strings.ToLower(name)})
|
||||
}
|
||||
|
||||
// IsEmailUsed returns true if the e-mail has been used.
|
||||
func IsEmailUsed(email string) (bool, error) {
|
||||
if len(email) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
email = strings.ToLower(email)
|
||||
if has, err := x.Get(&EmailAddress{Email: email}); has || err != nil {
|
||||
return has, err
|
||||
}
|
||||
return x.Get(&User{Email: email})
|
||||
}
|
||||
|
||||
// GetUserSalt returns a ramdom user salt token.
|
||||
func GetUserSalt() string {
|
||||
return base.GetRandomString(10)
|
||||
@@ -433,6 +482,7 @@ func CreateUser(u *User) (err error) {
|
||||
return ErrUserAlreadyExist{u.Name}
|
||||
}
|
||||
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
isExist, err = IsEmailUsed(u.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -442,22 +492,21 @@ func CreateUser(u *User) (err error) {
|
||||
|
||||
u.LowerName = strings.ToLower(u.Name)
|
||||
u.AvatarEmail = u.Email
|
||||
u.Avatar = avatar.HashEmail(u.AvatarEmail)
|
||||
u.Avatar = base.HashEmail(u.AvatarEmail)
|
||||
u.Rands = GetUserSalt()
|
||||
u.Salt = GetUserSalt()
|
||||
u.EncodePasswd()
|
||||
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
|
||||
}
|
||||
|
||||
@@ -546,11 +595,24 @@ func ChangeUserName(u *User, newUserName string) (err error) {
|
||||
return ErrUserAlreadyExist{newUserName}
|
||||
}
|
||||
|
||||
return os.Rename(UserPath(u.LowerName), UserPath(newUserName))
|
||||
if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil {
|
||||
return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
repo := bean.(*Repository)
|
||||
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Delete repository wiki local copy: %v", err)
|
||||
}
|
||||
|
||||
return os.Rename(UserPath(u.Name), UserPath(newUserName))
|
||||
}
|
||||
|
||||
func updateUser(e Engine, u *User) error {
|
||||
// Organization does not need e-mail.
|
||||
// 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))
|
||||
@@ -563,22 +625,15 @@ func updateUser(e Engine, u *User) error {
|
||||
if len(u.AvatarEmail) == 0 {
|
||||
u.AvatarEmail = u.Email
|
||||
}
|
||||
u.Avatar = avatar.HashEmail(u.AvatarEmail)
|
||||
u.Avatar = base.HashEmail(u.AvatarEmail)
|
||||
}
|
||||
|
||||
u.LowerName = strings.ToLower(u.Name)
|
||||
u.Location = base.TruncateString(u.Location, 255)
|
||||
u.Website = base.TruncateString(u.Website, 255)
|
||||
u.Description = base.TruncateString(u.Description, 255)
|
||||
|
||||
if len(u.Location) > 255 {
|
||||
u.Location = u.Location[:255]
|
||||
}
|
||||
if len(u.Website) > 255 {
|
||||
u.Website = u.Website[:255]
|
||||
}
|
||||
if len(u.Description) > 255 {
|
||||
u.Description = u.Description[:255]
|
||||
}
|
||||
|
||||
u.FullName = base.Sanitizer.Sanitize(u.FullName)
|
||||
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
|
||||
_, err := e.Id(u.Id).AllCols().Update(u)
|
||||
return err
|
||||
}
|
||||
@@ -666,7 +721,7 @@ func deleteUser(e *xorm.Session, u *User) error {
|
||||
&IssueUser{UID: u.Id},
|
||||
&EmailAddress{UID: u.Id},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteUser: %v", err)
|
||||
return fmt.Errorf("deleteBeans: %v", err)
|
||||
}
|
||||
|
||||
// ***** START: PublicKey *****
|
||||
@@ -809,8 +864,8 @@ func GetUserEmailsByNames(names []string) []string {
|
||||
return mails
|
||||
}
|
||||
|
||||
// GetUserIdsByNames returns a slice of ids corresponds to names.
|
||||
func GetUserIdsByNames(names []string) []int64 {
|
||||
// GetUserIDsByNames returns a slice of ids corresponds to names.
|
||||
func GetUserIDsByNames(names []string) []int64 {
|
||||
ids := make([]int64, 0, len(names))
|
||||
for _, name := range names {
|
||||
u, err := GetUserByName(name)
|
||||
@@ -822,121 +877,6 @@ func GetUserIdsByNames(names []string) []int64 {
|
||||
return ids
|
||||
}
|
||||
|
||||
// GetEmailAddresses returns all e-mail addresses belongs to given user.
|
||||
func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
|
||||
emails := make([]*EmailAddress, 0, 5)
|
||||
err := x.Where("uid=?", uid).Find(&emails)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := GetUserByID(uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isPrimaryFound := false
|
||||
for _, email := range emails {
|
||||
if email.Email == u.Email {
|
||||
isPrimaryFound = true
|
||||
email.IsPrimary = true
|
||||
} else {
|
||||
email.IsPrimary = false
|
||||
}
|
||||
}
|
||||
|
||||
// We alway want the primary email address displayed, even if it's not in
|
||||
// the emailaddress table (yet)
|
||||
if !isPrimaryFound {
|
||||
emails = append(emails, &EmailAddress{
|
||||
Email: u.Email,
|
||||
IsActivated: true,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
return emails, nil
|
||||
}
|
||||
|
||||
func AddEmailAddress(email *EmailAddress) error {
|
||||
email.Email = strings.ToLower(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 (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) error {
|
||||
has, err := x.Get(email)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return ErrEmailNotExist
|
||||
}
|
||||
|
||||
if _, err = x.Id(email.ID).Delete(email); 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
|
||||
@@ -1009,112 +949,116 @@ 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)
|
||||
|
||||
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
|
||||
type SearchUserOptions struct {
|
||||
Keyword string
|
||||
Type UserType
|
||||
OrderBy string
|
||||
Page int
|
||||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
||||
}
|
||||
|
||||
// Follow is connection request for receiving user notification.
|
||||
// SearchUserByName takes keyword and part of user name to search,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
|
||||
if len(opts.Keyword) == 0 {
|
||||
return users, 0, nil
|
||||
}
|
||||
opts.Keyword = strings.ToLower(opts.Keyword)
|
||||
|
||||
if opts.PageSize <= 0 || opts.PageSize > setting.ExplorePagingNum {
|
||||
opts.PageSize = setting.ExplorePagingNum
|
||||
}
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
|
||||
searchQuery := "%" + opts.Keyword + "%"
|
||||
users = make([]*User, 0, opts.PageSize)
|
||||
// Append conditions
|
||||
sess := x.Where("LOWER(lower_name) LIKE ?", searchQuery).
|
||||
Or("LOWER(full_name) LIKE ?", searchQuery).
|
||||
And("type = ?", opts.Type)
|
||||
|
||||
var countSess xorm.Session
|
||||
countSess = *sess
|
||||
count, err := countSess.Count(new(User))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("Count: %v", err)
|
||||
}
|
||||
|
||||
if len(opts.OrderBy) > 0 {
|
||||
sess.OrderBy(opts.OrderBy)
|
||||
}
|
||||
return users, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&users)
|
||||
}
|
||||
|
||||
// ___________ .__ .__
|
||||
// \_ _____/___ | | | | ______ _ __
|
||||
// | __)/ _ \| | | | / _ \ \/ \/ /
|
||||
// | \( <_> ) |_| |_( <_> ) /
|
||||
// \___ / \____/|____/____/\____/ \/\_/
|
||||
// \/
|
||||
|
||||
// Follow represents relations of user and his/her followers.
|
||||
type Follow struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(follow)"`
|
||||
FollowID int64 `xorm:"UNIQUE(follow)"`
|
||||
}
|
||||
|
||||
func IsFollowing(userID, followID int64) bool {
|
||||
has, _ := x.Get(&Follow{UserID: userID, FollowID: followID})
|
||||
return has
|
||||
}
|
||||
|
||||
// FollowUser marks someone be another's follower.
|
||||
func FollowUser(userId int64, followId int64) (err error) {
|
||||
func FollowUser(userID, followID int64) (err error) {
|
||||
if userID == followID || IsFollowing(userID, followID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
sess.Begin()
|
||||
|
||||
if _, err = sess.Insert(&Follow{UserID: userId, FollowID: followId}); err != nil {
|
||||
sess.Rollback()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
|
||||
if _, err = sess.Exec(rawSql, followId); err != nil {
|
||||
sess.Rollback()
|
||||
if _, err = sess.Insert(&Follow{UserID: userID, FollowID: followID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
|
||||
if _, err = sess.Exec(rawSql, userId); err != nil {
|
||||
sess.Rollback()
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", followID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", userID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// UnFollowUser unmarks someone be another's follower.
|
||||
func UnFollowUser(userId int64, unFollowId int64) (err error) {
|
||||
session := x.NewSession()
|
||||
defer session.Close()
|
||||
session.Begin()
|
||||
// UnfollowUser unmarks someone be another's follower.
|
||||
func UnfollowUser(userID, followID int64) (err error) {
|
||||
if userID == followID || !IsFollowing(userID, followID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err = session.Delete(&Follow{UserID: userId, FollowID: unFollowId}); err != nil {
|
||||
session.Rollback()
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?"
|
||||
if _, err = session.Exec(rawSql, unFollowId); err != nil {
|
||||
session.Rollback()
|
||||
if _, err = sess.Delete(&Follow{UserID: userID, FollowID: followID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?"
|
||||
if _, err = session.Exec(rawSql, userId); err != nil {
|
||||
session.Rollback()
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil {
|
||||
return err
|
||||
}
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func UpdateMentions(userNames []string, issueId int64) error {
|
||||
for i := range userNames {
|
||||
userNames[i] = strings.ToLower(userNames[i])
|
||||
}
|
||||
users := make([]*User, 0, len(userNames))
|
||||
|
||||
if err := x.Where("lower_name IN (?)", strings.Join(userNames, "\",\"")).OrderBy("lower_name ASC").Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, len(userNames))
|
||||
for _, user := range users {
|
||||
ids = append(ids, user.Id)
|
||||
if !user.IsOrganization() {
|
||||
continue
|
||||
}
|
||||
|
||||
if user.NumMembers == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tempIds := make([]int64, 0, user.NumMembers)
|
||||
orgUsers, err := GetOrgUsersByOrgId(user.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, orgUser := range orgUsers {
|
||||
tempIds = append(tempIds, orgUser.ID)
|
||||
}
|
||||
|
||||
ids = append(ids, tempIds...)
|
||||
}
|
||||
|
||||
if err := UpdateIssueUsersByMentions(ids, issueId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/httplib"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
type HookContentType int
|
||||
@@ -94,8 +94,20 @@ type Webhook struct {
|
||||
HookTaskType HookTaskType
|
||||
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
||||
LastStatus HookStatus // Last delivery status
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
Updated time.Time `xorm:"UPDATED"`
|
||||
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
Updated time.Time `xorm:"-"`
|
||||
UpdatedUnix int64
|
||||
}
|
||||
|
||||
func (w *Webhook) BeforeInsert() {
|
||||
w.CreatedUnix = time.Now().UTC().Unix()
|
||||
w.UpdatedUnix = w.CreatedUnix
|
||||
}
|
||||
|
||||
func (w *Webhook) BeforeUpdate() {
|
||||
w.UpdatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
|
||||
@@ -106,8 +118,10 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
|
||||
if err = json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
||||
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
|
||||
}
|
||||
case "created":
|
||||
w.Created = regulateTimeZone(w.Created)
|
||||
case "created_unix":
|
||||
w.Created = time.Unix(w.CreatedUnix, 0).Local()
|
||||
case "updated_unix":
|
||||
w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,16 +174,32 @@ func CreateWebhook(w *Webhook) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// GetWebhookByID returns webhook by given ID.
|
||||
func GetWebhookByID(id int64) (*Webhook, error) {
|
||||
w := new(Webhook)
|
||||
has, err := x.Id(id).Get(w)
|
||||
// getWebhook uses argument bean as query condition,
|
||||
// ID must be specified and do not assign unnecessary fields.
|
||||
func getWebhook(bean *Webhook) (*Webhook, error) {
|
||||
has, err := x.Get(bean)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrWebhookNotExist{id}
|
||||
return nil, ErrWebhookNotExist{bean.ID}
|
||||
}
|
||||
return w, nil
|
||||
return bean, nil
|
||||
}
|
||||
|
||||
// GetWebhookByRepoID returns webhook of repository by given ID.
|
||||
func GetWebhookByRepoID(repoID, id int64) (*Webhook, error) {
|
||||
return getWebhook(&Webhook{
|
||||
ID: id,
|
||||
RepoID: repoID,
|
||||
})
|
||||
}
|
||||
|
||||
// GetWebhookByOrgID returns webhook of organization by given ID.
|
||||
func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
|
||||
return getWebhook(&Webhook{
|
||||
ID: id,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
|
||||
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
|
||||
@@ -190,25 +220,42 @@ func UpdateWebhook(w *Webhook) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteWebhook deletes webhook of repository.
|
||||
func DeleteWebhook(id int64) (err error) {
|
||||
// deleteWebhook uses argument bean as query condition,
|
||||
// ID must be specified and do not assign unnecessary fields.
|
||||
func deleteWebhook(bean *Webhook) (err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.Delete(&Webhook{ID: id}); err != nil {
|
||||
if _, err = sess.Delete(bean); err != nil {
|
||||
return err
|
||||
} else if _, err = sess.Delete(&HookTask{HookID: id}); err != nil {
|
||||
} else if _, err = sess.Delete(&HookTask{HookID: bean.ID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// GetWebhooksByOrgId returns all webhooks for an organization.
|
||||
func GetWebhooksByOrgId(orgID int64) (ws []*Webhook, err error) {
|
||||
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
|
||||
func DeleteWebhookByRepoID(repoID, id int64) (error) {
|
||||
return deleteWebhook(&Webhook{
|
||||
ID: id,
|
||||
RepoID: repoID,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteWebhookByOrgID deletes webhook of organization by given ID.
|
||||
func DeleteWebhookByOrgID(orgID, id int64) (error) {
|
||||
return deleteWebhook(&Webhook{
|
||||
ID: id,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
|
||||
// GetWebhooksByOrgID returns all webhooks for an organization.
|
||||
func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
|
||||
err = x.Find(&ws, &Webhook{OrgID: orgID})
|
||||
return ws, err
|
||||
}
|
||||
@@ -285,7 +332,7 @@ type HookTask struct {
|
||||
HookID int64
|
||||
UUID string
|
||||
Type HookTaskType
|
||||
URL string
|
||||
URL string `xorm:"TEXT"`
|
||||
api.Payloader `xorm:"-"`
|
||||
PayloadContent string `xorm:"TEXT"`
|
||||
ContentType HookContentType
|
||||
@@ -335,7 +382,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
|
||||
|
||||
t.ResponseInfo = &HookResponse{}
|
||||
if err = json.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
|
||||
log.Error(3, "Unmarshal[%d]: %v", t.ID, err)
|
||||
log.Error(3, "Unmarshal [%d]: %v", t.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,7 +390,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
|
||||
func (t *HookTask) MarshalJSON(v interface{}) string {
|
||||
p, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
log.Error(3, "Marshal[%d]: %v", t.ID, err)
|
||||
log.Error(3, "Marshal [%d]: %v", t.ID, err)
|
||||
}
|
||||
return string(p)
|
||||
}
|
||||
@@ -361,7 +408,7 @@ func CreateHookTask(t *HookTask) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.UUID = uuid.NewV4().String()
|
||||
t.UUID = gouuid.NewV4().String()
|
||||
t.PayloadContent = string(data)
|
||||
_, err = x.Insert(t)
|
||||
return err
|
||||
@@ -398,6 +445,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
return nil
|
||||
}
|
||||
|
||||
var payloader api.Payloader
|
||||
for _, w := range ws {
|
||||
switch event {
|
||||
case HOOK_EVENT_CREATE:
|
||||
@@ -410,14 +458,16 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
}
|
||||
}
|
||||
|
||||
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
|
||||
switch w.HookTaskType {
|
||||
case SLACK:
|
||||
p, err = GetSlackPayload(p, event, w.Meta)
|
||||
payloader, err = GetSlackPayload(p, event, w.Meta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetSlackPayload: %v", err)
|
||||
}
|
||||
default:
|
||||
p.SetSecret(w.Secret)
|
||||
payloader = p
|
||||
}
|
||||
|
||||
if err = CreateHookTask(&HookTask{
|
||||
@@ -425,7 +475,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
HookID: w.ID,
|
||||
Type: w.HookTaskType,
|
||||
URL: w.URL,
|
||||
Payloader: p,
|
||||
Payloader: payloader,
|
||||
ContentType: w.ContentType,
|
||||
EventType: HOOK_EVENT_PUSH,
|
||||
IsSSL: w.IsSSL,
|
||||
@@ -526,10 +576,12 @@ func (t *HookTask) deliver() {
|
||||
t.Delivered = time.Now().UTC().UnixNano()
|
||||
if t.IsSucceed {
|
||||
log.Trace("Hook delivered: %s", t.UUID)
|
||||
} else {
|
||||
log.Trace("Hook delivery failed: %s", t.UUID)
|
||||
}
|
||||
|
||||
// Update webhook last delivery status.
|
||||
w, err := GetWebhookByID(t.HookID)
|
||||
w, err := GetWebhookByRepoID(t.RepoID, t.HookID)
|
||||
if err != nil {
|
||||
log.Error(5, "GetWebhookByID: %v", err)
|
||||
return
|
||||
@@ -565,14 +617,6 @@ func (t *HookTask) deliver() {
|
||||
return
|
||||
}
|
||||
t.ResponseInfo.Body = string(p)
|
||||
|
||||
switch t.Type {
|
||||
case SLACK:
|
||||
if t.ResponseInfo.Body != "ok" {
|
||||
log.Error(5, "slack failed with: %s", t.ResponseInfo.Body)
|
||||
t.IsSucceed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeliverHooks checks and delivers undelivered hooks.
|
||||
@@ -590,24 +634,24 @@ func DeliverHooks() {
|
||||
// Update hook task status.
|
||||
for _, t := range tasks {
|
||||
if err := UpdateHookTask(t); err != nil {
|
||||
log.Error(4, "UpdateHookTask(%d): %v", t.ID, err)
|
||||
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening on new hook requests.
|
||||
for repoID := range HookQueue.Queue() {
|
||||
log.Trace("DeliverHooks[%v]: processing delivery hooks", repoID)
|
||||
log.Trace("DeliverHooks [%v]: processing delivery hooks", repoID)
|
||||
HookQueue.Remove(repoID)
|
||||
|
||||
tasks = make([]*HookTask, 0, 5)
|
||||
if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil {
|
||||
log.Error(4, "Get repository(%d) hook tasks: %v", repoID, err)
|
||||
log.Error(4, "Get repository [%d] hook tasks: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
for _, t := range tasks {
|
||||
t.deliver()
|
||||
if err := UpdateHookTask(t); err != nil {
|
||||
log.Error(4, "UpdateHookTask[%d]: %v", t.ID, err)
|
||||
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
)
|
||||
|
||||
type SlackMeta struct {
|
||||
@@ -33,8 +32,9 @@ type SlackPayload struct {
|
||||
}
|
||||
|
||||
type SlackAttachment struct {
|
||||
Color string `json:"color"`
|
||||
Text string `json:"text"`
|
||||
Fallback string `json:"fallback"`
|
||||
Color string `json:"color"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func (p *SlackPayload) SetSecret(_ string) {}
|
||||
@@ -82,19 +82,19 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
|
||||
// n new commits
|
||||
var (
|
||||
branchName = git.RefEndName(p.Ref)
|
||||
commitDesc string
|
||||
commitString string
|
||||
)
|
||||
|
||||
if len(p.Commits) == 1 {
|
||||
commitString = "1 new commit"
|
||||
if len(p.CompareUrl) > 0 {
|
||||
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
|
||||
}
|
||||
commitDesc = "1 new commit"
|
||||
} else {
|
||||
commitString = fmt.Sprintf("%d new commits", len(p.Commits))
|
||||
if p.CompareUrl != "" {
|
||||
commitString = SlackLinkFormatter(p.CompareUrl, commitString)
|
||||
}
|
||||
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
|
||||
}
|
||||
if len(p.CompareUrl) > 0 {
|
||||
commitString = SlackLinkFormatter(p.CompareUrl, commitDesc)
|
||||
} else {
|
||||
commitString = commitDesc
|
||||
}
|
||||
|
||||
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
|
||||
@@ -111,7 +111,10 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
|
||||
}
|
||||
}
|
||||
|
||||
slackAttachments := []SlackAttachment{{Color: slack.Color, Text: attachmentText}}
|
||||
slackAttachments := []SlackAttachment{{
|
||||
Color: slack.Color,
|
||||
Text: attachmentText,
|
||||
}}
|
||||
|
||||
return &SlackPayload{
|
||||
Channel: slack.Channel,
|
||||
|
||||
225
models/wiki.go
Normal file
225
models/wiki.go
Normal file
@@ -0,0 +1,225 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
// workingPool represents a pool of working status which makes sure
|
||||
// that only one instance of same task is performing at a time.
|
||||
// However, different type of tasks can performing at the same time.
|
||||
type workingPool struct {
|
||||
lock sync.Mutex
|
||||
pool map[string]*sync.Mutex
|
||||
count map[string]int
|
||||
}
|
||||
|
||||
// CheckIn checks in a task and waits if others are running.
|
||||
func (p *workingPool) CheckIn(name string) {
|
||||
p.lock.Lock()
|
||||
|
||||
lock, has := p.pool[name]
|
||||
if !has {
|
||||
lock = &sync.Mutex{}
|
||||
p.pool[name] = lock
|
||||
}
|
||||
p.count[name]++
|
||||
|
||||
p.lock.Unlock()
|
||||
lock.Lock()
|
||||
}
|
||||
|
||||
// CheckOut checks out a task to let other tasks run.
|
||||
func (p *workingPool) CheckOut(name string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
p.pool[name].Unlock()
|
||||
if p.count[name] == 1 {
|
||||
delete(p.pool, name)
|
||||
delete(p.count, name)
|
||||
} else {
|
||||
p.count[name]--
|
||||
}
|
||||
}
|
||||
|
||||
var wikiWorkingPool = &workingPool{
|
||||
pool: make(map[string]*sync.Mutex),
|
||||
count: make(map[string]int),
|
||||
}
|
||||
|
||||
// ToWikiPageURL formats a string to corresponding wiki URL name.
|
||||
func ToWikiPageURL(name string) string {
|
||||
return url.QueryEscape(strings.Replace(name, " ", "-", -1))
|
||||
}
|
||||
|
||||
// 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 strings.Replace(strings.TrimLeft(name, "./"), "/", " ", -1)
|
||||
}
|
||||
|
||||
// WikiCloneLink returns clone URLs of repository wiki.
|
||||
func (repo *Repository) WikiCloneLink() (cl *CloneLink) {
|
||||
return repo.cloneLink(true)
|
||||
}
|
||||
|
||||
// WikiPath returns wiki data path by given user and repository name.
|
||||
func WikiPath(userName, repoName string) string {
|
||||
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
|
||||
}
|
||||
|
||||
func (repo *Repository) WikiPath() string {
|
||||
return WikiPath(repo.MustOwner().Name, repo.Name)
|
||||
}
|
||||
|
||||
// HasWiki returns true if repository has wiki.
|
||||
func (repo *Repository) HasWiki() bool {
|
||||
return com.IsDir(repo.WikiPath())
|
||||
}
|
||||
|
||||
// InitWiki initializes a wiki for repository,
|
||||
// it does nothing when repository already has wiki.
|
||||
func (repo *Repository) InitWiki() error {
|
||||
if repo.HasWiki() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
|
||||
return fmt.Errorf("InitRepository: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) LocalWikiPath() string {
|
||||
return path.Join(setting.AppDataPath, "tmp/local-wiki", com.ToStr(repo.ID))
|
||||
}
|
||||
|
||||
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
|
||||
func (repo *Repository) UpdateLocalWiki() error {
|
||||
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// updateWikiPage adds new page to repository wiki.
|
||||
func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, message string, isNew bool) (err error) {
|
||||
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.InitWiki(); err != nil {
|
||||
return fmt.Errorf("InitWiki: %v", err)
|
||||
}
|
||||
|
||||
localPath := repo.LocalWikiPath()
|
||||
if err = discardLocalWikiChanges(localPath); err != nil {
|
||||
return fmt.Errorf("discardLocalWikiChanges: %v", err)
|
||||
} else if err = repo.UpdateLocalWiki(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalWiki: %v", err)
|
||||
}
|
||||
|
||||
title = ToWikiPageName(title)
|
||||
filename := path.Join(localPath, title+".md")
|
||||
|
||||
// If not a new file, show perform update not create.
|
||||
if isNew {
|
||||
if com.IsExist(filename) {
|
||||
return ErrWikiAlreadyExist{filename}
|
||||
}
|
||||
} else {
|
||||
os.Remove(path.Join(localPath, oldTitle+".md"))
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
if len(message) == 0 {
|
||||
message = "Update page '" + title + "'"
|
||||
}
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) AddWikiPage(doer *User, title, content, message string) error {
|
||||
return repo.updateWikiPage(doer, "", title, content, message, true)
|
||||
}
|
||||
|
||||
func (repo *Repository) EditWikiPage(doer *User, oldTitle, title, content, message string) error {
|
||||
return repo.updateWikiPage(doer, oldTitle, title, content, message, false)
|
||||
}
|
||||
|
||||
func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
|
||||
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
localPath := repo.LocalWikiPath()
|
||||
if err = discardLocalWikiChanges(localPath); err != nil {
|
||||
return fmt.Errorf("discardLocalWikiChanges: %v", err)
|
||||
} else if err = repo.UpdateLocalWiki(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalWiki: %v", err)
|
||||
}
|
||||
|
||||
title = ToWikiPageName(title)
|
||||
filename := path.Join(localPath, title+".md")
|
||||
os.Remove(filename)
|
||||
|
||||
message := "Delete page '" + title + "'"
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Copyright 2009 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=github.com/mmitton/asn1-ber
|
||||
GOFILES=\
|
||||
ber.go\
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
@@ -1,14 +0,0 @@
|
||||
ASN1 BER Encoding / Decoding Library for the GO programming language.
|
||||
|
||||
Required Librarys:
|
||||
None
|
||||
|
||||
Working:
|
||||
Very basic encoding / decoding needed for LDAP protocol
|
||||
|
||||
Tests Implemented:
|
||||
None
|
||||
|
||||
TODO:
|
||||
Fix all encoding / decoding to conform to ASN1 BER spec
|
||||
Implement Tests / Benchmarks
|
||||
@@ -1,497 +0,0 @@
|
||||
package ber
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Packet struct {
|
||||
ClassType uint8
|
||||
TagType uint8
|
||||
Tag uint8
|
||||
Value interface{}
|
||||
ByteValue []byte
|
||||
Data *bytes.Buffer
|
||||
Children []*Packet
|
||||
Description string
|
||||
}
|
||||
|
||||
const (
|
||||
TagEOC = 0x00
|
||||
TagBoolean = 0x01
|
||||
TagInteger = 0x02
|
||||
TagBitString = 0x03
|
||||
TagOctetString = 0x04
|
||||
TagNULL = 0x05
|
||||
TagObjectIdentifier = 0x06
|
||||
TagObjectDescriptor = 0x07
|
||||
TagExternal = 0x08
|
||||
TagRealFloat = 0x09
|
||||
TagEnumerated = 0x0a
|
||||
TagEmbeddedPDV = 0x0b
|
||||
TagUTF8String = 0x0c
|
||||
TagRelativeOID = 0x0d
|
||||
TagSequence = 0x10
|
||||
TagSet = 0x11
|
||||
TagNumericString = 0x12
|
||||
TagPrintableString = 0x13
|
||||
TagT61String = 0x14
|
||||
TagVideotexString = 0x15
|
||||
TagIA5String = 0x16
|
||||
TagUTCTime = 0x17
|
||||
TagGeneralizedTime = 0x18
|
||||
TagGraphicString = 0x19
|
||||
TagVisibleString = 0x1a
|
||||
TagGeneralString = 0x1b
|
||||
TagUniversalString = 0x1c
|
||||
TagCharacterString = 0x1d
|
||||
TagBMPString = 0x1e
|
||||
TagBitmask = 0x1f // xxx11111b
|
||||
)
|
||||
|
||||
var TagMap = map[uint8]string{
|
||||
TagEOC: "EOC (End-of-Content)",
|
||||
TagBoolean: "Boolean",
|
||||
TagInteger: "Integer",
|
||||
TagBitString: "Bit String",
|
||||
TagOctetString: "Octet String",
|
||||
TagNULL: "NULL",
|
||||
TagObjectIdentifier: "Object Identifier",
|
||||
TagObjectDescriptor: "Object Descriptor",
|
||||
TagExternal: "External",
|
||||
TagRealFloat: "Real (float)",
|
||||
TagEnumerated: "Enumerated",
|
||||
TagEmbeddedPDV: "Embedded PDV",
|
||||
TagUTF8String: "UTF8 String",
|
||||
TagRelativeOID: "Relative-OID",
|
||||
TagSequence: "Sequence and Sequence of",
|
||||
TagSet: "Set and Set OF",
|
||||
TagNumericString: "Numeric String",
|
||||
TagPrintableString: "Printable String",
|
||||
TagT61String: "T61 String",
|
||||
TagVideotexString: "Videotex String",
|
||||
TagIA5String: "IA5 String",
|
||||
TagUTCTime: "UTC Time",
|
||||
TagGeneralizedTime: "Generalized Time",
|
||||
TagGraphicString: "Graphic String",
|
||||
TagVisibleString: "Visible String",
|
||||
TagGeneralString: "General String",
|
||||
TagUniversalString: "Universal String",
|
||||
TagCharacterString: "Character String",
|
||||
TagBMPString: "BMP String",
|
||||
}
|
||||
|
||||
const (
|
||||
ClassUniversal = 0 // 00xxxxxxb
|
||||
ClassApplication = 64 // 01xxxxxxb
|
||||
ClassContext = 128 // 10xxxxxxb
|
||||
ClassPrivate = 192 // 11xxxxxxb
|
||||
ClassBitmask = 192 // 11xxxxxxb
|
||||
)
|
||||
|
||||
var ClassMap = map[uint8]string{
|
||||
ClassUniversal: "Universal",
|
||||
ClassApplication: "Application",
|
||||
ClassContext: "Context",
|
||||
ClassPrivate: "Private",
|
||||
}
|
||||
|
||||
const (
|
||||
TypePrimitive = 0 // xx0xxxxxb
|
||||
TypeConstructed = 32 // xx1xxxxxb
|
||||
TypeBitmask = 32 // xx1xxxxxb
|
||||
)
|
||||
|
||||
var TypeMap = map[uint8]string{
|
||||
TypePrimitive: "Primative",
|
||||
TypeConstructed: "Constructed",
|
||||
}
|
||||
|
||||
var Debug bool = false
|
||||
|
||||
func PrintBytes(buf []byte, indent string) {
|
||||
data_lines := make([]string, (len(buf)/30)+1)
|
||||
num_lines := make([]string, (len(buf)/30)+1)
|
||||
|
||||
for i, b := range buf {
|
||||
data_lines[i/30] += fmt.Sprintf("%02x ", b)
|
||||
num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
|
||||
}
|
||||
|
||||
for i := 0; i < len(data_lines); i++ {
|
||||
fmt.Print(indent + data_lines[i] + "\n")
|
||||
fmt.Print(indent + num_lines[i] + "\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func PrintPacket(p *Packet) {
|
||||
printPacket(p, 0, false)
|
||||
}
|
||||
|
||||
func printPacket(p *Packet, indent int, printBytes bool) {
|
||||
indent_str := ""
|
||||
|
||||
for len(indent_str) != indent {
|
||||
indent_str += " "
|
||||
}
|
||||
|
||||
class_str := ClassMap[p.ClassType]
|
||||
|
||||
tagtype_str := TypeMap[p.TagType]
|
||||
|
||||
tag_str := fmt.Sprintf("0x%02X", p.Tag)
|
||||
|
||||
if p.ClassType == ClassUniversal {
|
||||
tag_str = TagMap[p.Tag]
|
||||
}
|
||||
|
||||
value := fmt.Sprint(p.Value)
|
||||
description := ""
|
||||
|
||||
if p.Description != "" {
|
||||
description = p.Description + ": "
|
||||
}
|
||||
|
||||
fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
|
||||
|
||||
if printBytes {
|
||||
PrintBytes(p.Bytes(), indent_str)
|
||||
}
|
||||
|
||||
for _, child := range p.Children {
|
||||
printPacket(child, indent+1, printBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func resizeBuffer(in []byte, new_size uint64) (out []byte) {
|
||||
out = make([]byte, new_size)
|
||||
|
||||
copy(out, in)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func readBytes(reader io.Reader, buf []byte) error {
|
||||
idx := 0
|
||||
buflen := len(buf)
|
||||
|
||||
if reader == nil {
|
||||
return errors.New("reader was nil, aborting")
|
||||
}
|
||||
|
||||
for idx < buflen {
|
||||
n, err := reader.Read(buf[idx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
idx += n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadPacket(reader io.Reader) (*Packet, error) {
|
||||
buf := make([]byte, 2)
|
||||
|
||||
err := readBytes(reader, buf)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idx := uint64(2)
|
||||
datalen := uint64(buf[1])
|
||||
|
||||
if Debug {
|
||||
fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf))
|
||||
|
||||
for _, b := range buf {
|
||||
fmt.Printf("%02X ", b)
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
if datalen&128 != 0 {
|
||||
a := datalen - 128
|
||||
|
||||
idx += a
|
||||
buf = resizeBuffer(buf, 2+a)
|
||||
|
||||
err := readBytes(reader, buf[2:])
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
datalen = DecodeInteger(buf[2 : 2+a])
|
||||
|
||||
if Debug {
|
||||
fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf))
|
||||
|
||||
for _, b := range buf {
|
||||
fmt.Printf("%02X ", b)
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf = resizeBuffer(buf, idx+datalen)
|
||||
err = readBytes(reader, buf[idx:])
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen)
|
||||
|
||||
for _, b := range buf {
|
||||
fmt.Printf("%02X ", b)
|
||||
}
|
||||
}
|
||||
|
||||
p := DecodePacket(buf)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func DecodeString(data []byte) (ret string) {
|
||||
// for _, c := range data {
|
||||
// ret += fmt.Sprintf("%c", c)
|
||||
// }
|
||||
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func DecodeInteger(data []byte) (ret uint64) {
|
||||
for _, i := range data {
|
||||
ret = ret * 256
|
||||
ret = ret + uint64(i)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func EncodeInteger(val uint64) []byte {
|
||||
var out bytes.Buffer
|
||||
|
||||
found := false
|
||||
|
||||
shift := uint(56)
|
||||
|
||||
mask := uint64(0xFF00000000000000)
|
||||
|
||||
for mask > 0 {
|
||||
if !found && (val&mask != 0) {
|
||||
found = true
|
||||
}
|
||||
|
||||
if found || (shift == 0) {
|
||||
out.Write([]byte{byte((val & mask) >> shift)})
|
||||
}
|
||||
|
||||
shift -= 8
|
||||
mask = mask >> 8
|
||||
}
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
func DecodePacket(data []byte) *Packet {
|
||||
p, _ := decodePacket(data)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func decodePacket(data []byte) (*Packet, []byte) {
|
||||
if Debug {
|
||||
fmt.Printf("decodePacket: enter %d\n", len(data))
|
||||
}
|
||||
|
||||
p := new(Packet)
|
||||
|
||||
p.ClassType = data[0] & ClassBitmask
|
||||
p.TagType = data[0] & TypeBitmask
|
||||
p.Tag = data[0] & TagBitmask
|
||||
|
||||
datalen := DecodeInteger(data[1:2])
|
||||
datapos := uint64(2)
|
||||
|
||||
if datalen&128 != 0 {
|
||||
datalen -= 128
|
||||
datapos += datalen
|
||||
datalen = DecodeInteger(data[2 : 2+datalen])
|
||||
}
|
||||
|
||||
p.Data = new(bytes.Buffer)
|
||||
|
||||
p.Children = make([]*Packet, 0, 2)
|
||||
|
||||
p.Value = nil
|
||||
|
||||
value_data := data[datapos : datapos+datalen]
|
||||
|
||||
if p.TagType == TypeConstructed {
|
||||
for len(value_data) != 0 {
|
||||
var child *Packet
|
||||
|
||||
child, value_data = decodePacket(value_data)
|
||||
p.AppendChild(child)
|
||||
}
|
||||
} else if p.ClassType == ClassUniversal {
|
||||
p.Data.Write(data[datapos : datapos+datalen])
|
||||
p.ByteValue = value_data
|
||||
|
||||
switch p.Tag {
|
||||
case TagEOC:
|
||||
case TagBoolean:
|
||||
val := DecodeInteger(value_data)
|
||||
|
||||
p.Value = val != 0
|
||||
case TagInteger:
|
||||
p.Value = DecodeInteger(value_data)
|
||||
case TagBitString:
|
||||
case TagOctetString:
|
||||
p.Value = DecodeString(value_data)
|
||||
case TagNULL:
|
||||
case TagObjectIdentifier:
|
||||
case TagObjectDescriptor:
|
||||
case TagExternal:
|
||||
case TagRealFloat:
|
||||
case TagEnumerated:
|
||||
p.Value = DecodeInteger(value_data)
|
||||
case TagEmbeddedPDV:
|
||||
case TagUTF8String:
|
||||
case TagRelativeOID:
|
||||
case TagSequence:
|
||||
case TagSet:
|
||||
case TagNumericString:
|
||||
case TagPrintableString:
|
||||
p.Value = DecodeString(value_data)
|
||||
case TagT61String:
|
||||
case TagVideotexString:
|
||||
case TagIA5String:
|
||||
case TagUTCTime:
|
||||
case TagGeneralizedTime:
|
||||
case TagGraphicString:
|
||||
case TagVisibleString:
|
||||
case TagGeneralString:
|
||||
case TagUniversalString:
|
||||
case TagCharacterString:
|
||||
case TagBMPString:
|
||||
}
|
||||
} else {
|
||||
p.Data.Write(data[datapos : datapos+datalen])
|
||||
}
|
||||
|
||||
return p, data[datapos+datalen:]
|
||||
}
|
||||
|
||||
func (p *Packet) DataLength() uint64 {
|
||||
return uint64(p.Data.Len())
|
||||
}
|
||||
|
||||
func (p *Packet) Bytes() []byte {
|
||||
var out bytes.Buffer
|
||||
|
||||
out.Write([]byte{p.ClassType | p.TagType | p.Tag})
|
||||
packet_length := EncodeInteger(p.DataLength())
|
||||
|
||||
if p.DataLength() > 127 || len(packet_length) > 1 {
|
||||
out.Write([]byte{byte(len(packet_length) | 128)})
|
||||
out.Write(packet_length)
|
||||
} else {
|
||||
out.Write(packet_length)
|
||||
}
|
||||
|
||||
out.Write(p.Data.Bytes())
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
func (p *Packet) AppendChild(child *Packet) {
|
||||
p.Data.Write(child.Bytes())
|
||||
|
||||
if len(p.Children) == cap(p.Children) {
|
||||
newChildren := make([]*Packet, cap(p.Children)*2)
|
||||
|
||||
copy(newChildren, p.Children)
|
||||
p.Children = newChildren[0:len(p.Children)]
|
||||
}
|
||||
|
||||
p.Children = p.Children[0 : len(p.Children)+1]
|
||||
p.Children[len(p.Children)-1] = child
|
||||
}
|
||||
|
||||
func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string) *Packet {
|
||||
p := new(Packet)
|
||||
|
||||
p.ClassType = ClassType
|
||||
p.TagType = TagType
|
||||
p.Tag = Tag
|
||||
p.Data = new(bytes.Buffer)
|
||||
|
||||
p.Children = make([]*Packet, 0, 2)
|
||||
|
||||
p.Value = Value
|
||||
p.Description = Description
|
||||
|
||||
if Value != nil {
|
||||
v := reflect.ValueOf(Value)
|
||||
|
||||
if ClassType == ClassUniversal {
|
||||
switch Tag {
|
||||
case TagOctetString:
|
||||
sv, ok := v.Interface().(string)
|
||||
|
||||
if ok {
|
||||
p.Data.Write([]byte(sv))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func NewSequence(Description string) *Packet {
|
||||
return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description)
|
||||
}
|
||||
|
||||
func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet {
|
||||
intValue := 0
|
||||
|
||||
if Value {
|
||||
intValue = 1
|
||||
}
|
||||
|
||||
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||
|
||||
p.Value = Value
|
||||
p.Data.Write(EncodeInteger(uint64(intValue)))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet {
|
||||
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||
|
||||
p.Value = Value
|
||||
p.Data.Write(EncodeInteger(Value))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet {
|
||||
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||
|
||||
p.Value = Value
|
||||
p.Data.Write([]byte(Value))
|
||||
|
||||
return p
|
||||
}
|
||||
@@ -31,10 +31,12 @@ type AdminEditUserForm struct {
|
||||
Password string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"MaxSize(50)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
MaxRepoCreation int
|
||||
Active bool
|
||||
Admin bool
|
||||
AllowGitHook bool
|
||||
AllowImportLocal bool
|
||||
ProhibitLogin bool
|
||||
}
|
||||
|
||||
func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package apiv1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
)
|
||||
|
||||
type MarkdownForm struct {
|
||||
Text string
|
||||
Mode string
|
||||
Context string
|
||||
}
|
||||
|
||||
func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validateApiReq(errs, ctx.Data, f)
|
||||
}
|
||||
|
||||
func validateApiReq(errs binding.Errors, data map[string]interface{}, f auth.Form) binding.Errors {
|
||||
if errs.Len() == 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
data["HasError"] = true
|
||||
|
||||
typ := reflect.TypeOf(f)
|
||||
val := reflect.ValueOf(f)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
fieldName := field.Tag.Get("form")
|
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if errs[0].FieldNames[0] == field.Name {
|
||||
switch errs[0].Classification {
|
||||
case binding.ERR_REQUIRED:
|
||||
data["ErrorMsg"] = fieldName + " cannot be empty"
|
||||
case binding.ERR_ALPHA_DASH:
|
||||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) characters"
|
||||
case binding.ERR_ALPHA_DASH_DOT:
|
||||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) or dot characters"
|
||||
case binding.ERR_MIN_SIZE:
|
||||
data["ErrorMsg"] = fieldName + " must contain at least " + auth.GetMinSize(field) + " characters"
|
||||
case binding.ERR_MAX_SIZE:
|
||||
data["ErrorMsg"] = fieldName + " must contain at most " + auth.GetMaxSize(field) + " characters"
|
||||
case binding.ERR_EMAIL:
|
||||
data["ErrorMsg"] = fieldName + " is not a valid e-mail address"
|
||||
case binding.ERR_URL:
|
||||
data["ErrorMsg"] = fieldName + " is not a valid URL"
|
||||
default:
|
||||
data["ErrorMsg"] = "Unknown error: " + errs[0].Classification
|
||||
}
|
||||
return errs
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/session"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
func IsAPIPath(url string) bool {
|
||||
@@ -49,14 +49,14 @@ 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
|
||||
}
|
||||
t.Updated = time.Now()
|
||||
if err = models.UpdateAccessToekn(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToekn: %v", err)
|
||||
if err = models.UpdateAccessToken(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
}
|
||||
return t.UID
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
if setting.Service.EnableReverseProxyAutoRegister {
|
||||
u := &models.User{
|
||||
Name: webAuthUser,
|
||||
Email: uuid.NewV4().String() + "@localhost",
|
||||
Email: gouuid.NewV4().String() + "@localhost",
|
||||
Passwd: webAuthUser,
|
||||
IsActive: true,
|
||||
}
|
||||
|
||||
@@ -10,28 +10,31 @@ import (
|
||||
)
|
||||
|
||||
type AuthenticationForm struct {
|
||||
ID int64
|
||||
Type int `binding:"Range(2,5)"`
|
||||
Name string `binding:"Required;MaxSize(30)"`
|
||||
Host string
|
||||
Port int
|
||||
BindDN string
|
||||
BindPassword string
|
||||
UserBase string
|
||||
UserDN string `form:"user_dn"`
|
||||
AttributeName string
|
||||
AttributeSurname string
|
||||
AttributeMail string
|
||||
Filter string
|
||||
AdminFilter string
|
||||
IsActive bool
|
||||
SMTPAuth string
|
||||
SMTPHost string
|
||||
SMTPPort int
|
||||
AllowedDomains string
|
||||
TLS bool
|
||||
SkipVerify bool
|
||||
PAMServiceName string `form:"pam_service_name"`
|
||||
ID int64
|
||||
Type int `binding:"Range(2,5)"`
|
||||
Name string `binding:"Required;MaxSize(30)"`
|
||||
Host string
|
||||
Port int
|
||||
BindDN string
|
||||
BindPassword string
|
||||
UserBase string
|
||||
UserDN string
|
||||
AttributeUsername string
|
||||
AttributeName string
|
||||
AttributeSurname string
|
||||
AttributeMail string
|
||||
AttributesInBind bool
|
||||
Filter string
|
||||
AdminFilter string
|
||||
IsActive bool
|
||||
SMTPAuth string
|
||||
SMTPHost string
|
||||
SMTPPort int
|
||||
AllowedDomains string
|
||||
SecurityProtocol int `binding:"Range(0,2)"`
|
||||
TLS bool
|
||||
SkipVerify bool
|
||||
PAMServiceName string
|
||||
}
|
||||
|
||||
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -11,27 +11,39 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/gogs/modules/ldap"
|
||||
"gopkg.in/ldap.v2"
|
||||
|
||||
"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
|
||||
SkipVerify bool
|
||||
BindDN string // DN to bind with
|
||||
BindPassword string // Bind DN password
|
||||
UserBase string // Base search path for users
|
||||
UserDN string // Template for the DN of the user for simple auth
|
||||
AttributeName string // First name attribute
|
||||
AttributeSurname string // Surname attribute
|
||||
AttributeMail string // E-mail attribute
|
||||
Filter string // Query filter to validate entry
|
||||
AdminFilter string // Query filter to check if user is admin
|
||||
Enabled bool // if this source is disabled
|
||||
Name string // canonical name (ie. corporate.ad)
|
||||
Host string // LDAP host
|
||||
Port int // port number
|
||||
SecurityProtocol SecurityProtocol
|
||||
SkipVerify bool
|
||||
BindDN string // DN to bind with
|
||||
BindPassword string // Bind DN password
|
||||
UserBase string // Base search path for users
|
||||
UserDN string // Template for the DN of the user for simple auth
|
||||
AttributeUsername string // Username attribute
|
||||
AttributeName string // First name attribute
|
||||
AttributeSurname string // Surname attribute
|
||||
AttributeMail string // E-mail attribute
|
||||
AttributesInBind bool // fetch attributes in bind context (not user)
|
||||
Filter string // Query filter to validate entry
|
||||
AdminFilter string // Query filter to check if user is admin
|
||||
Enabled bool // if this source is disabled
|
||||
}
|
||||
|
||||
func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
|
||||
@@ -56,18 +68,10 @@ func (ls *Source) sanitizedUserDN(username string) (string, bool) {
|
||||
return fmt.Sprintf(ls.UserDN, username), true
|
||||
}
|
||||
|
||||
func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
|
||||
log.Trace("Search for LDAP user: %s", name)
|
||||
if ls.BindDN != "" && ls.BindPassword != "" {
|
||||
err = l.Bind(ls.BindDN, ls.BindPassword)
|
||||
err := l.Bind(ls.BindDN, ls.BindPassword)
|
||||
if err != nil {
|
||||
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err)
|
||||
return "", false
|
||||
@@ -83,7 +87,7 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
log.Trace("Searching using filter %s", userFilter)
|
||||
log.Trace("Searching for DN using filter %s and base %s", userFilter, ls.UserBase)
|
||||
search := ldap.NewSearchRequest(
|
||||
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
|
||||
false, userFilter, []string{}, nil)
|
||||
@@ -100,15 +104,60 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
|
||||
userDN := sr.Entries[0].DN
|
||||
if userDN == "" {
|
||||
log.Error(4, "LDAP search was succesful, but found no DN!")
|
||||
log.Error(4, "LDAP search was successful, but found no DN!")
|
||||
return "", false
|
||||
}
|
||||
|
||||
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, bool, bool) {
|
||||
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
|
||||
l, err := dial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
var userDN string
|
||||
if directBind {
|
||||
log.Trace("LDAP will bind directly via UserDN template: %s", ls.UserDN)
|
||||
@@ -116,48 +165,41 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
|
||||
var ok bool
|
||||
userDN, ok = ls.sanitizedUserDN(name)
|
||||
if !ok {
|
||||
return "", "", "", false, false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
} else {
|
||||
log.Trace("LDAP will use BindDN.")
|
||||
|
||||
var found bool
|
||||
userDN, found = ls.FindUserDN(name)
|
||||
userDN, found = ls.findUserDN(l, name)
|
||||
if !found {
|
||||
return "", "", "", false, false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error (%s): %v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", "", "", false, false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
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 "", "", "", false, false
|
||||
if directBind || !ls.AttributesInBind {
|
||||
// binds user (checking password) before looking-up attributes in user context
|
||||
err = bindUser(l, userDN, passwd)
|
||||
if err != nil {
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("Bound successfully with userDN: %s", userDN)
|
||||
userFilter, ok := ls.sanitizedUserQuery(name)
|
||||
if !ok {
|
||||
return "", "", "", false, false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
|
||||
log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN)
|
||||
search := ldap.NewSearchRequest(
|
||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||
[]string{ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
|
||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
|
||||
nil)
|
||||
|
||||
sr, err := l.Search(search)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
|
||||
return "", "", "", false, false
|
||||
return "", "", "", "", false, false
|
||||
} else if len(sr.Entries) < 1 {
|
||||
if directBind {
|
||||
log.Error(4, "User filter inhibited user login.")
|
||||
@@ -165,15 +207,17 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
|
||||
log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
|
||||
}
|
||||
|
||||
return "", "", "", false, false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
|
||||
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(
|
||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
|
||||
[]string{ls.AttributeName},
|
||||
@@ -185,20 +229,17 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
return name_attr, sn_attr, mail_attr, admin_attr, true
|
||||
}
|
||||
|
||||
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))
|
||||
if !directBind && ls.AttributesInBind {
|
||||
// binds user (checking password) after looking-up attributes in BindDN context
|
||||
err = bindUser(l, userDN, passwd)
|
||||
if err != nil {
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
return username, firstname, surname, mail, isAdmin, true
|
||||
}
|
||||
|
||||
@@ -25,11 +25,12 @@ func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) bind
|
||||
}
|
||||
|
||||
type UpdateOrgSettingForm struct {
|
||||
Name string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
Name string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
MaxRepoCreation int
|
||||
}
|
||||
|
||||
func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
@@ -44,9 +45,9 @@ func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Error
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateTeamForm struct {
|
||||
TeamName string `form:"team_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||
Permission string `form:"permission"`
|
||||
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Permission string
|
||||
}
|
||||
|
||||
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -57,7 +57,7 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// It also checks if given user has permission when remote address
|
||||
// is actually a local path.
|
||||
func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
|
||||
remoteAddr := f.CloneAddr
|
||||
remoteAddr := strings.TrimSpace(f.CloneAddr)
|
||||
|
||||
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||
if strings.HasPrefix(remoteAddr, "http://") ||
|
||||
@@ -81,12 +81,24 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
|
||||
}
|
||||
|
||||
type RepoSettingForm struct {
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Branch string
|
||||
Interval int
|
||||
Private bool
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Branch string
|
||||
Interval int
|
||||
MirrorAddress string
|
||||
Private bool
|
||||
EnablePrune bool
|
||||
|
||||
// Advanced settings
|
||||
EnableWiki bool
|
||||
EnableExternalWiki bool
|
||||
ExternalWikiURL string
|
||||
EnableIssues bool
|
||||
EnableExternalTracker bool
|
||||
TrackerURLFormat string
|
||||
TrackerIssueStyle string
|
||||
EnablePulls bool
|
||||
}
|
||||
|
||||
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
@@ -131,7 +143,7 @@ func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
|
||||
}
|
||||
|
||||
type NewSlackHookForm struct {
|
||||
PayloadURL string `binding:"Required;Url`
|
||||
PayloadURL string `binding:"Required;Url"`
|
||||
Channel string `binding:"Required"`
|
||||
Username string
|
||||
IconURL string
|
||||
@@ -229,7 +241,7 @@ func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
|
||||
|
||||
type EditReleaseForm struct {
|
||||
Title string `form:"title" binding:"Required"`
|
||||
Content string `form:"content" binding:"Required"`
|
||||
Content string `form:"content"`
|
||||
Draft string `form:"draft"`
|
||||
Prerelease bool `form:"prerelease"`
|
||||
}
|
||||
@@ -237,3 +249,22 @@ type EditReleaseForm struct {
|
||||
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// __ __.__ __ .__
|
||||
// / \ / \__| | _|__|
|
||||
// \ \/\/ / | |/ / |
|
||||
// \ /| | <| |
|
||||
// \__/\ / |__|__|_ \__|
|
||||
// \/ \/
|
||||
|
||||
type NewWikiForm struct {
|
||||
OldTitle string
|
||||
Title string `binding:"Required"`
|
||||
Content string `binding:"Required"`
|
||||
Message string
|
||||
}
|
||||
|
||||
// FIXME: use code generation to generate this method.
|
||||
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ type InstallForm struct {
|
||||
SSHPort int
|
||||
HTTPPort string `binding:"Required"`
|
||||
AppUrl string `binding:"Required"`
|
||||
LogRootPath string `binding:"Required"`
|
||||
|
||||
SMTPHost string
|
||||
SMTPFrom string
|
||||
@@ -87,12 +88,12 @@ func (f *SignInForm) Validate(ctx *macaron.Context, errs binding.Errors) binding
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type UpdateProfileForm struct {
|
||||
Name string `binding:"Required;MaxSize(35)"`
|
||||
Name string `binding:"OmitEmpty;MaxSize(35)"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Email string `binding:"Required;Email;MaxSize(254)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
Gravatar string `binding:"Required;Email;MaxSize(254)"`
|
||||
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
|
||||
}
|
||||
|
||||
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user