Compare commits
1988 Commits
dev_local_
...
master
Author | SHA1 | Date |
---|---|---|
|
cb34089982 | |
|
4eb7d275a0 | |
|
89dd43e079 | |
|
6ffac40f8d | |
|
0364b2b47c | |
|
a3e94e47e7 | |
|
0be92d5288 | |
|
8665d989c1 | |
|
5df4f2d0b1 | |
|
5d5b927fb8 | |
![]() |
b6401930e9 | |
|
d1ccee4e7c | |
![]() |
d80d151460 | |
|
a45953d350 | |
|
78d4d0f1ea | |
![]() |
843d109b36 | |
|
5693c74171 | |
![]() |
1acac5d39a | |
|
fa2448b94d | |
|
4861de5670 | |
|
257f295f2c | |
|
5ef309519c | |
![]() |
46d41a67a7 | |
|
fadb729647 | |
|
07f7394172 | |
|
97c3222926 | |
|
eb1b917d98 | |
|
609373a978 | |
![]() |
a46bec5f0c | |
|
6706840a56 | |
![]() |
0fa7ce4127 | |
|
e581509e06 | |
![]() |
3c81b924cd | |
|
facb8d7ded | |
![]() |
802e8bb0aa | |
|
bf89ed5297 | |
![]() |
9fbf5920df | |
|
7067c7d190 | |
|
12370367f7 | |
|
c57482042d | |
|
eee63a7c2a | |
|
a3f3d3ec18 | |
|
a9668c9651 | |
|
3038f3bfb9 | |
|
bff009d673 | |
|
a5cf0ce14e | |
|
a3e156005f | |
|
fcedae86cb | |
|
63ff4306d4 | |
|
c967684b3c | |
|
66e7959434 | |
|
97ed99f004 | |
|
afc87f1393 | |
|
d91b7da82c | |
|
def1f4adf2 | |
|
298aec5886 | |
|
ce5d5a88ba | |
|
78c5458bb8 | |
|
bf3540c250 | |
|
6574ee5270 | |
|
717fb74c8a | |
|
3fe528359e | |
|
bf32f58813 | |
|
1c325f412f | |
|
1af1917579 | |
|
330ab008a8 | |
|
870eacaced | |
|
70089d06cc | |
|
6ca55f0f61 | |
|
79863995d6 | |
|
33138aed80 | |
|
ab576fdba5 | |
|
56212f4536 | |
|
5c916bc4e8 | |
|
558bcfeefa | |
|
5c62b1d129 | |
|
3d9f037025 | |
|
ed8593071f | |
|
492561c405 | |
|
b4da913f2b | |
|
9c593b1271 | |
|
7ff07e9c29 | |
|
88415e256d | |
|
d3bc799263 | |
|
44396e444b | |
|
a53f2e0eb9 | |
|
3594462917 | |
|
9b8de2457d | |
|
0f2419cd93 | |
|
2a1372cf5a | |
|
bddfe9d8f7 | |
|
a8be844208 | |
|
0274456442 | |
|
2a0d4d6f45 | |
|
4255966a5b | |
|
68b08d8ca4 | |
|
b494ed718b | |
|
c94111b395 | |
|
4b93cab54e | |
|
aed452e144 | |
|
033c5cf191 | |
|
1a21d54857 | |
|
b74d7c8166 | |
|
d540dadb22 | |
|
3236bb37b0 | |
|
5fd5431d5c | |
|
dbde8aad7c | |
|
19783ac526 | |
|
b4fd3b851e | |
|
137a67fe53 | |
|
6068d44d62 | |
|
15704c0a75 | |
|
ef214af00a | |
|
4d22889ba9 | |
|
b46645fd2d | |
|
b21317eb0a | |
|
925e9f1c64 | |
|
5d804ddeb6 | |
|
1639f1d434 | |
|
6c73c6f485 | |
|
e70e8db02d | |
|
076d92a3eb | |
|
568248e6c1 | |
|
efb4b3040d | |
|
46873a77cd | |
|
7fdf4e7557 | |
|
272639f9fd | |
|
fe77a97057 | |
|
cd32a3ab6c | |
|
656fb9a2a6 | |
|
c9e259e2e8 | |
|
ce5beac223 | |
|
b67ed4d74b | |
|
a06e55d30c | |
|
4514b8b5ff | |
|
469d086cac | |
|
ec13987023 | |
|
ffa4c6e870 | |
|
e50a14595d | |
|
9d3ee56b6f | |
|
3b04a59215 | |
|
cf72921eb1 | |
|
0c5395bff6 | |
|
b2acea82a3 | |
|
6e92086d3e | |
|
164bcb86bd | |
|
0c438cbe21 | |
|
001f90aede | |
|
f738dbed24 | |
|
f8f525bf91 | |
|
756ed9152e | |
|
e17021b9c1 | |
|
1de6cc4e45 | |
|
e0bc394bd3 | |
|
1ccbecc112 | |
|
0baf0781f0 | |
|
e74cd4f661 | |
|
d5511ad8ee | |
|
552037642e | |
|
a2ad254510 | |
|
c7f7f255d2 | |
|
21a78563a0 | |
|
8b72f5157c | |
|
bcabe0e74c | |
|
150f7a485b | |
|
5a1e942d1c | |
|
f8b601bc9f | |
|
8c61254a64 | |
|
7d1688c3dd | |
|
49bd1a130a | |
|
ae6400a06d | |
|
36c6e77f6d | |
|
add2afeb5f | |
|
6ede037c62 | |
|
292248b9b8 | |
|
144860fd2f | |
|
377adf901f | |
|
a1d8e4fa40 | |
|
56b277d37b | |
|
db396cd94f | |
|
0811de86e1 | |
|
9e10625b8b | |
|
383019b7f5 | |
|
3fcbf74890 | |
|
4fe26099dd | |
|
053afec587 | |
|
874e5eeade | |
|
ef18ea8cdc | |
|
bb55122a28 | |
|
ce980714af | |
|
27ac452d0b | |
|
bbbf4283d4 | |
|
2dbc7ee9f1 | |
|
2e93b5ea34 | |
|
19ccaa5599 | |
|
bb14883e31 | |
|
465d5db87e | |
|
62eeda7007 | |
|
6096234742 | |
|
98a2bc5b4a | |
|
8a052e30d8 | |
|
5c2639773e | |
|
5540d8732c | |
|
a26bbf35c5 | |
|
4da3ac2558 | |
|
2e7e25e2d1 | |
|
5d01e8ae40 | |
|
2ed334707d | |
|
a73292ad98 | |
|
dee3d1c438 | |
|
8a46bb263b | |
|
47627fbcaf | |
|
4dd920313c | |
|
54c38fd9e7 | |
|
26621340f1 | |
|
00ec4a0ed8 | |
|
4d0ed530b7 | |
|
829d2f239d | |
|
c7b399f624 | |
|
4331fc3302 | |
|
2a7290341f | |
|
e82e63938b | |
|
e447746bdb | |
|
0fb6069ed6 | |
|
b35093e47a | |
|
c94078831c | |
|
e3d21199f5 | |
|
71a8d67515 | |
|
504d01e038 | |
|
4be2d817c9 | |
|
2a77ac99d9 | |
|
84d6626c5c | |
|
5bd686dcb4 | |
|
b27dc8393d | |
|
aef492cc4f | |
|
38d860385d | |
|
accecb3d0c | |
|
956552e36f | |
|
3c3ff13ab0 | |
|
c014857cf5 | |
|
bdcd12fe74 | |
|
96254f0cc4 | |
|
69a143417e | |
|
c99dc6647a | |
|
45652f5df8 | |
|
c472871355 | |
|
0984ab2ad3 | |
|
c96bbf5ec7 | |
|
e6688d9214 | |
|
117e268306 | |
|
5dc16d11c5 | |
|
43f33b1af2 | |
|
e822652901 | |
|
31ff7ba49e | |
|
f838ce4a0c | |
|
406ceb0942 | |
|
3b55009473 | |
|
9cdc593763 | |
|
f9cf1e3a13 | |
|
e5c030270b | |
|
2792c172d5 | |
|
46796095cf | |
|
944a85dbbb | |
|
848afa3ec4 | |
|
28f3395b05 | |
|
35c0ac4eec | |
|
d87fe501c4 | |
|
a5e6594a37 | |
|
131871dabb | |
|
6a0bec2d3a | |
|
c038979732 | |
|
3ba6259d9f | |
|
8af31adf9d | |
|
b8de8a1d3b | |
|
fdc310bc28 | |
|
a6a05b69d1 | |
|
6142f483ca | |
|
463a0393eb | |
|
69f801115c | |
|
1681b144d6 | |
|
46604c1010 | |
|
bff1dbfc36 | |
|
840af7a73c | |
|
d9880b66d7 | |
|
5939e59347 | |
|
1901aca44c | |
|
18d575512d | |
|
0ca548f3a6 | |
|
d188e5bb7b | |
|
f7d3e7acdf | |
|
9885881a28 | |
|
54fa4e0521 | |
|
2b67333f74 | |
|
de9e7cfcd6 | |
|
b6645bd34a | |
|
13d2c3e46c | |
|
5dbf614e00 | |
|
3d3c09a804 | |
|
10a33ace70 | |
|
d2dd376323 | |
|
12061f4ce8 | |
|
f94d224afc | |
|
05ba6dda63 | |
|
e7b5039eb6 | |
|
58a02a0fda | |
|
f49d5d5c3a | |
|
a7fd0a5437 | |
|
fd3bcfe92b | |
|
de71b5e192 | |
|
61098942f7 | |
|
8b968d3f1a | |
|
55f60bf062 | |
|
6287566eb8 | |
|
73f0b2c075 | |
|
ad239580da | |
|
de2ee51fc4 | |
|
ccb9b5f881 | |
|
735a70bac6 | |
|
5a2f1aa61e | |
|
b68c5c1351 | |
|
ea188dd2a0 | |
|
b55f24e6fe | |
|
0336aa0cca | |
|
c1419480a4 | |
|
a4c2242a8a | |
|
ca3db4c724 | |
|
49e2b35a1e | |
|
96a70007fd | |
|
c00d885e53 | |
|
82e071ecf5 | |
|
42171cba21 | |
|
8cd17a42f3 | |
|
a0138a8d7b | |
|
a3075c157b | |
|
a247c3ae46 | |
|
6bbb4726f2 | |
|
507d2cfeca | |
|
e57910a9a8 | |
|
fe971495cd | |
|
6e40112138 | |
|
b5d3f69f21 | |
|
25630ce40f | |
|
4e9da34ac1 | |
|
2be14cf87c | |
|
f5f73bfa68 | |
|
acda84fec2 | |
|
cfcc0d8d0a | |
|
d474a421ab | |
|
34b5fdfc84 | |
|
dd4b21115f | |
|
4a12ab2d90 | |
|
1756c73a3f | |
|
7d6d95c7eb | |
|
c5505dc4a2 | |
|
2140a163ea | |
|
4f1a984a7f | |
|
e448433ced | |
|
a5a0351266 | |
|
c0ebb7431e | |
|
7392e3e338 | |
|
732b273ad7 | |
|
b03c1bb7a2 | |
|
2f6dda4a15 | |
|
be4726c6a6 | |
|
a4f2243a7a | |
|
301a7f70d2 | |
|
ee520940de | |
|
ba20708514 | |
|
64ffab243c | |
|
b891d99569 | |
|
e9b8f2aee7 | |
|
3958944bf1 | |
|
cf519788d1 | |
|
67b7206183 | |
|
527c1a5e9c | |
|
13da8e3577 | |
|
52f43dbcc3 | |
|
3a460b3b1d | |
|
45f597ab47 | |
|
04da22ed64 | |
|
36409600ea | |
|
c93ae8ebae | |
|
d038f30994 | |
|
c0da80139a | |
|
d6ac38a9ce | |
|
dd3c14e50e | |
|
271e1f4ac7 | |
|
2cd36d019c | |
|
8db7bbd51c | |
|
6e6a15bbc1 | |
|
23c0bcbf36 | |
|
0d2ed00e4c | |
|
a3ee98125b | |
|
12c020f315 | |
|
256f29b7f4 | |
|
151e028d34 | |
|
ee1b7c8f57 | |
|
e8112212bb | |
|
7303be9db2 | |
|
3e09ee08d3 | |
|
84a46a1042 | |
|
d887eb5d41 | |
|
ba7f36c34c | |
|
c89493d6e9 | |
|
2084698801 | |
|
3229ef5e2e | |
|
fc972a9cad | |
|
17c8866d64 | |
|
267adf354b | |
|
e91ae81589 | |
|
e94e45bb63 | |
|
3597dc38e7 | |
|
f33e583ca4 | |
|
8a14530395 | |
|
c37a076868 | |
|
bffecfc0e4 | |
|
0dd1748f1b | |
|
f896735710 | |
|
fec67e64e5 | |
|
314ccdba0b | |
|
670f05c658 | |
|
e0b47faec9 | |
|
768b4f1f57 | |
|
2055a5a3a6 | |
|
f2ab9f6a28 | |
|
04a8d194cc | |
|
dff3c9061e | |
|
9db6713a34 | |
|
2e773e92fb | |
|
db736cae66 | |
|
55b3eea277 | |
|
a434fc59f5 | |
|
13517c8eab | |
|
1bf1651b0c | |
|
77f31e3a78 | |
|
7675370239 | |
|
bd0e456b9f | |
|
359f1c40f6 | |
|
9ac8bac777 | |
|
8bf6f24fe6 | |
|
098b045315 | |
|
c8e9c705f3 | |
|
bb7125f266 | |
|
87c8598c4b | |
|
7f93c068b7 | |
|
97d23f8fdc | |
|
ef64e69aaa | |
|
28fea9a872 | |
|
7b12526963 | |
|
1e82f5ba91 | |
|
bfb3381829 | |
|
382ac02b81 | |
|
55f3890ccf | |
|
b07fa509e1 | |
|
ebb1ff76ea | |
|
9c8e3f44bb | |
|
1233daa466 | |
|
1459e2f626 | |
|
71bdde79ef | |
|
6f8ccea616 | |
|
34ee9d1cbf | |
|
2e0eab0d59 | |
|
d5656f1d7a | |
|
4002245601 | |
|
4e855a2a7b | |
|
5c2f84141e | |
|
66a7c4eb00 | |
|
bd19bb1251 | |
|
94667f4b71 | |
|
05e3036a2f | |
|
ea76beb1bf | |
|
65a7af3d6e | |
|
afb3272cf3 | |
|
b9b3d875ed | |
|
83dc605c26 | |
|
d5a2580ae9 | |
|
75c61bfff5 | |
|
f213ce23af | |
|
3f9cac37c8 | |
|
25978fb97e | |
|
c73e138ee7 | |
|
6924366e02 | |
|
6574aff205 | |
|
cb693dca8b | |
|
4329f9dbf0 | |
|
80828d85d7 | |
|
19cf675f2e | |
|
3fae388d92 | |
|
25321648f6 | |
|
11eb5d3f98 | |
|
17d47170ba | |
|
f4525d6744 | |
|
cf36e89f56 | |
|
29ee61ab1b | |
|
2381851c88 | |
|
a628043efe | |
|
47f8ce478c | |
|
7f4bb60b5e | |
|
20543c6bc2 | |
|
610db14bc9 | |
|
9954a5f92f | |
|
59065ae1e9 | |
|
75153cb099 | |
|
3cce800746 | |
|
3b5894894f | |
|
e29b6181bc | |
|
d1968a63c1 | |
|
5f3aaa03eb | |
|
2faea9aa59 | |
|
2148d5a0ce | |
|
30ec8ef1ce | |
|
5c3a988336 | |
|
ca226e1f81 | |
|
484346d542 | |
|
b51f31cb6b | |
|
8b8388f8db | |
|
2dd567d212 | |
|
6ecf46e88d | |
|
8264bb8107 | |
|
6ba0374119 | |
|
bf7178fb37 | |
|
53988cf557 | |
|
ba77db7cc3 | |
|
f221e9c069 | |
|
cc8899906f | |
|
441ced217b | |
|
5823ec6f8c | |
|
46381e90d1 | |
|
7f19972347 | |
|
7bc213fe88 | |
|
91125c5e44 | |
|
a465849391 | |
|
1e47fa7c91 | |
|
b63b15c7fd | |
|
f079a812b1 | |
|
38ef156b55 | |
|
26736a1cd6 | |
|
e2c3de3601 | |
|
b676462dd7 | |
|
cadafb6fe0 | |
|
2e6544031d | |
|
0d1ca7bc49 | |
|
8ccaedd3d1 | |
|
4fbbe88ca9 | |
|
1a6d333c1a | |
|
a33a26a87e | |
|
1d3bf34da6 | |
|
6a87765f3d | |
|
a18bc247bb | |
|
98f2898395 | |
|
5b7eaa0663 | |
|
fbbfab7a31 | |
|
f6a2883c00 | |
|
421fba24c2 | |
|
eaeb65443e | |
|
f81bd6bffb | |
|
444ce3764b | |
|
ba1251be28 | |
|
2033b2cbf0 | |
|
192e555315 | |
|
3760eab73d | |
|
1026a5ea3d | |
|
2a1b9792cd | |
|
844811bc48 | |
|
033c65b46f | |
|
973e18812c | |
|
8588c486e3 | |
|
46124f7f15 | |
|
9ec3f4655e | |
|
cd71532dd7 | |
|
cbdbc4b25e | |
|
5b9b08c05d | |
|
ccfe28ceb9 | |
|
4d75e4a174 | |
|
d10334a825 | |
|
30eedbafb9 | |
|
7b6845ec3e | |
|
f80a33c9df | |
|
39f234cc06 | |
|
04f8bcb1b0 | |
|
0559110d12 | |
|
05dd162646 | |
|
9f269189a4 | |
|
12ae3b94d9 | |
|
b153a486f3 | |
|
0852a70417 | |
|
eff2b1fe36 | |
|
0dea83488d | |
|
792810f4a9 | |
|
9c2990e3f8 | |
|
75011f66c3 | |
|
9e6ea77bf9 | |
|
fb572af48f | |
|
2ee2a5f3f3 | |
|
655ac8ec67 | |
|
adf77df1bf | |
|
771798220c | |
|
9f0956ac75 | |
|
96e346c4e9 | |
|
4516558e6f | |
|
958631ce36 | |
|
118edbf61f | |
|
1d9387e1ab | |
|
d69438454d | |
|
63753c3963 | |
|
0643d24486 | |
|
1a374468ea | |
|
91399808c4 | |
|
11743355ef | |
|
fde238eb1b | |
|
19c2367257 | |
|
69b5cae870 | |
|
a8b0435c94 | |
|
854df00ffb | |
|
b7aa1e51b3 | |
|
233642d903 | |
|
fd54d4d10c | |
|
f66e6a7774 | |
|
65dba54a41 | |
|
913f4faefd | |
|
435f458f6a | |
|
8819c9b9ae | |
|
61a36cc847 | |
|
bd9ca0439c | |
|
f1a79d926c | |
|
97685bf68c | |
|
6f0afffb3b | |
|
6ba2d39e9b | |
|
2b55bfacf8 | |
|
97af146a30 | |
|
8725e9ef8c | |
|
b7c009ae94 | |
|
1fc75379e4 | |
|
c9df8fa3fe | |
|
f9e7dafefd | |
|
c362315ea5 | |
|
d109859149 | |
|
8177606f81 | |
|
6dda125a1c | |
|
baa2c62186 | |
|
da6931d790 | |
|
21eb842766 | |
|
d577f1691a | |
|
ecde7be506 | |
|
87bcc7b8d0 | |
|
785275c65b | |
|
f36a0f18ad | |
|
cc5a671458 | |
|
99266bce7e | |
|
7dda079ff3 | |
|
c640b81de2 | |
|
79e3ac3fa8 | |
|
a34f17b669 | |
|
b0ec4d7e9e | |
|
389a72b0a1 | |
|
90fa4774d8 | |
|
551f9cbbad | |
|
a30a5b09a0 | |
|
c9d8ce073f | |
|
ae842938c2 | |
|
c2f8da0dd1 | |
|
11f0373c26 | |
|
07bc3b4eab | |
|
2ca8c90487 | |
|
40423aabf7 | |
|
f70cbc09b4 | |
|
e22b2c8c29 | |
|
fe924527ec | |
|
fc1fa8de23 | |
|
290f5cc161 | |
|
b38a329584 | |
|
499473c296 | |
|
efc99407a8 | |
|
a384e129c6 | |
|
2d661f2d45 | |
|
dfe2f8a7a2 | |
|
013a1d6cba | |
|
4d4a98c3b7 | |
|
8637dfb193 | |
|
90d0c8a282 | |
|
26263ba5bb | |
|
a6868e8b12 | |
|
90f992a1c0 | |
|
bad7be4266 | |
|
7f8aac4d28 | |
|
2c8e285170 | |
|
6d593f786b | |
|
b4c5991bc8 | |
|
4318e9acfa | |
|
7767f4b262 | |
|
2ac7a416c7 | |
|
ec01552818 | |
|
4146843d71 | |
|
32b40487f6 | |
|
6b1c87a415 | |
|
939cce2cd3 | |
|
c1173511e0 | |
|
6b73b5383d | |
|
33801448fe | |
|
36d17d37a4 | |
|
55fac3d6e2 | |
|
68bb149dab | |
|
3dfb616213 | |
|
93ad4b046b | |
|
0c509c58ed | |
|
502884810d | |
|
89d6a3f48d | |
|
30b779d54b | |
|
d993c1f4e1 | |
|
f87268eac0 | |
|
1d81361c6a | |
|
14f0320494 | |
|
f6f3aa53f9 | |
|
f8a489a1a8 | |
|
4fc96c477f | |
|
4eb634c109 | |
|
025e3f1ac7 | |
|
71ae7b3e57 | |
|
9ca81b06b0 | |
|
105f4401c2 | |
|
49b4224a69 | |
|
486156ff92 | |
|
59907c371d | |
|
2219dc5b76 | |
|
1a53054e58 | |
|
73b2173a2d | |
|
3b60fee922 | |
|
b6746d5c49 | |
|
069f165fc5 | |
|
2d30ae9914 | |
|
1450aec0f5 | |
|
77d01360e6 | |
|
f6f8a1ca87 | |
|
68d38079fb | |
|
ee7916de01 | |
|
90928219fb | |
|
619dce03ca | |
|
f68224ea2b | |
|
7df9bfd297 | |
|
43b7dc92b7 | |
|
756e308e06 | |
|
4d172eef94 | |
|
6cf51901d8 | |
|
69568cf626 | |
|
5877162714 | |
|
fdc7c1565e | |
|
0c361b0c54 | |
|
7482458135 | |
|
ace64f6071 | |
|
814aa55578 | |
|
0187851a04 | |
|
9de04dba7e | |
|
30a17f53b3 | |
|
2d113ff02a | |
|
4438b11c51 | |
|
1449064b64 | |
|
a0b4da4247 | |
|
e8348194b7 | |
|
ac815ed9a2 | |
|
fc8c31ec66 | |
|
c53b084538 | |
|
0c4e3a1be7 | |
|
4a4ffea71c | |
|
d6399e26db | |
|
395c3fd1fc | |
|
c98c7d5ac5 | |
|
e09dbfeba5 | |
|
750a032f3f | |
|
4d0225e0d9 | |
|
f6c5916b97 | |
|
cfb7f61f0d | |
|
aa739a25b6 | |
|
626fa8a7b3 | |
|
a05ef8d107 | |
|
1b4ca03ac7 | |
|
07918dbb04 | |
|
be2491cd90 | |
|
45587ad543 | |
|
73c747397f | |
|
6eafc2eb84 | |
|
58e17d6a01 | |
|
b83982c623 | |
|
c58ca88edd | |
|
4c82863851 | |
|
e0fc959037 | |
|
1573abdde1 | |
|
b96d52a84d | |
|
62de4a0ac8 | |
|
cf5b4c1e2d | |
|
9c84856f99 | |
|
0a80eea1aa | |
|
e393b13ac1 | |
|
ff1e85cad5 | |
|
983edca9a3 | |
|
ed4b4062e0 | |
|
c590c29f29 | |
|
97d1e9466b | |
|
11d087b381 | |
|
ad085fcddc | |
|
56dca30f69 | |
|
61ca57e4e0 | |
|
c87da2947f | |
|
fe6c821a69 | |
|
541815fb03 | |
|
e812f07a14 | |
|
572a6de2ad | |
|
c88479a8ec | |
|
4d3e33a4e8 | |
|
8325fa7367 | |
|
15fc5b84fe | |
|
3b389480f4 | |
|
f610d35213 | |
|
10b404f750 | |
|
52aeb9ec07 | |
|
907098619b | |
|
5edd492343 | |
|
0d0f25777a | |
|
a6343d5442 | |
|
d2c44ed163 | |
|
8c077ef9a8 | |
|
411e7535d9 | |
|
790a7eeb8c | |
|
da831ec6e7 | |
|
8760e46c4b | |
|
15513718f9 | |
|
2b7414c2fc | |
|
f55d69d5cf | |
|
4c956e48ae | |
|
08fe69ca37 | |
|
801dbd3f2f | |
|
87604a1dea | |
|
329511ac4b | |
|
6ba2394c16 | |
|
4ad6b265c7 | |
|
47c4d30cf7 | |
|
b078501460 | |
|
656c446471 | |
|
eb5c2a6b8b | |
|
caa7acc654 | |
|
6f25498c29 | |
|
785869d48a | |
|
65ad9f6c44 | |
|
2724174f9a | |
|
c6ae30f2cd | |
|
ddaa6f7aec | |
|
35378c3a04 | |
|
697f022ab1 | |
|
e9587ff322 | |
|
4fbf7a52cd | |
|
871904fb9c | |
|
5559330706 | |
|
ddf754485a | |
|
9462e14628 | |
|
c5ec05ea77 | |
|
cf6b991027 | |
|
6155187550 | |
|
7e654331db | |
|
26b00f364f | |
|
ba2e03287d | |
|
362aee1a35 | |
|
0414086daa | |
|
35f1b840a6 | |
|
28ed60da16 | |
|
20e8561815 | |
|
d5c8fe6e56 | |
|
e0b1d6fbb6 | |
|
fd48f00097 | |
|
2a3f2fb620 | |
|
c63258a519 | |
|
e96d4e3d05 | |
|
b1b234d6c0 | |
|
81b8255a54 | |
|
d385319764 | |
|
a98fe05599 | |
|
b3a51f2f74 | |
|
08a5028006 | |
|
ff57561aad | |
|
f0622b6261 | |
|
2f880fe068 | |
|
d8dbea60eb | |
|
8ae91ff558 | |
|
ba228a7e93 | |
|
60857ed357 | |
|
61f893ba0a | |
|
4cacc91130 | |
|
ef6d952124 | |
|
be73306cf8 | |
|
a3b31ee67a | |
|
6683fef667 | |
|
289d1e795e | |
|
cb0ecc4194 | |
|
db40a21b04 | |
|
0a2ab5eddc | |
|
b236733637 | |
|
f0b9765462 | |
|
9835f4f84f | |
|
5f899d8706 | |
|
c591a445f0 | |
|
03f1c59391 | |
|
1c1cceabbe | |
|
d5f841441b | |
|
e556e53f54 | |
|
5af5219f97 | |
|
ae4ad29821 | |
|
31ede9c69d | |
|
589d2ae2e8 | |
|
a273c1cfcf | |
|
9c32cd8769 | |
|
9f8d0e4aac | |
|
af9436622c | |
|
dd4eab1c9d | |
|
031ad5fb08 | |
|
6f0993396d | |
|
8cdacc3210 | |
|
01a38f89a7 | |
|
9a7e9b4237 | |
|
e9237d7789 | |
|
81d39588c6 | |
|
946b449d9d | |
|
f28f1a5c55 | |
|
b744e10dfc | |
|
a54aa72f46 | |
|
c58880a4d3 | |
|
0f5066f943 | |
|
b7a400060b | |
|
7ab159d7f9 | |
|
643fb163d9 | |
|
5fb4a82f2b | |
|
1a186547d3 | |
|
240e086232 | |
|
565c1c1cab | |
|
6f458e0e79 | |
|
4dc1c0b7b4 | |
|
4c7963585f | |
|
edfc540469 | |
|
eeb0994961 | |
|
831d314ebd | |
|
1554268b17 | |
|
9950273460 | |
|
63db6624e1 | |
|
d88b8cbb8a | |
|
8b1ef7bf15 | |
|
804d369de2 | |
![]() |
9654cc280e | |
|
d79f6e2dfa | |
![]() |
74d7875552 | |
|
2605b6eda8 | |
![]() |
d37ce50c40 | |
|
7271603248 | |
|
e358e3b6f6 | |
|
91cb0ea036 | |
![]() |
a1941fb594 | |
|
05f83bca6c | |
![]() |
d5fb8587ee | |
|
6d70bc6aa9 | |
![]() |
21fb916c90 | |
|
2dafe8c9c9 | |
|
8e8226d15b | |
|
3a81c0e859 | |
|
810db632d9 | |
|
3762515207 | |
|
07a43120f2 | |
|
0dc4ecbfb8 | |
|
5e9621d8d7 | |
|
d84ebe0f42 | |
|
6feb3369c2 | |
|
89565acd13 | |
|
7ef905c7d6 | |
|
f9b1aac07e | |
|
04e70b3b34 | |
|
ad9345badb | |
|
5a61933857 | |
|
1e8dba9050 | |
|
d2d602ab89 | |
|
b227250020 | |
|
e861dd059e | |
|
957a8f9d85 | |
|
99fd459bd6 | |
|
bc58efa397 | |
|
49bcff6277 | |
|
abed0079d9 | |
|
870b09f5d5 | |
|
0d03ef88b4 | |
|
69e611c427 | |
|
dea9444a56 | |
|
493de92920 | |
|
03c9df3f92 | |
|
7440a79cc4 | |
|
7d560032b0 | |
|
8ac9592195 | |
|
c8b37448d5 | |
|
47c4af8ea1 | |
|
dbfbee78fa | |
|
0a13387c1c | |
|
9b0581831f | |
|
5519c9c51a | |
|
81e916889e | |
|
7880ec1779 | |
|
a0b7cc99a1 | |
|
59a6e3121e | |
|
d3b552337e | |
|
a1ba0b596a | |
|
9fbd0a470e | |
|
35cc2cb735 | |
|
f4ddc45d6b | |
|
d7a414aa1f | |
|
2d264bf52b | |
|
d8ddde617f | |
|
d4055bbe75 | |
|
15b8f1e068 | |
|
30ffd95fa5 | |
|
51266553f8 | |
|
cb125dc85f | |
|
b91358a7fe | |
|
68348f1fc3 | |
|
c999d37f7e | |
|
6e2816af75 | |
|
bf7289032a | |
|
d6acce86a7 | |
|
7bdab0bc53 | |
|
e891d52c32 | |
|
d78bd895d1 | |
|
b8b5828a7c | |
|
721116467b | |
|
fd6f904f7e | |
|
444c57c237 | |
|
531611c9df | |
|
c88d0c2712 | |
|
acb99701a1 | |
|
62ff6dd1d7 | |
|
a0f1679f03 | |
|
cc66f99d64 | |
|
b051213278 | |
|
c1fbea8453 | |
|
28dfce0247 | |
|
7d769ad118 | |
|
ea29f4c673 | |
|
370a565a7c | |
|
597d77ba85 | |
|
f3f63e3dd3 | |
|
780ba6c103 | |
|
d96a33fca4 | |
|
41e9f00138 | |
|
1e70d93a83 | |
|
c6152aaca8 | |
|
48c5aa732f | |
|
a7b6dbc1a0 | |
|
a8997ae160 | |
|
f422350895 | |
|
69754d5c11 | |
|
0f546bc316 | |
|
847e501dee | |
|
c7bdaa8962 | |
|
d95fefe589 | |
|
0e31daf9a8 | |
|
1ed41b93d8 | |
|
404abe3b2a | |
|
dd96e1e2da | |
|
d20a7b65c2 | |
|
be531eb283 | |
|
1894f00a2d | |
|
2d9b97ee78 | |
|
d2b6f4189a | |
|
5e1c1d8c87 | |
|
8eefb8ca07 | |
|
f35dddbbf7 | |
|
59e8ce206f | |
|
5aab575b36 | |
|
6e41605cbc | |
|
8760a8234f | |
|
13e58392dc | |
|
a247ac0d3a | |
|
4e05be3176 | |
|
c5af356f34 | |
|
4ca1e2e85a | |
|
3934b1b8a4 | |
![]() |
6694ed625f | |
|
7f6c6383bc | |
|
8bdad1d1c0 | |
![]() |
9b5fdb5134 | |
|
ecd1cea4e1 | |
|
08e17454d5 | |
|
92de5dd69d | |
![]() |
0d815db283 | |
|
447429a663 | |
|
94b7129257 | |
|
d0bc8e4378 | |
|
c88c64b33b | |
|
d477d2cabb | |
|
725226e930 | |
![]() |
f3dd40515a | |
|
5fa1edb434 | |
![]() |
9e90b2cef3 | |
|
413b90199d | |
![]() |
65d2387931 | |
![]() |
9b9374c99b | |
|
34d00a9c6d | |
![]() |
b456bf99ca | |
|
6a4f63d8ea | |
|
feec49d4bd | |
|
a644a65493 | |
|
d8eeb8f1b7 | |
|
c94bffd844 | |
|
096941ea9e | |
|
026d58c347 | |
|
a0265d4808 | |
|
ee1b0556ad | |
![]() |
a5a22f6889 | |
|
eb00419eb4 | |
![]() |
9538767167 | |
|
932fa04a45 | |
![]() |
7d8e0d018e | |
|
69b9ae0cb0 | |
![]() |
53083d3030 | |
|
fc007d8f0b | |
![]() |
f39b83692b | |
|
0c148b0fad | |
![]() |
3094c81d2c | |
|
0e72e11275 | |
![]() |
3505d29410 | |
|
8ca9ced360 | |
|
036acfc43d | |
|
627332e93a | |
|
c957617263 | |
|
6ff89d7929 | |
|
d2663eb7b7 | |
|
0e8a3ddb79 | |
|
f61393f34a | |
|
df0ef313f6 | |
|
b6b81b6092 | |
|
28de064841 | |
|
768764a814 | |
|
ea0bdd83d0 | |
![]() |
efef195c27 | |
|
0ce1b5fd9c | |
![]() |
45e8b4d832 | |
|
1f07833de9 | |
|
dbf41c04b3 | |
|
604e3eeba1 | |
|
299978833d | |
|
088bb3d1ac | |
|
3986b86852 | |
|
b33c4bf78b | |
![]() |
0d250e0d4e | |
|
5649f5b67a | |
![]() |
406da81ccf | |
|
5a0c7cddcf | |
![]() |
27b81a5479 | |
![]() |
dbdebc6232 | |
|
d106ac9763 | |
|
4889eb8554 | |
![]() |
f85f9fe4f4 | |
|
c9b6484b66 | |
![]() |
191153a39e | |
|
07a563f769 | |
![]() |
ea6295c888 | |
|
7a57108ca5 | |
|
99e0d8b128 | |
|
90ea1804e9 | |
|
c562d5a102 | |
|
24e4020809 | |
|
f98c044715 | |
|
9ef255f3b6 | |
|
e4faee134a | |
|
1fd4196751 | |
|
89e755a590 | |
|
ec2f7d8c03 | |
|
302e501610 | |
|
354242a290 | |
|
7d6e09c696 | |
|
db0b47c39e | |
|
f468f0cf67 | |
|
4453975b54 | |
|
65abdda8f9 | |
|
2ebd8c44f5 | |
|
817b607a54 | |
|
6d2ae4dcf1 | |
|
3c33ef7709 | |
![]() |
afe4a66c2b | |
|
d6229b62bf | |
![]() |
539bf58e0d | |
|
ed81ce5927 | |
|
5a5a602ce5 | |
|
1c8811fda6 | |
|
4498369064 | |
|
7d813c0ebe | |
|
109ef3fe1c | |
|
38f711f4ae | |
|
ccdacb641f | |
|
3333e8c779 | |
|
fd62ffdee2 | |
|
6ca883aedd | |
|
e2374676c3 | |
|
d55ff07296 | |
|
f893ce41d0 | |
|
ebdfbbf420 | |
|
8edc150800 | |
|
f9ce2a8b26 | |
|
72b3279e8b | |
|
3a85d1d736 | |
|
1e159ec1cf | |
|
bf3f25972e | |
|
6756687c07 | |
|
c89c394374 | |
|
35e6d945dd | |
|
3ceefc33f8 | |
![]() |
f2b732b8e7 | |
|
05aeecf67a | |
|
515bf4663d | |
![]() |
1cd25c188c | |
|
5fafd8195c | |
|
9d45ea07c8 | |
|
beb96c5526 | |
|
2562329a5e | |
|
d79213d14f | |
|
2f68da74cb | |
![]() |
5aff334054 | |
|
3d0fd28c2a | |
![]() |
9f60518e3e | |
|
e25f27e488 | |
![]() |
3a0a95a18f | |
|
f3376594f1 | |
![]() |
69c4d461a4 | |
|
3fefc0d7c6 | |
|
93ab86e363 | |
|
3f621bd5b5 | |
|
ae8b86ef02 | |
|
1195a7a339 | |
![]() |
d590e1165e | |
|
6b8749589e | |
|
883542dfe8 | |
|
3b5b78faed | |
|
1d48af015e | |
|
26461f3a44 | |
|
21f559f254 | |
|
016a2f8cf5 | |
|
75fff13550 | |
|
2c5b9649aa | |
|
c8217d8596 | |
|
761021d191 | |
|
326dcc56ab | |
|
3806ddaa17 | |
|
5fe9719cc9 | |
|
c6a38c06d0 | |
|
eaf389ecea | |
|
7b1d0e21ee | |
|
9979ae6d3a | |
|
b80ed537fc | |
|
de393148d9 | |
|
b7597c3fa7 | |
|
505d873ea6 | |
|
1eb18e4036 | |
|
0b21d4af41 | |
|
1ecd7f26b6 | |
|
7d1b4da72c | |
|
d4b46dbf97 | |
|
d98ad8a3f4 | |
|
ad96991730 | |
|
03283813c2 | |
|
4b57e96914 | |
|
e78f7ab9dd | |
|
835f2db759 | |
|
ac601b4b22 | |
|
c972d538ee | |
|
c75953d343 | |
|
a2ca6bd91b | |
|
129970a525 | |
|
8be254710e | |
|
062e654d45 | |
|
095c83d2d0 | |
|
39aa02ff57 | |
|
b29e500645 | |
|
60c8b25075 | |
|
247c5a60b1 | |
|
de1266ba6c | |
|
9a0809e45b | |
|
637fcca509 | |
|
8264717017 | |
|
a423576ffc | |
|
852d430178 | |
|
d74901cffa | |
|
008d9dda3e | |
|
947117ac5f | |
|
0cb38bce4f | |
|
aac91538aa | |
|
9ac061f2a9 | |
|
60359333f8 | |
|
b2250db79a | |
|
03277d2ad7 | |
|
c2a4e62131 | |
|
f81b3a0b35 | |
|
48a446662f | |
|
f9753c948e | |
|
648d4189a2 | |
|
09942caa3b | |
|
6bd2bb7024 | |
|
5fec6b3942 | |
|
b15bddea49 | |
|
67ce9af382 | |
|
50986035e2 | |
|
b08c1763ac | |
|
63638d4b2e | |
|
b13f1a681e | |
|
1bdb6dad98 | |
|
fea7c52227 | |
|
98770ca47e | |
|
6fb22d3117 | |
|
d0623e4d57 | |
|
c63c0cc636 | |
|
32f03abe84 | |
|
24b5c4e672 | |
|
65590bd33e | |
|
d2402c4103 | |
|
1bbf53279b | |
|
f9427f17a3 | |
![]() |
d797676639 | |
|
21640fe5e6 | |
|
c97d5f9fdf | |
|
93514e8a73 | |
|
ba196794a8 | |
![]() |
3833816a0a | |
|
fe4f56dd36 | |
|
9c4bc3f37c | |
|
0adff52355 | |
|
1a067d0607 | |
|
bd5f4057f6 | |
|
f8a6dcb3eb | |
|
fe137443f8 | |
|
c09c167bdd | |
|
778f9563f3 | |
|
168f5bf7d1 | |
|
9526d1b896 | |
|
d26dcb5b9a | |
|
2ea41d0100 | |
|
6ae4aded65 | |
![]() |
2985dc7902 | |
|
0c48eeb52b | |
|
3a693b88c0 | |
|
d6fbdd87d0 | |
|
ed8ec15eda | |
|
39423ff6ea | |
|
e683dddcaf | |
|
8030d7db1a | |
|
b305b22a8a | |
|
f48ad14411 | |
|
924406d59f | |
|
6d90cbed81 | |
|
c27aa16699 | |
|
40c5525e0a | |
|
252cfcd353 | |
|
a3f0cf87e1 | |
|
7994839d96 | |
|
fbad9859e6 | |
|
cbbd62121c | |
|
0e35a997f2 | |
|
d84b32f4f6 | |
|
74d9e34187 | |
|
fe4d563d6b | |
|
a0e34c9ddd | |
|
c2f64adf17 | |
|
7da8102782 | |
![]() |
3f8a7c7cee | |
|
0eea1c7d65 | |
![]() |
d45dab31cb | |
|
5e192db530 | |
![]() |
776533be8c | |
|
14d9ca760d | |
![]() |
aa9d45dc91 | |
|
c92c86b65f | |
![]() |
84895231dc | |
|
5ea904b2aa | |
![]() |
bbc3717737 | |
|
252b132a4a | |
![]() |
b3252ddf85 | |
|
35556c0cd4 | |
![]() |
23a1be8ce3 | |
|
ee5c8b4b9e | |
|
a3df60b185 | |
|
9e4e30a495 | |
|
c428c29042 | |
![]() |
f9f0485e50 | |
|
e9318d38f9 | |
![]() |
a303f3d01b | |
|
63cb83b1d9 | |
![]() |
c70e43d19b | |
|
fa7e24b580 | |
![]() |
ad30b56b26 | |
|
da1f1b9c8c | |
![]() |
7ed4d12e95 | |
|
1d4dae4202 | |
![]() |
dddc4f9752 | |
|
a1c58b7a78 | |
![]() |
0fda6721de | |
|
9c76a6171a | |
![]() |
b0ecc0a30b | |
|
404f2fb671 | |
![]() |
d758b367b1 | |
|
2f7e92092e | |
![]() |
19458ac963 | |
|
a61996bdc3 | |
|
ef18964ad1 | |
![]() |
6dda3ef6b9 | |
|
efa9ecfcb0 | |
|
33c56e3e79 | |
|
ce7a0e4884 | |
|
27bfeb5fc8 | |
|
5541002dab | |
|
228209b52c | |
|
9ee2c8dde3 | |
|
783a2e39ae | |
|
9e91427de0 | |
|
030d76e276 | |
|
40ec406a19 | |
|
9c02b8ba31 | |
|
ee25d7b477 | |
![]() |
a644bfee25 | |
|
cd25b78625 | |
![]() |
be45e45dbc | |
|
4020fc3515 | |
![]() |
a474934391 | |
|
e19eae7733 | |
|
8532281904 | |
|
7080b74ebe | |
|
0c553203c1 | |
|
32386c2f66 | |
|
2437bda410 | |
|
71305d7304 | |
|
df201d74e0 | |
|
75a18c1fe4 | |
![]() |
e4c4518e8b | |
|
ea852a8ea6 | |
![]() |
6267217c4b | |
|
af97483873 | |
![]() |
b1d8245a22 | |
![]() |
12bf781c8b | |
|
c2424d4633 | |
![]() |
ed5bf51821 | |
|
2cb7a1cf7e | |
![]() |
7fb462d2db | |
|
130024677f | |
![]() |
fcea1193b9 | |
|
4bc7b65726 | |
![]() |
e66ae562b7 | |
|
601d058edf | |
![]() |
086b66d51d | |
|
cffd930d68 | |
![]() |
778f564e8b | |
|
c4d181f887 | |
|
8d44597916 | |
![]() |
a572554102 | |
![]() |
3fa3f3a7cc | |
|
80ed1c5b8a | |
![]() |
43be8d1724 | |
|
2f61c0963b | |
![]() |
452890f825 | |
|
8af3613200 | |
![]() |
ec43b9e97d | |
|
3aa4d6a33a | |
![]() |
c752671453 | |
|
e83bad4df1 | |
![]() |
00448f0f01 | |
|
084a5d0506 | |
![]() |
8329cc113b | |
|
f7ef709b71 | |
![]() |
005f1d4aa5 | |
![]() |
289cb08ccd | |
|
a5da06b7b3 | |
|
9c7ad15e38 | |
|
5646aadfd6 | |
|
3362c78765 | |
![]() |
b40fcf5d63 | |
|
b06785dd54 | |
![]() |
840bbff88a | |
|
cf26f7b51b | |
![]() |
dd30341f6e | |
![]() |
468c5a3c41 | |
|
99fbd4c04d | |
![]() |
8e658d4d12 | |
|
767b232ed4 | |
![]() |
af002c731d | |
|
32251e8a7b | |
![]() |
061b71955f | |
|
44d6de067d | |
![]() |
f00c3931a8 | |
|
8fd38c0638 | |
![]() |
5c72feb705 | |
|
41bdbd9531 | |
![]() |
36a659678d | |
![]() |
770f743750 | |
|
99cab85b54 | |
![]() |
51648e52b3 | |
![]() |
92cefd34b2 | |
|
e4bf925905 | |
|
34a7add47c | |
|
da5972698f | |
|
6a989f972a | |
|
2e2f7b2bd5 | |
|
cf190632a1 | |
|
d4d96759ac | |
|
25df7c02d5 | |
![]() |
2e43bab1b5 | |
![]() |
f6ffaa82a6 | |
|
e8b36f33ed | |
|
467a4f0b94 | |
|
abbb033fc7 | |
|
99fe06c788 | |
|
fa1a03e4db | |
|
28b8e15fea | |
![]() |
624e5b150e | |
|
6a057dedd0 | |
![]() |
93dc10b6a5 | |
|
fffe776cd5 | |
![]() |
2c4253b04b | |
![]() |
526dac1230 | |
|
ce1d6707b8 | |
![]() |
472499e278 | |
|
2fde0da442 | |
![]() |
d19c94666a | |
|
bf232f3518 | |
|
50a0ecdbd2 | |
|
a27a352dfb | |
![]() |
d60ba95444 | |
|
f5bf0c7a87 | |
![]() |
19d36af37f | |
|
bb0bbeb06c | |
|
1e427a62a6 | |
|
5a28204b12 | |
|
0357f963ff | |
![]() |
6cb7af0401 | |
|
b1736e7aaa | |
![]() |
b92fdb8388 | |
|
3ccac9192d | |
|
ef3472567e | |
|
e07af929b2 | |
|
31b07e47a9 | |
|
b4723a0488 | |
![]() |
f9f99fea7e | |
|
4c354f6841 | |
|
9cd148e108 | |
|
cf2625b12c | |
![]() |
cef99e90b3 | |
|
f655a7b469 | |
![]() |
b7d6be8b9f | |
|
3cfcd1a671 | |
![]() |
e1808e0689 | |
|
f4d6bfc210 | |
![]() |
5592855996 | |
|
d663e6b2bc | |
|
0be711e6f0 | |
![]() |
272b73fa0a | |
![]() |
9d5c5acfbf | |
|
73391911d8 | |
![]() |
b080b8fca5 | |
|
915481468f | |
![]() |
19c8587723 | |
|
206b8d25cb | |
![]() |
3367d748b6 | |
|
e6f2e9a798 | |
|
0da32d15a9 | |
|
29b6c1a4d2 | |
![]() |
412ac22998 | |
![]() |
0e7ccdf58f | |
|
9e650c5f59 | |
![]() |
fab25436a0 | |
|
c6461de871 | |
|
09bab2f462 | |
|
4d1be6134c | |
![]() |
7664e2e4d3 | |
|
35ca53c202 | |
![]() |
6bd1eef14a | |
|
eccdc572c4 | |
![]() |
8d7c114b40 | |
|
7b3dbfd9ab | |
![]() |
892aa31ea9 | |
|
02b85859b5 | |
|
14462752cc | |
|
3235a60a34 | |
![]() |
192f48f26c | |
|
b48c65c3ff | |
![]() |
bd441d024b | |
|
747f58d4d0 | |
![]() |
477b21e633 | |
|
18377dc2e0 | |
|
743c63a796 | |
|
74c42f679a | |
|
300dffd2a1 | |
|
9db60413d9 | |
|
04c147d80d | |
|
1da6c582f0 | |
|
2e15988ad6 | |
|
f47c4e4b9c | |
|
1d1d6ebda1 | |
|
56103a885b | |
|
e177e059dc | |
![]() |
71fd9969cb | |
|
cdf62b4626 | |
|
53b66f6145 | |
|
03ce084916 | |
|
075f525783 | |
|
6248040f8c | |
|
a9f4292586 | |
|
9946b85205 | |
|
810e8b9887 | |
|
a2fb12ffd6 | |
|
1d20f8e5fb | |
|
092a890577 | |
|
46430fc0f0 | |
|
d3bf9f66d6 | |
|
1b3a825c81 | |
![]() |
798488e689 | |
|
df94f815ba | |
![]() |
463c87e68a | |
|
e2334f9604 | |
![]() |
9fc5324319 | |
|
75e3c4f121 | |
![]() |
0a5f575315 | |
|
a1f7414e3e | |
![]() |
497c1d827f | |
|
913552a2c4 | |
![]() |
77d72e8e1a | |
![]() |
06bd275b95 | |
|
a574216c18 | |
![]() |
d4d6751dc0 | |
![]() |
d22a18a8fe | |
![]() |
484d769f1b | |
|
23ac219a94 | |
![]() |
94d0862868 | |
|
5bcc963530 | |
![]() |
4f5f7639f9 | |
|
5a69e604b9 | |
![]() |
1d220a6f13 | |
|
cded93715d | |
![]() |
eb449f9937 | |
|
0ceda653e8 | |
![]() |
31bb2502b8 | |
|
8624ae4f22 | |
![]() |
3dacc83e4a | |
|
2a0322bae9 | |
![]() |
c3a949906a | |
|
a4d8193484 | |
![]() |
7139ae0613 | |
|
766e190b2a | |
![]() |
35062aa87d | |
|
6cb0fd44f1 | |
![]() |
e8c1933778 | |
|
4220788b1f | |
![]() |
9544846c6c | |
|
2ed7ce3e6f | |
![]() |
c4222f1d65 | |
|
36b482e6ed | |
![]() |
890c826685 | |
|
8a2d927e8d | |
![]() |
beeb12c336 | |
|
6f01ce170e | |
|
235ecf6ce2 | |
|
c9659fd926 | |
|
b73f724bb7 | |
|
ca85975197 | |
![]() |
9763d5c780 | |
|
4260fe7a71 | |
![]() |
471fbcace4 | |
![]() |
47a00092b1 | |
|
cf2f5b3e0f | |
![]() |
4790f34e0e | |
|
65be43ed4a | |
![]() |
78ea8988de | |
|
52f751de78 | |
![]() |
1b944e4914 | |
|
e5e2f48126 | |
![]() |
13768a2f3a | |
|
79029fc43b | |
![]() |
bfa5c18304 | |
![]() |
cc6f85939c | |
|
7e7b8407f2 | |
![]() |
f7e1487c10 | |
|
766d41f7de | |
![]() |
a286d97fca | |
|
391059602e | |
|
dd938a218e | |
|
d708c65797 | |
![]() |
7b2db3bd93 | |
|
153c8aebed | |
![]() |
9a2610cfc5 | |
|
2f35b2b5d1 | |
![]() |
c811ded37f | |
|
34d763005e | |
|
bcf085b860 | |
|
e4823c2d18 | |
|
0ea45459b8 | |
|
78b2c80bec | |
|
d1adffbd76 | |
|
f0b7618b3d | |
|
d74cb997ab | |
![]() |
36a3a3a24c | |
|
b706bb26d2 | |
![]() |
96936da9ac | |
|
232bef8f88 | |
|
7e29a5d47f | |
|
ba4c479cc2 | |
|
b01d767bcd | |
|
e4b5479d51 | |
|
26094679e4 | |
![]() |
2784405847 | |
|
1765f7b842 | |
![]() |
6c44ecae2d | |
|
5039f2a9d1 | |
![]() |
e3b3dacde7 | |
|
174a2d47dc | |
|
eb860f742a | |
|
5fb8c7739f | |
|
9f23400d2a | |
|
3527e89866 | |
|
9a5a4e8d66 | |
|
61c4e149de | |
|
92f0ed71a1 | |
|
69c8403758 | |
|
06613493a3 | |
|
9e0404b24e | |
|
8197e30069 | |
|
d9cc7f43b5 | |
|
9da15029b0 | |
|
b4029b9aa4 | |
|
64bca88d35 | |
|
b0e10207a4 | |
|
efe1425157 | |
|
1189388431 | |
|
e00da21545 | |
|
a29b4546e4 | |
|
28942c7863 | |
|
9428b5aebb | |
|
001f505555 | |
|
85fe03e40f | |
|
2dbe80fb29 | |
![]() |
7eb9f0ce2e | |
|
3741445d2b | |
![]() |
4713f526d0 | |
|
c58b821b9f | |
![]() |
012077923c | |
|
62781412dd | |
![]() |
c98e3c9d74 | |
|
d871c45fca | |
![]() |
39825e9e02 | |
|
a33f2f93c5 | |
![]() |
ab3cf745e8 | |
|
72f88c8c13 | |
|
349c775404 | |
|
a136a0468e | |
|
dd914595fa | |
|
d0178a4a6c | |
|
0ffb5f892d | |
|
3ac9c0b5d8 | |
|
0f5b0b6b48 | |
|
b838921f74 | |
![]() |
5490dd8ee4 | |
![]() |
97861afef9 | |
|
31e9c406c3 | |
![]() |
101534d8fd | |
|
f109332288 | |
![]() |
5d31401d7e | |
|
d62bbe5943 | |
![]() |
8b1857a3d8 | |
|
b4f2d0a9a8 | |
|
53135857fe | |
|
15c584625a | |
![]() |
80321c6ca2 | |
|
5f3f9afbce | |
|
0f45f31db0 | |
|
86a583017b | |
|
3bd4187b0e | |
|
46456d956a | |
|
f15bc3a3bf | |
|
466705bd0f | |
|
b1e55baf36 | |
|
a40c5a7619 | |
|
d1fc1c21f1 | |
|
3740ae3108 | |
|
fc4520c06f | |
|
909488b072 | |
|
3a2b476dd0 | |
|
17934e55e5 | |
|
205e93dd1a | |
|
b7ab513efd | |
|
bbacebc1c9 | |
|
c344859063 | |
|
c85a15b794 | |
|
bdbbdecd70 | |
![]() |
1533e5e737 | |
|
1b68e7c9d5 | |
|
bcab75e5d1 | |
|
2b03ccc67c | |
|
f18f71db9c | |
|
3f63181b4f | |
|
2f411e3421 | |
|
8dc1c7f48c | |
|
0b10f1bcee | |
|
daf498d6b5 | |
|
1a0de3752e | |
|
956531e8f1 | |
|
aff64187c0 | |
|
de095953cc | |
|
7e66c13497 | |
|
be9185543b | |
|
cf46deb21a | |
|
7673a13d3a | |
|
64e85397f3 | |
|
d29052a8dd | |
![]() |
53906590f7 | |
![]() |
921c285d0f | |
![]() |
bc7008d8a4 | |
|
ff53e15b31 | |
![]() |
58abe47051 | |
|
c2d0f040e5 | |
![]() |
bd3a0d1cab | |
|
61b0d4d302 | |
|
f9a02c3bd6 | |
|
f094c3a84c | |
|
d38707f317 | |
![]() |
1b09c93b5e | |
|
2dec7be029 | |
![]() |
65816a980b | |
|
d35bbcf6fb | |
![]() |
99f2c5b996 | |
|
6c1aa9bb31 | |
|
c0f0b90347 | |
|
3b896fca3d | |
|
0faf192b45 | |
|
076120de8d | |
|
88eb382a2b | |
![]() |
65eaafe003 | |
|
897c21e682 | |
![]() |
325f345381 | |
|
eebbc348f4 | |
![]() |
86a616fc2f | |
|
2df283e202 | |
![]() |
7a9be10194 | |
|
de87bd8d75 | |
![]() |
633a6ba585 | |
|
9844ffa0cb | |
![]() |
4077de7360 | |
|
b6a47350ee | |
![]() |
1727435aa6 | |
|
962c2bb04d | |
![]() |
a04e0508d6 | |
|
a4fa95f352 | |
![]() |
fed604989f | |
|
3eb59b0281 | |
|
d407b3c674 | |
![]() |
fb4a44a6fa | |
![]() |
74dcdebe5e | |
![]() |
d5807c0df0 | |
|
63cc2528cd | |
|
e3df5a0f64 | |
|
6be6dd1bf1 | |
|
328c5c3561 | |
|
d0baa9073d | |
|
fca25ff482 | |
|
f28d835e58 | |
|
f4a7903613 | |
|
fafae74dec | |
|
cc4452e4ad | |
|
8ef2839e9c | |
![]() |
fccf36e1eb | |
|
a74b6a1ca4 | |
|
6e42b84040 | |
|
cc504e3c54 | |
![]() |
6b772ea889 | |
|
6270cfb18d | |
![]() |
b938025e5b | |
|
af1e2ae003 | |
![]() |
78a1d48a3e | |
|
37d1db6c82 | |
![]() |
0d00fd1744 | |
|
43c2879f65 | |
![]() |
04b3351962 | |
|
ead3bfdffd | |
![]() |
bde9220641 | |
|
1a0d2fa3e2 | |
![]() |
0a483cf762 | |
|
606d6ab621 | |
![]() |
cfaa5301ea | |
|
a46de1b658 | |
|
b4a5f685be | |
|
89c64e276e | |
|
46252c2feb | |
|
eb8266db90 | |
|
31923c9086 | |
|
5135f60e50 | |
|
66004f3457 | |
|
caa5ad5ac4 | |
|
8be1373bf9 | |
|
7bebe42c49 | |
|
635ca7ca4b | |
|
52cefc5a51 | |
|
cf4b5e9ab8 | |
|
c7b61775c2 | |
|
289e024253 | |
|
68be385af0 | |
|
74de1cf78f | |
|
18a4833759 | |
|
9f40886c45 | |
|
f1ab52da5c | |
|
6f33016a78 | |
|
4591ef2df3 | |
|
b8807d6009 | |
|
471de1dc07 | |
|
63824eaa8b | |
|
80f9e1065d | |
|
d87a2fcd7e | |
|
a6fa3f9354 | |
|
aad2db5c5b | |
|
8f51955bd7 | |
|
b114ee9701 | |
|
14da90d601 | |
|
73d91440d9 | |
|
dc6b92c774 | |
|
554bbe7c7b | |
![]() |
e90c79486a | |
|
d6aa23b484 | |
|
1b93da7f67 | |
|
a2ebf3dbd6 | |
|
cddb204d28 | |
|
da299195a0 | |
|
f7162abe0d | |
|
6d8956e803 | |
|
677f9c2f4e | |
|
da7e0a4143 | |
|
f19dfc9d08 | |
|
3456ddf526 | |
|
f5c3fe2b8d | |
|
712fe34c12 | |
|
b6448d127d | |
|
7116f38061 | |
|
a7968ed95c | |
|
2998fce62e | |
|
b45e9fb224 | |
|
fa57d3a9ba | |
|
9c9c376224 | |
|
cc6228bcfe | |
|
818781f6e0 | |
|
dbdd2f8968 | |
|
ba134ad0fa | |
|
1327fcb4f4 | |
|
166952560e | |
|
7fdd39291b | |
|
d78408d799 | |
|
5fa1709664 | |
|
f289b8046f | |
|
c8a02bf7b0 | |
|
09e674f0c1 | |
|
41a9773c90 | |
|
d14fca3792 | |
|
206b71cf72 | |
|
9449bd6eb9 | |
|
9f4d9aa5db | |
|
a336e91dd8 | |
|
65a00efd32 | |
|
9859c30f9d | |
|
9232f3ca9b | |
|
c56d3dfd83 | |
|
24ac425c21 | |
|
41465a456e | |
|
2c0c6a1a77 | |
|
ef88c31b96 | |
|
eb7e658a7d | |
|
e16452ac90 | |
|
8cc565ca0c | |
|
1b2a4e0b94 | |
|
99f7fe6102 | |
|
8fbf1b4a35 | |
|
09b1007800 | |
|
2aeaee8479 | |
|
681a485192 | |
|
ee62c394fc | |
|
bea6442a1c | |
|
6b68de130c | |
|
58354dc944 | |
|
77c4a44041 | |
![]() |
afe87a2ff1 | |
|
f44b503eec | |
![]() |
23e8bea507 | |
|
0dc810e72d | |
![]() |
3d0cd96e32 | |
|
d1c8f1aead | |
|
bf1ffadf41 | |
|
f07ae49246 | |
|
69f8b43186 | |
|
b3f713e050 | |
|
5eee13ea87 |
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
# Ignore lock config file
|
# Ignore lock config file
|
||||||
*.log
|
*.log
|
||||||
|
.rubocop.yml
|
||||||
|
.env
|
||||||
# mac
|
# mac
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
.bashrc
|
.bashrc
|
||||||
|
@ -85,3 +86,4 @@ dump.rdb
|
||||||
.tags*
|
.tags*
|
||||||
ceshi_user.xlsx
|
ceshi_user.xlsx
|
||||||
public/trace_task_results
|
public/trace_task_results
|
||||||
|
public/项目活跃度排行.xls
|
14
Dockerfile
14
Dockerfile
|
@ -41,11 +41,19 @@ RUN /bin/bash -l -c 'gem install puma -v 5.6.5'
|
||||||
RUN rm -rf Gemfile.lock
|
RUN rm -rf Gemfile.lock
|
||||||
|
|
||||||
RUN cp config/configuration.yml.example config/configuration.yml
|
RUN cp config/configuration.yml.example config/configuration.yml
|
||||||
RUN cp config/database.yml.example config/database.yml
|
RUN cp config/database-docker.yml.example config/database.yml
|
||||||
RUN touch config/redis.yml
|
RUN touch config/redis.yml
|
||||||
RUN touch config/elasticsearch.yml
|
RUN touch config/elasticsearch.yml
|
||||||
|
|
||||||
RUN /bin/bash -l -c 'bundle install'
|
RUN /bin/bash -l -c 'bundle install'
|
||||||
|
|
||||||
#EXPOSE 4000
|
RUN redis-server &
|
||||||
#RUN /bin/bash -l -c 'RAILS_ENV=production puma'
|
|
||||||
|
RUN /bin/bash -l -c 'bundle exec rake sync_table_structure:import_csv'
|
||||||
|
|
||||||
|
RUN /bin/bash -l -c 'rails db:migrate RAILS_ENV=development'
|
||||||
|
|
||||||
|
RUN /bin/bash -l -c 'bundle exec sidekiq -C config/sidekiq.yml -e production -d'
|
||||||
|
|
||||||
|
EXPOSE 4000
|
||||||
|
RUN /bin/bash -l -c 'RAILS_ENV=production puma -C config/puma.rb'
|
9
Gemfile
9
Gemfile
|
@ -1,5 +1,6 @@
|
||||||
#source 'https://gems.ruby-china.com'
|
#source 'https://gems.ruby-china.com'
|
||||||
source 'https://mirrors.cloud.tencent.com/rubygems/'
|
source 'https://mirrors.cloud.tencent.com/rubygems/'
|
||||||
|
#source 'https://rubygems.org'
|
||||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||||
|
|
||||||
gem 'rails', '~> 5.2.0'
|
gem 'rails', '~> 5.2.0'
|
||||||
|
@ -26,7 +27,7 @@ gem 'roo-xls'
|
||||||
gem 'simple_xlsx_reader', '~>1.0.4'
|
gem 'simple_xlsx_reader', '~>1.0.4'
|
||||||
|
|
||||||
gem 'rubyzip'
|
gem 'rubyzip'
|
||||||
|
gem 'sonarqube', :git => 'https://gitlink.org.cn/KingChan/sonarqube.git'
|
||||||
gem 'spreadsheet'
|
gem 'spreadsheet'
|
||||||
gem 'ruby-ole'
|
gem 'ruby-ole'
|
||||||
# 导出为xlsx
|
# 导出为xlsx
|
||||||
|
@ -70,6 +71,7 @@ group :development do
|
||||||
gem 'web-console', '>= 3.3.0'
|
gem 'web-console', '>= 3.3.0'
|
||||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
|
gem 'pry-rails'
|
||||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||||
gem "annotate", "~> 2.6.0"
|
gem "annotate", "~> 2.6.0"
|
||||||
end
|
end
|
||||||
|
@ -114,7 +116,6 @@ gem 'aasm'
|
||||||
gem 'enumerize'
|
gem 'enumerize'
|
||||||
|
|
||||||
gem 'diffy'
|
gem 'diffy'
|
||||||
|
|
||||||
gem 'deep_cloneable', '~> 3.0.0'
|
gem 'deep_cloneable', '~> 3.0.0'
|
||||||
|
|
||||||
# oauth2
|
# oauth2
|
||||||
|
@ -141,4 +142,6 @@ gem 'doorkeeper'
|
||||||
|
|
||||||
gem 'doorkeeper-jwt'
|
gem 'doorkeeper-jwt'
|
||||||
|
|
||||||
gem 'gitea-client', '~> 1.4.2'
|
gem 'gitea-client', '~> 1.6.1'
|
||||||
|
|
||||||
|
gem 'loofah', '~> 2.20.0'
|
36
Gemfile.lock
36
Gemfile.lock
|
@ -99,6 +99,7 @@ GEM
|
||||||
archive-zip (~> 0.10)
|
archive-zip (~> 0.10)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
chunky_png (1.3.11)
|
chunky_png (1.3.11)
|
||||||
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.1.6)
|
concurrent-ruby (1.1.6)
|
||||||
connection_pool (2.2.2)
|
connection_pool (2.2.2)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
|
@ -135,7 +136,7 @@ GEM
|
||||||
fugit (1.4.1)
|
fugit (1.4.1)
|
||||||
et-orbi (~> 1.1, >= 1.1.8)
|
et-orbi (~> 1.1, >= 1.1.8)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
gitea-client (1.4.2)
|
gitea-client (1.5.9)
|
||||||
rest-client (~> 2.1.0)
|
rest-client (~> 2.1.0)
|
||||||
globalid (0.4.2)
|
globalid (0.4.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
@ -148,7 +149,7 @@ GEM
|
||||||
hashie (3.6.0)
|
hashie (3.6.0)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
http-accept (1.7.0)
|
http-accept (1.7.0)
|
||||||
http-cookie (1.0.5)
|
http-cookie (1.0.8)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
i18n (1.8.2)
|
i18n (1.8.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
|
@ -178,7 +179,8 @@ GEM
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
ruby_dep (~> 1.2)
|
ruby_dep (~> 1.2)
|
||||||
loofah (2.4.0)
|
logger (1.6.6)
|
||||||
|
loofah (2.20.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -187,9 +189,10 @@ GEM
|
||||||
mimemagic (~> 0.3.2)
|
mimemagic (~> 0.3.2)
|
||||||
maruku (0.7.3)
|
maruku (0.7.3)
|
||||||
method_source (0.9.2)
|
method_source (0.9.2)
|
||||||
mime-types (3.4.1)
|
mime-types (3.6.0)
|
||||||
|
logger
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2023.0218.1)
|
mime-types-data (3.2025.0220)
|
||||||
mimemagic (0.3.10)
|
mimemagic (0.3.10)
|
||||||
nokogiri (~> 1)
|
nokogiri (~> 1)
|
||||||
rake
|
rake
|
||||||
|
@ -244,14 +247,18 @@ GEM
|
||||||
popper_js (1.16.0)
|
popper_js (1.16.0)
|
||||||
powerpack (0.1.2)
|
powerpack (0.1.2)
|
||||||
prettier (0.18.2)
|
prettier (0.18.2)
|
||||||
|
pry (0.12.2)
|
||||||
|
coderay (~> 1.1.0)
|
||||||
|
method_source (~> 0.9.0)
|
||||||
|
pry-rails (0.3.9)
|
||||||
|
pry (>= 0.10.4)
|
||||||
public_suffix (4.0.3)
|
public_suffix (4.0.3)
|
||||||
puma (3.12.2)
|
puma (5.6.5)
|
||||||
|
nio4r (~> 2.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
rack (2.0.9)
|
rack (2.0.9)
|
||||||
rack-cors (1.1.1)
|
rack-cors (1.1.1)
|
||||||
rack (>= 2.0.0)
|
rack (>= 2.0.0)
|
||||||
rack-mini-profiler (2.0.1)
|
|
||||||
rack (>= 1.2.0)
|
|
||||||
rack-protection (2.0.8.1)
|
rack-protection (2.0.8.1)
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
|
@ -448,9 +455,7 @@ GEM
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (4.2.0)
|
uglifier (4.2.0)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unf (0.1.4)
|
unf (0.2.0)
|
||||||
unf_ext
|
|
||||||
unf_ext (0.0.8.2)
|
|
||||||
unicode-display_width (1.6.1)
|
unicode-display_width (1.6.1)
|
||||||
web-console (3.7.0)
|
web-console (3.7.0)
|
||||||
actionview (>= 5.0)
|
actionview (>= 5.0)
|
||||||
|
@ -492,7 +497,7 @@ DEPENDENCIES
|
||||||
enumerize
|
enumerize
|
||||||
faraday (~> 0.15.4)
|
faraday (~> 0.15.4)
|
||||||
font-awesome-sass (= 4.7.0)
|
font-awesome-sass (= 4.7.0)
|
||||||
gitea-client (~> 1.4.2)
|
gitea-client (~> 1.5.8)
|
||||||
grape-entity (~> 0.7.1)
|
grape-entity (~> 0.7.1)
|
||||||
groupdate (~> 4.1.0)
|
groupdate (~> 4.1.0)
|
||||||
harmonious_dictionary (~> 0.0.1)
|
harmonious_dictionary (~> 0.0.1)
|
||||||
|
@ -502,6 +507,7 @@ DEPENDENCIES
|
||||||
kaminari (~> 1.1, >= 1.1.1)
|
kaminari (~> 1.1, >= 1.1.1)
|
||||||
letter_avatar
|
letter_avatar
|
||||||
listen (>= 3.0.5, < 3.2)
|
listen (>= 3.0.5, < 3.2)
|
||||||
|
loofah (~> 2.20.0)
|
||||||
mysql2 (>= 0.4.4, < 0.6.0)
|
mysql2 (>= 0.4.4, < 0.6.0)
|
||||||
oauth2
|
oauth2
|
||||||
omniauth (~> 1.9.0)
|
omniauth (~> 1.9.0)
|
||||||
|
@ -514,9 +520,9 @@ DEPENDENCIES
|
||||||
parallel (~> 1.19, >= 1.19.1)
|
parallel (~> 1.19, >= 1.19.1)
|
||||||
pdfkit
|
pdfkit
|
||||||
prettier
|
prettier
|
||||||
puma (~> 3.11)
|
pry-rails
|
||||||
|
puma (~> 5.6.5)
|
||||||
rack-cors
|
rack-cors
|
||||||
rack-mini-profiler
|
|
||||||
rails (~> 5.2.0)
|
rails (~> 5.2.0)
|
||||||
rails-i18n (~> 5.1)
|
rails-i18n (~> 5.1)
|
||||||
ransack
|
ransack
|
||||||
|
@ -538,7 +544,7 @@ DEPENDENCIES
|
||||||
sidekiq-cron (= 1.2.0)
|
sidekiq-cron (= 1.2.0)
|
||||||
sidekiq-failures
|
sidekiq-failures
|
||||||
simple_form
|
simple_form
|
||||||
simple_xlsx_reader
|
simple_xlsx_reader (~> 1.0.4)
|
||||||
sinatra
|
sinatra
|
||||||
solargraph (~> 0.38.0)
|
solargraph (~> 0.38.0)
|
||||||
spreadsheet
|
spreadsheet
|
||||||
|
|
13
README.md
13
README.md
|
@ -3,7 +3,8 @@
|
||||||
GitLink(确实开源)是中国计算机学会(CCF)官方指定的开源创新服务平台,旨在以“为开源创新服务”为使命,以“成为开源创新的汇聚地”为愿景,秉承“创新、开放、协作、共享”的价值观,致力于为大规模开源开放协同创新助力赋能,打造创新成果孵化和新工科人才培养的开源创新生态!
|
GitLink(确实开源)是中国计算机学会(CCF)官方指定的开源创新服务平台,旨在以“为开源创新服务”为使命,以“成为开源创新的汇聚地”为愿景,秉承“创新、开放、协作、共享”的价值观,致力于为大规模开源开放协同创新助力赋能,打造创新成果孵化和新工科人才培养的开源创新生态!
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/gitlink.png?raw=true" width=80% /></center>
|
<img src="docs/figs/gitlink.png" width=80% /></center>
|
||||||
|
|
||||||
|
|
||||||
## 特色功能
|
## 特色功能
|
||||||
|
|
||||||
|
@ -174,31 +175,31 @@ http://localhost:3000/
|
||||||
- 项目列表
|
- 项目列表
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/project_list.png?raw=true" width=50% />
|
<img src="docs/figs/project_list.png" width=80% />
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
- 代码仓库
|
- 代码仓库
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/repo.png?raw=true" width=50% />
|
<img src="docs/figs/repo.png" width=80% />
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
- 任务管理
|
- 任务管理
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/issues.png?raw=true" width=50% />
|
<img src="docs/figs/issues.png" width=80% />
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
- 合并请求
|
- 合并请求
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/PR.png?raw=true" width=50% />
|
<img src="docs/figs/PR.png" width=80% />
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
- 引擎配置
|
- 引擎配置
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<img src="https://code.gitlink.org.cn/young/forgeplus/raw/branch/master/docs/figs/engine.png?raw=true" width=50% />
|
<img src="docs/figs/engine.png" width=80% />
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -63,7 +63,7 @@ $(document).on('turbolinks:load', function() {
|
||||||
|
|
||||||
if(!valid) return;
|
if(!valid) return;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method: 'PATCH',
|
method: 'PUT',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
url: $form.attr('action'),
|
url: $form.attr('action'),
|
||||||
data: new FormData($form[0]),
|
data: new FormData($form[0]),
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
$(document).on('turbolinks:load', function(){
|
||||||
|
if ($('body.admins-organizations-index-page').length > 0) {
|
||||||
|
var showSuccessNotify = function() {
|
||||||
|
$.notify({
|
||||||
|
message: '操作成功'
|
||||||
|
},{
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// organizations open cla
|
||||||
|
$('.organizations-list-container').on('click', '.open-cla-action', function(){
|
||||||
|
var $openClaAction = $(this);
|
||||||
|
var $closeClaAction = $openClaAction.siblings('.close-cla-action');
|
||||||
|
|
||||||
|
var userId = $openClaAction.data('id');
|
||||||
|
customConfirm({
|
||||||
|
content: '确认开通吗?',
|
||||||
|
ok: function () {
|
||||||
|
$.ajax({
|
||||||
|
url: '/admins/organizations/' + userId + '/open_cla',
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function() {
|
||||||
|
showSuccessNotify();
|
||||||
|
$closeClaAction.show();
|
||||||
|
$openClaAction.hide();
|
||||||
|
},
|
||||||
|
error: function(res){
|
||||||
|
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// organizations close cla
|
||||||
|
$('.organizations-list-container').on('click', '.close-cla-action', function(){
|
||||||
|
var $closeClaAction = $(this);
|
||||||
|
var $openClaAction= $closeClaAction.siblings('.open-cla-action');
|
||||||
|
|
||||||
|
var userId = $openClaAction.data('id');
|
||||||
|
customConfirm({
|
||||||
|
content: '确认关闭吗?',
|
||||||
|
ok: function () {
|
||||||
|
$.ajax({
|
||||||
|
url: '/admins/organizations/' + userId + '/close_cla',
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function() {
|
||||||
|
showSuccessNotify();
|
||||||
|
$openClaAction.show();
|
||||||
|
$closeClaAction.hide();
|
||||||
|
},
|
||||||
|
error: function(res){
|
||||||
|
$.notify({ message: res.responseJSON.message }, { type: 'danger' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
// All this logic will automatically be available in application.js.
|
|
@ -40,6 +40,13 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.editormd .CodeMirror{
|
||||||
|
margin-top: 35px!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-gutter .CodeMirror-linenumbers {
|
||||||
|
width: 28px!important;
|
||||||
|
}
|
||||||
|
|
||||||
input.form-control {
|
input.form-control {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the admins/glcc_pr_check controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the admins/identity_verifications controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the admins/page_themes controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the admins/site_pages controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the api/pm/issue_links controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the api/pm/projects controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the api/v1/pm_issues controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the api/v1/sonarqube/issues controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the api/v1/sonarqubes controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the identity_verifications controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the organizations/clas controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the pages controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the pm/journals controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the users/clas controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -1,6 +1,7 @@
|
||||||
class AccountsController < ApplicationController
|
class AccountsController < ApplicationController
|
||||||
before_action :require_login, only: [:login_check, :simple_update]
|
before_action :require_login, only: [:login_check, :simple_update, :change_password]
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
|
include AesCryptHelper
|
||||||
|
|
||||||
#skip_before_action :check_account, :only => [:logout]
|
#skip_before_action :check_account, :only => [:logout]
|
||||||
|
|
||||||
|
@ -8,11 +9,12 @@ class AccountsController < ApplicationController
|
||||||
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
|
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
|
||||||
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
|
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
|
||||||
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
|
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
|
||||||
Register::RemoteForm.new(simple_update_params).validate!
|
Register::RemoteForm.new(simple_update_params.merge(user_id: current_user.id)).validate!
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
result = auto_update(current_user, simple_update_params)
|
result = auto_update(current_user, simple_update_params)
|
||||||
if result[:message].blank?
|
if result[:message].blank?
|
||||||
|
UserAction.create(:action_id => current_user.id, :action_type => "sync_educoder_user", :user_id => current_user.id, :ip => request.remote_ip) if params[:platform] == "educoder"
|
||||||
render_ok
|
render_ok
|
||||||
else
|
else
|
||||||
render_error(result[:message])
|
render_error(result[:message])
|
||||||
|
@ -30,11 +32,12 @@ class AccountsController < ApplicationController
|
||||||
username = params[:username]&.gsub(/\s+/, "")
|
username = params[:username]&.gsub(/\s+/, "")
|
||||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
||||||
email = params[:email]&.gsub(/\s+/, "")
|
email = params[:email]&.gsub(/\s+/, "")
|
||||||
|
phone = params[:phone]&.gsub(/\s+/, "")
|
||||||
password = params[:password]
|
password = params[:password]
|
||||||
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
result = autologin_register(username, email, password, platform)
|
result = autologin_register(username, email, password, platform, phone)
|
||||||
if result[:message].blank?
|
if result[:message].blank?
|
||||||
render_ok({user: result[:user]})
|
render_ok({user: result[:user]})
|
||||||
else
|
else
|
||||||
|
@ -142,7 +145,8 @@ class AccountsController < ApplicationController
|
||||||
|
|
||||||
user = Users::RegisterService.call(register_params)
|
user = Users::RegisterService.call(register_params)
|
||||||
user.mail = "#{user.login}@example.org" if user.mail.blank?
|
user.mail = "#{user.login}@example.org" if user.mail.blank?
|
||||||
password = register_params[:password].strip
|
password = decrypt(register_params[:password]) rescue register_params[:password].to_s
|
||||||
|
password = password.strip
|
||||||
|
|
||||||
# gitea用户注册, email, username, password
|
# gitea用户注册, email, username, password
|
||||||
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
|
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
|
||||||
|
@ -160,8 +164,11 @@ class AccountsController < ApplicationController
|
||||||
successful_authentication(user)
|
successful_authentication(user)
|
||||||
render_ok
|
render_ok
|
||||||
end
|
end
|
||||||
|
elsif interactor.result[:message].to_s.include?("user already exists")
|
||||||
|
UserAction.create(:action_id => 2, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};")
|
||||||
|
normal_status(-1, "用户已注册,请勿连续操作。")
|
||||||
else
|
else
|
||||||
tip_exception(-1, interactor.error)
|
tip_exception(-1, interactor.result[:message])
|
||||||
end
|
end
|
||||||
rescue Register::BaseForm::EmailError => e
|
rescue Register::BaseForm::EmailError => e
|
||||||
render_result(-2, e.message)
|
render_result(-2, e.message)
|
||||||
|
@ -176,28 +183,34 @@ class AccountsController < ApplicationController
|
||||||
rescue Register::BaseForm::VerifiCodeError => e
|
rescue Register::BaseForm::VerifiCodeError => e
|
||||||
render_result(-6, e.message)
|
render_result(-6, e.message)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
Gitea::User::DeleteService.call(user.login) unless user.nil?
|
if user.present? && !e.message.to_s.include?("user already exists")
|
||||||
uid_logger_error(e.message)
|
# Gitea::User::DeleteService.call(user.login)
|
||||||
tip_exception(-1, e.message)
|
# user.destroy
|
||||||
|
end
|
||||||
|
Rails.logger.error("##:register error--#{user.try(:id)},message:#{e.message}")
|
||||||
|
UserAction.create(:action_id => 1, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};")
|
||||||
|
logger_error(e)
|
||||||
|
tip_exception(-1, "注册失败")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# 用户登录
|
# 用户登录
|
||||||
def login
|
def login
|
||||||
Users::LoginForm.new(login_params).validate!
|
password = decrypt(login_params[:password]) rescue login_params[:password].to_s
|
||||||
@user = User.try_to_login(params[:login], params[:password])
|
Users::LoginForm.new(login_params.merge!({password: password})).validate!
|
||||||
|
@user = User.try_to_login(params[:login], password)
|
||||||
|
|
||||||
return normal_status(-2, "错误的账号或密码") if @user.blank?
|
return normal_status(-2, "错误的账号或密码") if @user.blank?
|
||||||
# user is already in local database
|
# user is already in local database
|
||||||
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
|
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
|
||||||
|
|
||||||
login_control = LimitForbidControl::UserLogin.new(@user)
|
login_control = LimitForbidControl::UserLogin.new(@user)
|
||||||
return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
|
return normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
|
||||||
|
|
||||||
password_ok = @user.check_password?(params[:password].to_s)
|
password_ok = @user.check_password?(password.to_s)
|
||||||
unless password_ok
|
unless password_ok
|
||||||
if login_control.remain_times-1 == 0
|
if login_control.remain_times-1 == 0
|
||||||
normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
|
normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
|
||||||
else
|
else
|
||||||
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
|
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
|
||||||
end
|
end
|
||||||
|
@ -207,19 +220,24 @@ class AccountsController < ApplicationController
|
||||||
|
|
||||||
LimitForbidControl::UserLogin.new(@user).clear
|
LimitForbidControl::UserLogin.new(@user).clear
|
||||||
successful_authentication(@user)
|
successful_authentication(@user)
|
||||||
sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步
|
sync_pwd_to_gitea!(@user, {password: password.to_s}) # TODO用户密码未同步
|
||||||
|
|
||||||
# session[:user_id] = @user.id
|
# session[:user_id] = @user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_password
|
def change_password
|
||||||
|
password = decrypt(params[:password]) rescue params[:password].to_s
|
||||||
|
new_password_repeat = decrypt(params[:new_password_repeat]) rescue params[:new_password_repeat].to_s
|
||||||
|
old_password = decrypt(params[:old_password]) rescue params[:old_password]
|
||||||
|
return render_error("两次输入的密码不一致") if password.to_s != new_password_repeat.to_s
|
||||||
@user = User.find_by(login: params[:login])
|
@user = User.find_by(login: params[:login])
|
||||||
|
return render_forbidden unless User.current.login == @user&.login
|
||||||
return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691
|
return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691
|
||||||
return render_error("未找到相关用户!") if @user.blank?
|
return render_error("未找到相关用户!") if @user.blank?
|
||||||
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
|
return render_error("旧密码不正确") unless @user.check_password?(old_password)
|
||||||
|
|
||||||
sync_params = {
|
sync_params = {
|
||||||
password: params[:password].to_s,
|
password: password.to_s,
|
||||||
email: @user.mail,
|
email: @user.mail,
|
||||||
login_name: @user.name,
|
login_name: @user.name,
|
||||||
source_id: 0
|
source_id: 0
|
||||||
|
@ -227,7 +245,7 @@ class AccountsController < ApplicationController
|
||||||
|
|
||||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||||
if interactor.success?
|
if interactor.success?
|
||||||
@user.update_attribute(:password, params[:password])
|
@user.update_attribute(:password, password)
|
||||||
render_ok
|
render_ok
|
||||||
else
|
else
|
||||||
render_error(interactor.error)
|
render_error(interactor.error)
|
||||||
|
@ -351,6 +369,17 @@ class AccountsController < ApplicationController
|
||||||
render_ok
|
render_ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_keywords
|
||||||
|
text = params[:text].to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
|
||||||
|
data = ! ReversedKeyword.check_exists?(text)
|
||||||
|
result = {
|
||||||
|
status: 0,
|
||||||
|
data: data,
|
||||||
|
message: data ? "" : "无法使用以下关键词:#{text},请重新命名"
|
||||||
|
}
|
||||||
|
render_ok(result)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
class Action::NodeInputsController < ApplicationController
|
||||||
|
before_action :require_admin, except: [:index]
|
||||||
|
before_action :find_action_node
|
||||||
|
|
||||||
|
def index
|
||||||
|
@node_inputs = @node.action_node_inputs
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json{ render_ok(data: @node_inputs.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@node_input = Action::NodeInput.new(node_input_params)
|
||||||
|
@node_input.action_node = @node
|
||||||
|
respond_to do |format|
|
||||||
|
if @node_input.save
|
||||||
|
format.html { redirect_to action_node_node_inputs_path(@node), notice: '创建成功.' }
|
||||||
|
format.json { render_ok(data: @node_input.as_json) }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @node_input.errors, status: -1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@node_input.update(node_input_params)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_node_node_inputs_path(@node), notice: '更新成功.' }
|
||||||
|
format.json { render_ok(data: @node_input.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @node_input.destroy!
|
||||||
|
flash[:success] = '删除成功'
|
||||||
|
else
|
||||||
|
flash[:danger] = '删除失败'
|
||||||
|
end
|
||||||
|
redirect_to "api/actions/nodes"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_action_node
|
||||||
|
@node = Action::Node.find(params[:node_id])
|
||||||
|
if params[:id].present?
|
||||||
|
@node_input = @node.action_node_inputs.find(params[:id])
|
||||||
|
else
|
||||||
|
@node_input = Action::NodeInput.new
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def node_input_params
|
||||||
|
if params.require(:action_node_input)
|
||||||
|
params.require(:action_node_input).permit(:name, :input_type, :description, :is_required, :sort_no, :default_value)
|
||||||
|
else
|
||||||
|
params.permit(:name, :input_type, :description, :is_required, :sort_no, :default_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,76 @@
|
||||||
|
class Action::NodeSelectsController < ApplicationController
|
||||||
|
|
||||||
|
before_action :require_admin, except: [:index]
|
||||||
|
before_action :find_action_node
|
||||||
|
|
||||||
|
def index
|
||||||
|
@node_selects = @node.action_node_selects
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@node_select = Action::NodeSelect.new(node_select_params)
|
||||||
|
@node_select.action_node = @node
|
||||||
|
respond_to do |format|
|
||||||
|
if @node_select.save
|
||||||
|
format.html { redirect_to action_node_node_selects_path(@node), notice: '创建成功.' }
|
||||||
|
format.json { render_ok(data: @node_select.as_json) }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @node_select.errors, status: -1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@node_select.update(node_select_params)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_node_node_selects_path(@node), notice: '更新成功.' }
|
||||||
|
format.json { render_ok(data: @node_select.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @node_select.destroy!
|
||||||
|
flash[:success] = '删除成功'
|
||||||
|
else
|
||||||
|
flash[:danger] = '删除失败'
|
||||||
|
end
|
||||||
|
redirect_to "api/actions/nodes"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_action_node
|
||||||
|
@node = Action::Node.find(params[:node_id])
|
||||||
|
if params[:id].present?
|
||||||
|
@node_select = @node.action_node_selects.find(params[:id])
|
||||||
|
else
|
||||||
|
@node_select = Action::NodeSelect.new
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def node_select_params
|
||||||
|
if params.require(:action_node_select)
|
||||||
|
params.require(:action_node_select).permit(:name, :val, :val_ext, :description, :sort_no)
|
||||||
|
else
|
||||||
|
params.permit(:name, :val, :val_ext, :description, :sort_no)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
class Action::NodeTypesController < ApplicationController
|
||||||
|
before_action :require_admin, except: [:index]
|
||||||
|
before_action :find_node_type, except: [:index, :create, :new]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@node_types = Action::NodeType.all
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json { render_ok(data: @node_types.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@node_type = Action::NodeType.new(node_types_params)
|
||||||
|
respond_to do |format|
|
||||||
|
if @node_type.save
|
||||||
|
format.html { redirect_to action_node_types_path, notice: '创建成功.' }
|
||||||
|
format.json { render_ok(data: @node_type.as_json) }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @node_type.errors, status: -1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json { render_ok(data: @node_type.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@node_type = Action::NodeType.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@node_type.update(node_types_params)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_node_types_path, notice: '更新成功.' }
|
||||||
|
format.json { render_ok(data: @node_type.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @node_type.destroy!
|
||||||
|
flash[:success] = '删除成功'
|
||||||
|
else
|
||||||
|
flash[:danger] = '删除失败'
|
||||||
|
end
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_node_types_path }
|
||||||
|
format.json { render_ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_node_type
|
||||||
|
@node_type = Action::NodeType.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def node_types_params
|
||||||
|
if params.require(:action_node_type)
|
||||||
|
params.require(:action_node_type).permit(:name, :description, :sort_no)
|
||||||
|
else
|
||||||
|
params.permit(:name, :description, :sort_no)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,87 @@
|
||||||
|
class Action::NodesController < ApplicationController
|
||||||
|
# before_action :require_admin, except: [:index]
|
||||||
|
before_action :require_login
|
||||||
|
before_action :find_action_node, except: [:index, :create, :new]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@node_types = Action::NodeType.all
|
||||||
|
no_node_type = Action::NodeType.find_by(name: "未分类")
|
||||||
|
@no_type_nodes = Action::Node.where(action_node_types_id: nil)
|
||||||
|
@no_type_nodes = Action::Node.where(action_node_types_id: nil).or(Action::Node.where(action_node_types_id: no_node_type.id)) if no_node_type.present?
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { @nodes = Action::Node.where("name LIKE :search OR full_name LIKE :search", :search => "%#{params[:search]}%") }
|
||||||
|
format.json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@node = Action::Node.new(node_params)
|
||||||
|
if params.require(:node).present? && params.require(:node)[:link_type_array].present?
|
||||||
|
@node.link_type = (params.require(:node)[:link_type_array] - [""]).join(",")
|
||||||
|
end
|
||||||
|
@node.user_id = current_user.id
|
||||||
|
respond_to do |format|
|
||||||
|
if @node.save
|
||||||
|
format.html { redirect_to action_nodes_path, notice: '创建成功.' }
|
||||||
|
format.json { render_ok(data: @node.as_json) }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @node.errors, status: -1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@node = Action::Node.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
if @node.link_type.present?
|
||||||
|
@node.link_type_array = @node.link_type.to_s.split(",")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if params.require(:node).present? && params.require(:node)[:link_type_array].present?
|
||||||
|
@node.link_type = (params.require(:node)[:link_type_array] - [""]).join(",")
|
||||||
|
end
|
||||||
|
@node.user_id = current_user.id if @node.user_id.blank?
|
||||||
|
@node.update(node_params)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_nodes_path, notice: '更新成功.' }
|
||||||
|
format.json { render_ok(data: @node.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @node.destroy!
|
||||||
|
flash[:success] = '删除成功'
|
||||||
|
else
|
||||||
|
flash[:danger] = '删除失败'
|
||||||
|
end
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_nodes_path }
|
||||||
|
format.json { render_ok() }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_action_node
|
||||||
|
@node = Action::Node.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def node_params
|
||||||
|
if params.require(:action_node)
|
||||||
|
params.require(:action_node).permit(:name, :label, :full_name, :description, :icon, :action_node_types_id,
|
||||||
|
:is_local, :local_url, :yaml, :sort_no, :node_type, :is_mutil_link, :link_type, :link_type_array)
|
||||||
|
else
|
||||||
|
params.permit(:name, :label, :full_name, :description, :icon, :action_node_types_id, :is_local, :local_url,
|
||||||
|
:yaml, :sort_no, :node_type, :is_mutil_link, :link_type, :link_type_array)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
class Action::TemplatesController < ApplicationController
|
||||||
|
before_action :require_admin, except: [:index]
|
||||||
|
before_action :find_action_template, except: [:index, :create, :new]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@templates = Action::Template.all
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@template = Action::Template.new(templates_params)
|
||||||
|
respond_to do |format|
|
||||||
|
if @template.save
|
||||||
|
format.html { redirect_to action_templates_path, notice: '创建成功.' }
|
||||||
|
format.json { render_ok(data: @template.as_json) }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @template.errors, status: -1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@template = Action::Template.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@template.update(templates_params)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_templates_path, notice: '更新成功.' }
|
||||||
|
format.json { render_ok(data: @template.as_json) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @template.destroy!
|
||||||
|
flash[:success] = '删除成功'
|
||||||
|
else
|
||||||
|
flash[:danger] = '删除失败'
|
||||||
|
end
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to action_templates_path }
|
||||||
|
format.json { render_ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_action_template
|
||||||
|
@template = Action::Template.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def templates_params
|
||||||
|
if params.require(:action_template)
|
||||||
|
params.require(:action_template).permit(:name, :description, :img, :sort_no, :json, :yaml)
|
||||||
|
else
|
||||||
|
params.permit(:name, :description, :img, :sort_no, :json, :yaml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,10 +23,23 @@ class Admins::BaseController < ApplicationController
|
||||||
def require_admin!
|
def require_admin!
|
||||||
return if current_user.blank? || !current_user.logged?
|
return if current_user.blank? || !current_user.logged?
|
||||||
return if current_user.admin_or_business?
|
return if current_user.admin_or_business?
|
||||||
|
return if current_user.admin_or_glcc_admin?
|
||||||
|
|
||||||
render_forbidden
|
render_forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def require_admin
|
||||||
|
render_forbidden unless User.current.admin?
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_business
|
||||||
|
render_forbidden unless admin_or_business?
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_glcc_admin
|
||||||
|
render_forbidden unless admin_or_glcc_admin?
|
||||||
|
end
|
||||||
|
|
||||||
# 触发after ajax render partial hooks,执行一些因为局部刷新后失效的绑定事件
|
# 触发after ajax render partial hooks,执行一些因为局部刷新后失效的绑定事件
|
||||||
def rebind_event_if_ajax_render_partial
|
def rebind_event_if_ajax_render_partial
|
||||||
return if request.format.symbol != :js
|
return if request.format.symbol != :js
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
class Admins::DashboardsController < Admins::BaseController
|
class Admins::DashboardsController < Admins::BaseController
|
||||||
def index
|
def index
|
||||||
|
# 查询优化
|
||||||
|
week_greater_id = CommitLog.where(created_at: current_week).limit(1)[0]&.id
|
||||||
|
#月份统计还需要优化
|
||||||
|
month_greater_id = CommitLog.where(created_at: current_month).limit(1)[0]&.id
|
||||||
# 用户活跃数
|
# 用户活跃数
|
||||||
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
|
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
|
||||||
weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:user_id).uniq
|
weekly_user_ids = CommitLog.where(created_at: current_week).where("id>= ?", week_greater_id).distinct.pluck(:user_id)
|
||||||
month_user_ids = CommitLog.where(created_at: current_month).pluck(:user_id).uniq
|
month_user_ids = CommitLog.where(created_at: current_month).where("id>= ?", month_greater_id).distinct.pluck(:user_id)
|
||||||
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
|
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
|
||||||
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
|
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
|
||||||
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
||||||
|
@ -18,16 +22,78 @@ class Admins::DashboardsController < Admins::BaseController
|
||||||
|
|
||||||
# 活跃项目数
|
# 活跃项目数
|
||||||
day_project_ids = (CommitLog.where(created_at: today).pluck(:project_id).uniq + Issue.where(created_on: today).pluck(:project_id).uniq).uniq
|
day_project_ids = (CommitLog.where(created_at: today).pluck(:project_id).uniq + Issue.where(created_on: today).pluck(:project_id).uniq).uniq
|
||||||
weekly_project_ids = (CommitLog.where(created_at: current_week).pluck(:project_id).uniq + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
|
weekly_project_ids = (CommitLog.where(created_at: current_week).where("id>= ?", week_greater_id).distinct.pluck(:project_id) + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
|
||||||
month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq
|
month_project_ids = (CommitLog.where(created_at: current_month).where("id>= ?", month_greater_id).distinct.pluck(:project_id) + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq
|
||||||
@day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count
|
@day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count
|
||||||
@weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
|
@weekly_active_project_count = Rails.cache.fetch("dashboardscontroller:weekly_active_project_count", expires_in: 10.minutes) do
|
||||||
@month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
|
Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
|
||||||
|
end
|
||||||
|
@month_active_project_count = Rails.cache.fetch("dashboardscontroller:month_active_project_count", expires_in: 1.hours) do
|
||||||
|
Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
|
||||||
|
end
|
||||||
# 新增项目数
|
# 新增项目数
|
||||||
@day_new_project_count = Project.where(created_on: today).count
|
@day_new_project_count = Rails.cache.fetch("dashboardscontroller:day_new_project_count", expires_in: 10.minutes) do
|
||||||
@weekly_new_project_count = Project.where(created_on: current_week).count
|
Project.where(created_on: today).count
|
||||||
@month_new_project_count = Project.where(created_on: current_month).count
|
end
|
||||||
|
@weekly_new_project_count = Rails.cache.fetch("dashboardscontroller:weekly_new_project_count", expires_in: 10.minutes) do
|
||||||
|
Project.where(created_on: current_week).count
|
||||||
|
end
|
||||||
|
@month_new_project_count = Rails.cache.fetch("dashboardscontroller:month_new_project_count", expires_in: 1.hours) do
|
||||||
|
Project.where(created_on: current_month).count
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# 总的平台用户数
|
||||||
|
# 总的平台项目数
|
||||||
|
# 总的平台组织数
|
||||||
|
# 总的平台Issue数、评论数、PR数、Commit数
|
||||||
|
@user_count = Rails.cache.fetch("dashboardscontroller:platform:user_count", expires_in: 1.days) do
|
||||||
|
User.count
|
||||||
|
end
|
||||||
|
@project_count = Rails.cache.fetch("dashboardscontroller:platform:project_count", expires_in: 1.days) do
|
||||||
|
Project.count
|
||||||
|
end
|
||||||
|
@organization_count = Rails.cache.fetch("dashboardscontroller:platform:organization_count", expires_in: 1.days) do
|
||||||
|
Organization.count
|
||||||
|
end
|
||||||
|
@issue_count = Rails.cache.fetch("dashboardscontroller:platform:issue_count", expires_in: 1.days) do
|
||||||
|
Issue.count
|
||||||
|
end
|
||||||
|
@comment_count = Rails.cache.fetch("dashboardscontroller:platform:comment_count", expires_in: 1.days) do
|
||||||
|
Journal.count
|
||||||
|
end
|
||||||
|
@pr_count = Rails.cache.fetch("dashboardscontroller:platform:pr_count", expires_in: 1.days) do
|
||||||
|
PullRequest.count
|
||||||
|
end
|
||||||
|
@commit_count = Rails.cache.fetch("dashboardscontroller:platform:commit_count", expires_in: 1.days) do
|
||||||
|
CommitLog.count
|
||||||
|
end
|
||||||
|
|
||||||
|
@subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"]
|
||||||
|
@subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"]
|
||||||
|
@subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count]
|
||||||
|
|
||||||
|
if EduSetting.get("open_baidu_tongji").to_s == "true"
|
||||||
|
tongji_service = Baidu::TongjiService.new
|
||||||
|
@access_token = tongji_service.access_token
|
||||||
|
Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}"
|
||||||
|
# @overview_data = tongji_service.api_overview
|
||||||
|
last_date = DailyPlatformStatistic.order(:date).last || Time.now
|
||||||
|
start_date = last_date.date
|
||||||
|
end_date = Time.now
|
||||||
|
if @access_token.present?
|
||||||
|
@overview_data = Rails.cache.fetch("dashboardscontroller:baidu_tongji:overview_data", expires_in: 10.minutes) do
|
||||||
|
tongji_service.source_from_batch_add(start_date, end_date)
|
||||||
|
@overview_data = tongji_service.overview_batch_add(start_date, end_date)
|
||||||
|
@overview_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@current_week_statistic = DailyPlatformStatistic.where(date: current_week)
|
||||||
|
@pre_week_statistic = DailyPlatformStatistic.where(date: pre_week)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def month_active_user
|
def month_active_user
|
||||||
|
@ -42,6 +108,19 @@ class Admins::DashboardsController < Admins::BaseController
|
||||||
render_ok(data: data)
|
render_ok(data: data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def baidu_tongji
|
||||||
|
tongji_service = Baidu::TongjiService.new
|
||||||
|
redirect_to tongji_service.code_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def baidu_tongji_auth
|
||||||
|
if params[:code].present?
|
||||||
|
tongji_service = Baidu::TongjiService.new
|
||||||
|
tongji_service.get_access_token(params[:code])
|
||||||
|
end
|
||||||
|
redirect_to "/admins/"
|
||||||
|
end
|
||||||
|
|
||||||
def evaluate
|
def evaluate
|
||||||
names = []
|
names = []
|
||||||
data = []
|
data = []
|
||||||
|
@ -63,15 +142,20 @@ class Admins::DashboardsController < Admins::BaseController
|
||||||
Time.now.beginning_of_day..Time.now.end_of_day
|
Time.now.beginning_of_day..Time.now.end_of_day
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_week
|
def pre_7_days
|
||||||
7.days.ago.end_of_day..Time.now.end_of_day
|
7.days.ago.end_of_day..Time.now.end_of_day
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def current_week
|
||||||
|
Time.now.beginning_of_week..Time.now.end_of_day
|
||||||
|
end
|
||||||
|
|
||||||
def current_month
|
def current_month
|
||||||
30.days.ago.end_of_day..Time.now.end_of_day
|
30.days.ago.end_of_day..Time.now.end_of_day
|
||||||
end
|
end
|
||||||
|
|
||||||
def pre_week
|
def pre_week
|
||||||
14.days.ago.end_of_day..7.days.ago.end_of_day
|
# 14.days.ago.end_of_day..7.days.ago.end_of_day
|
||||||
|
Time.now.prev_week..Time.now.prev_week.end_of_week
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::EduSettingsController < Admins::BaseController
|
class Admins::EduSettingsController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :find_setting, only: [:edit,:update, :destroy]
|
before_action :find_setting, only: [:edit,:update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::FaqsController < Admins::BaseController
|
class Admins::FaqsController < Admins::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_faq, only: [:edit,:update, :destroy]
|
before_action :find_faq, only: [:edit,:update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::FeedbacksController < Admins::BaseController
|
class Admins::FeedbacksController < Admins::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
class Admins::GlccPrCheckController < Admins::BaseController
|
||||||
|
before_action :require_glcc_admin
|
||||||
|
|
||||||
|
def index
|
||||||
|
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||||
|
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||||
|
examine_materials = Admins::GlccExamineMaterial.call(params)
|
||||||
|
@examine_materials = paginate examine_materials.includes(:glcc_student)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_mail
|
||||||
|
year = if params[:date].present?
|
||||||
|
params[:date][:year]
|
||||||
|
end
|
||||||
|
if year.nil?
|
||||||
|
return redirect_to admins_glcc_pr_check_index_path
|
||||||
|
flash[:error] = "时间不能为空"
|
||||||
|
end
|
||||||
|
if params[:term].blank?
|
||||||
|
return redirect_to admins_glcc_pr_check_index_path
|
||||||
|
flash[:error] = "考核选项不能为空"
|
||||||
|
end
|
||||||
|
|
||||||
|
examine_materials = GlccMediumTermExamineMaterial.where(\
|
||||||
|
term: params[:term],
|
||||||
|
created_on: [Time.now.change(year:year).beginning_of_year .. Time.now.change(year:year).end_of_year]
|
||||||
|
)
|
||||||
|
examine_materials.map{ |e|
|
||||||
|
e.send_mail
|
||||||
|
}
|
||||||
|
flash[:danger] = "#{year} 年 #{params[:term].to_i == 1 ? "中期考核": "结项考核"} PR 检测邮件已全部发送完毕,一共#{examine_materials.count}封邮件"
|
||||||
|
redirect_to admins_glcc_pr_check_index_path
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,38 @@
|
||||||
|
class Admins::IdentityVerificationsController < Admins::BaseController
|
||||||
|
before_action :require_business
|
||||||
|
before_action :finder_identity_verification, except: [:index]
|
||||||
|
def index
|
||||||
|
params[:sort_by] = params[:sort_by].presence || 'created_at'
|
||||||
|
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||||
|
identity_verifications = Admins::IdentityVerificationQuery.call(params)
|
||||||
|
@identity_verifications = paginate identity_verifications.preload(:user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if update_params[:state] == "已拒绝" && update_params[:description].blank?
|
||||||
|
flash[:danger] = '拒绝理由不能为空'
|
||||||
|
render 'edit'
|
||||||
|
else
|
||||||
|
UserAction.create(action_id: @identity_verification.id, action_type: "UpdateIdentityVerifications", user_id: current_user.id, :ip => request.remote_ip, data_bank: @identity_verification.attributes.to_json)
|
||||||
|
@identity_verification.update(update_params)
|
||||||
|
redirect_to admins_identity_verifications_path
|
||||||
|
flash[:success] = "更新成功"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def finder_identity_verification
|
||||||
|
@identity_verification = IdentityVerification.find(params[:id])
|
||||||
|
@user = @identity_verification.user
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_params
|
||||||
|
params.require(:identity_verification).permit(:state, :description)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,30 @@
|
||||||
|
class Admins::IssuesRankController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
|
||||||
|
def index
|
||||||
|
@statistics = DailyProjectStatistic.where('date >= ? AND date <= ?', begin_date, end_date)
|
||||||
|
@statistics = @statistics.group(:project_id).joins(:project).select("project_id,
|
||||||
|
sum(issues) as issues,
|
||||||
|
sum(closed_issues) as closed_issues,
|
||||||
|
projects.issues_count as issues_count")
|
||||||
|
@statistics = @statistics.order("#{sort_by} #{sort_direction}").limit(50)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def begin_date
|
||||||
|
params.fetch(:begin_date, (Date.yesterday-7.days).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_date
|
||||||
|
params.fetch(:end_date, Date.yesterday.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_by
|
||||||
|
DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "issues")) ? params.fetch(:sort_by, "issues") : "issues"
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_direction
|
||||||
|
%w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::LaboratoriesController < Admins::BaseController
|
class Admins::LaboratoriesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
def index
|
def index
|
||||||
default_sort('id', 'desc')
|
default_sort('id', 'desc')
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,6 @@ class Admins::LaboratorySettingsController < Admins::BaseController
|
||||||
params.permit(:identifier, :name,
|
params.permit(:identifier, :name,
|
||||||
:nav_logo, :login_logo, :tab_logo, :oj_banner,
|
:nav_logo, :login_logo, :tab_logo, :oj_banner,
|
||||||
:subject_banner, :course_banner, :competition_banner, :moop_cases_banner,
|
:subject_banner, :course_banner, :competition_banner, :moop_cases_banner,
|
||||||
:footer, navbar: %i[name link hidden])
|
:footer, navbar: %i[name link hidden index])
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::MessageTemplatesController < Admins::BaseController
|
class Admins::MessageTemplatesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :get_template, only: [:edit, :update, :destroy]
|
before_action :get_template, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -7,12 +8,12 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@message_template = MessageTemplate.new
|
@message_template = MessageTemplate::CustomTip.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@message_template = MessageTemplate::CustomTip.new(message_template_params)
|
@message_template = MessageTemplate::CustomTip.new
|
||||||
@message_template.type = "MessageTemplate::CustomTip"
|
@message_template.attributes = message_template_params
|
||||||
if @message_template.save!
|
if @message_template.save!
|
||||||
redirect_to admins_message_templates_path
|
redirect_to admins_message_templates_path
|
||||||
flash[:success] = "创建消息模板成功"
|
flash[:success] = "创建消息模板成功"
|
||||||
|
@ -47,9 +48,7 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
||||||
|
|
||||||
private
|
private
|
||||||
def message_template_params
|
def message_template_params
|
||||||
# type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
|
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
|
||||||
# params.require(type.split("::").join("_").underscore.to_sym).permit!
|
|
||||||
params.require(:message_template).permit!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_template
|
def get_template
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
class Admins::NpsController < Admins::BaseController
|
class Admins::NpsController < Admins::BaseController
|
||||||
|
before_action :require_business
|
||||||
def index
|
def index
|
||||||
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
||||||
@user_nps = UserNp.joins(:user).order(created_at: :desc)
|
@user_nps = UserNp.order(created_at: :desc)
|
||||||
keyword = params[:keyword].to_s.strip.presence
|
keyword = params[:keyword].to_s.strip.presence
|
||||||
if keyword
|
if keyword
|
||||||
sql = 'CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword OR users.login LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword'
|
sql = 'CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword OR users.login LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword'
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::OrganizationsController < Admins::BaseController
|
class Admins::OrganizationsController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :finder_org, except: [:index]
|
before_action :finder_org, except: [:index]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -9,12 +10,29 @@ class Admins::OrganizationsController < Admins::BaseController
|
||||||
@orgs = paginate orgs
|
@orgs = paginate orgs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def open_cla
|
||||||
|
@org.open_cla!
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def close_cla
|
||||||
|
if @org.cla.nil?
|
||||||
|
@org.close_cla!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error(' 该组织已创建CLA 不允许关闭')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@org.destroy!
|
@org.destroy!
|
||||||
Admins::DeleteOrganizationService.call(@org.login)
|
Admins::DeleteOrganizationService.call(@org.login)
|
||||||
|
UserAction.create(action_id: @org.id, action_type: "DestroyOrganization", user_id: current_user.id, :ip => request.remote_ip, data_bank: @org.attributes.to_json)
|
||||||
render_delete_success
|
render_delete_success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
class Admins::PageThemesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
before_action :finder_page_theme, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
|
def index
|
||||||
|
params[:sort_by] = params[:sort_by].presence || 'created_at'
|
||||||
|
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||||
|
|
||||||
|
page_themes = Admins::PageThemesQuery.call(params)
|
||||||
|
|
||||||
|
@page_themes = paginate page_themes
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@page_theme = PageTheme.new theme_params
|
||||||
|
if @page_theme.save
|
||||||
|
save_image_file(params[:image])
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:success] = "新增主题成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:danger] = "新增主题失败: #{@page_theme.errors.messages.values.flatten.join(',')}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if PageTheme.where(language_frame: @page_theme.language_frame).count <= 1
|
||||||
|
flash[:danger] = "删除主题失败,必须存在一个主题"
|
||||||
|
return redirect_to admins_page_themes_path
|
||||||
|
end
|
||||||
|
|
||||||
|
if @page_theme.destroy
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:success] = "删除主题成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:danger] = "删除主题失败"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@page_theme = PageTheme.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@page_theme.attributes = theme_params
|
||||||
|
if @page_theme.save
|
||||||
|
save_image_file(params[:image])
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:success] = "更新成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_page_themes_path
|
||||||
|
flash[:danger] = "更新失败"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def finder_page_theme
|
||||||
|
@page_theme = PageTheme.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def theme_params
|
||||||
|
params.require(:page_theme).permit(:language_frame, :name, :cate, :image_url, :clone_url, :order_index)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_image_file(file)
|
||||||
|
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
|
||||||
|
file_path = Util::FileManage.source_disk_filename(@page_theme, "image")
|
||||||
|
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
|
||||||
|
Util.write_file(file, file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::ProjectCategoriesController < Admins::BaseController
|
class Admins::ProjectCategoriesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :get_category, only: [:edit,:update, :destroy]
|
before_action :get_category, only: [:edit,:update, :destroy]
|
||||||
before_action :validate_names, only: [:create, :update]
|
before_action :validate_names, only: [:create, :update]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::ProjectIgnoresController < Admins::BaseController
|
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
||||||
# before_action :validate_params, only: [:create, :update]
|
# before_action :validate_params, only: [:create, :update]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::ProjectLanguagesController < Admins::BaseController
|
class Admins::ProjectLanguagesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :get_language, only: [:edit,:update, :destroy]
|
before_action :get_language, only: [:edit,:update, :destroy]
|
||||||
before_action :validate_names, only: [:create, :update]
|
before_action :validate_names, only: [:create, :update]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::ProjectLicensesController < Admins::BaseController
|
class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
||||||
# before_action :validate_params, only: [:create, :update]
|
# before_action :validate_params, only: [:create, :update]
|
||||||
|
|
||||||
|
@ -6,7 +7,7 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||||
q = License.ransack(name_cont: params[:search])
|
q = License.ransack(name_cont: params[:search])
|
||||||
project_licenses = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
project_licenses = q.result(distinct: true).reorder("#{sort_by} #{sort_direction}")
|
||||||
@project_licenses = paginate(project_licenses)
|
@project_licenses = paginate(project_licenses)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def license_params
|
def license_params
|
||||||
params.require(:license).permit(:name,:content)
|
params.require(:license).permit(:name,:content,:position)
|
||||||
end
|
end
|
||||||
|
|
||||||
# def validate_params
|
# def validate_params
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
class Admins::ProjectsController < Admins::BaseController
|
class Admins::ProjectsController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :find_project, only: [:edit, :update]
|
before_action :find_project, only: [:edit, :update]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
|
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
|
||||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||||
search = params[:search].to_s.strip
|
search = params[:search].to_s.strip
|
||||||
projects = Project.where("name like ?", "%#{search}%").order("#{sort_by} #{sort_direction}")
|
projects = Project.where("id = ? OR name like ? OR identifier LIKE ?", search, "%#{search}%", "%#{search}%").order("#{sort_by} #{sort_direction}")
|
||||||
|
case params[:category]
|
||||||
|
when 'public'
|
||||||
|
projects = projects.where(is_public: true)
|
||||||
|
when 'private'
|
||||||
|
projects = projects.where(is_public: false)
|
||||||
|
when 'fork'
|
||||||
|
projects = projects.where.not(forked_from_project_id: nil)
|
||||||
|
when 'original'
|
||||||
|
projects = projects.where(forked_from_project_id: nil, project_type: 'common')
|
||||||
|
end
|
||||||
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
|
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,9 +43,14 @@ class Admins::ProjectsController < Admins::BaseController
|
||||||
def destroy
|
def destroy
|
||||||
project = Project.find_by!(id: params[:id])
|
project = Project.find_by!(id: params[:id])
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
Gitea::Repository::DeleteService.new(project.owner, project.identifier).call
|
close_fork_pull_requests_by(project)
|
||||||
|
Gitea::Repository::DeleteService.new(project.owner, project.identifier, current_user.gitea_token).call
|
||||||
project.destroy!
|
project.destroy!
|
||||||
|
project.forked_projects.update_all(forked_from_project_id: nil)
|
||||||
|
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||||
|
project.project_category.decrement!(:private_projects_count, 1) if project.project_category.present? && !project.is_public
|
||||||
# render_delete_success
|
# render_delete_success
|
||||||
|
UserAction.create(action_id: project.id, action_type: "DestroyProject", user_id: current_user.id, :ip => request.remote_ip, data_bank: project.attributes.to_json)
|
||||||
redirect_to admins_projects_path
|
redirect_to admins_projects_path
|
||||||
flash[:success] = "删除成功"
|
flash[:success] = "删除成功"
|
||||||
end
|
end
|
||||||
|
@ -51,4 +67,19 @@ class Admins::ProjectsController < Admins::BaseController
|
||||||
def project_update_params
|
def project_update_params
|
||||||
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
|
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def close_fork_pull_requests_by(project)
|
||||||
|
open_pull_requests = PullRequest.where(fork_project_id: project.id)
|
||||||
|
if open_pull_requests.present?
|
||||||
|
open_pull_requests.each do |pull_request|
|
||||||
|
closed = PullRequests::CloseService.call(pull_request&.project.owner, pull_request&.project.repository, pull_request, current_user)
|
||||||
|
if closed === true
|
||||||
|
pull_request.project_trends.create!(user: current_user, project: pull_request&.project,action_type: ProjectTrend::CLOSE)
|
||||||
|
# 合并请求下issue处理为关闭
|
||||||
|
pull_request.issue&.update_attributes!({status_id:5})
|
||||||
|
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -1,16 +1,60 @@
|
||||||
class Admins::ProjectsRankController < Admins::BaseController
|
class Admins::ProjectsRankController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@rank_date = rank_date
|
@statistics = DailyProjectStatistic.where("date >= ? AND date <= ?", begin_date, end_date)
|
||||||
deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
|
@statistics = @statistics.group(:project_id).select("project_id,
|
||||||
$redis_cache.zrem("v2-project-rank-#{rank_date}", deleted_data) unless deleted_data.blank?
|
sum(score) as score,
|
||||||
@date_rank = $redis_cache.zrevrange("v2-project-rank-#{rank_date}", 0, -1, withscores: true)
|
sum(visits) as visits,
|
||||||
|
sum(watchers) as watchers,
|
||||||
|
sum(praises) as praises,
|
||||||
|
sum(forks) as forks,
|
||||||
|
sum(issues) as issues,
|
||||||
|
sum(pullrequests) as pullrequests,
|
||||||
|
sum(commits) as commits").includes(:project)
|
||||||
|
@statistics = paginate @statistics.order("#{sort_by} #{sort_direction}")
|
||||||
|
export_excel(@statistics.limit(50))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def rank_date
|
def begin_date
|
||||||
params.fetch(:date, Date.today.to_s)
|
params.fetch(:begin_date, (Date.yesterday-7.days).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_date
|
||||||
|
params.fetch(:end_date, Date.yesterday.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_by
|
||||||
|
DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "score")) ? params.fetch(:sort_by, "score") : "score"
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_direction
|
||||||
|
%w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc"
|
||||||
|
end
|
||||||
|
|
||||||
|
def export_excel(data)
|
||||||
|
book = Spreadsheet::Workbook.new
|
||||||
|
sheet = book.create_worksheet :name => "项目活跃度排行"
|
||||||
|
sheet.row(0).concat %w(排名 项目全称 项目地址 项目分类 首次创建时间 外部迁移/独立创建 得分 访问数 关注数 点赞数 fork数 疑修数 合并请求数 提交数)
|
||||||
|
data.each_with_index do |d, index|
|
||||||
|
sheet[index+1,0] = index+1
|
||||||
|
sheet[index+1,1] = "#{d&.project&.owner&.real_name}/#{d&.project&.name}"
|
||||||
|
sheet[index+1,2] = "#{Rails.application.config_for(:configuration)['platform_url']}/#{d&.project&.owner&.login}/#{d&.project&.identifier}"
|
||||||
|
sheet[index+1,3] = d&.project&.project_category&.name
|
||||||
|
sheet[index+1,4] = d&.project&.created_on.present? ? d&.project&.created_on.strftime("%Y-%m-%d %H:%M:%S") : ""
|
||||||
|
sheet[index+1,5] = d&.project&.common? ? "独立创建" : "外部迁移"
|
||||||
|
sheet[index+1,6] = d.score
|
||||||
|
sheet[index+1,7] = d.visits
|
||||||
|
sheet[index+1,8] = d.watchers
|
||||||
|
sheet[index+1,9] = d.praises
|
||||||
|
sheet[index+1,10] = d.forks
|
||||||
|
sheet[index+1,11] = d.issues
|
||||||
|
sheet[index+1,12] = d.pullrequests
|
||||||
|
sheet[index+1,13] = d.commits
|
||||||
|
end
|
||||||
|
book.write "#{Rails.root}/public/项目活跃度排行.xls"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::ReversedKeywordsController < Admins::BaseController
|
class Admins::ReversedKeywordsController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :get_keyword, only: [:edit,:update, :destroy]
|
before_action :get_keyword, only: [:edit,:update, :destroy]
|
||||||
# before_action :validate_identifer, only: [:create, :update]
|
# before_action :validate_identifer, only: [:create, :update]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
class Admins::SitePagesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
before_action :finder_site_page, except: [:index]
|
||||||
|
|
||||||
|
def index
|
||||||
|
params[:sort_by] = params[:sort_by].presence || 'created_at'
|
||||||
|
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||||
|
|
||||||
|
pages = Admins::SitePagesQuery.call(params)
|
||||||
|
|
||||||
|
@site_pages = paginate pages.preload(:user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @site_page.destroy
|
||||||
|
redirect_to admins_site_pages_path
|
||||||
|
flash[:success] = "删除站点成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_site_pages_path
|
||||||
|
flash[:danger] = "删除站点失败"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if update_params[:state] == "false" && update_params[:state_description].blank?
|
||||||
|
flash[:danger] = '关闭站点理由不能为空'
|
||||||
|
else
|
||||||
|
@site_page.update(update_params)
|
||||||
|
flash[:success] = '保存成功'
|
||||||
|
end
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def finder_site_page
|
||||||
|
@site_page = Page.find(params[:id])
|
||||||
|
@user = @site_page.user
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_params
|
||||||
|
params.require(:page).permit(:state, :state_description)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::SitesController < Admins::BaseController
|
class Admins::SitesController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :find_site, only: [:edit,:update, :destroy]
|
before_action :find_site, only: [:edit,:update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::SystemNotificationsController < Admins::BaseController
|
class Admins::SystemNotificationsController < Admins::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :get_notification, only: [:history, :edit,:update, :destroy]
|
before_action :get_notification, only: [:history, :edit,:update, :destroy]
|
||||||
# before_action :validate_identifer, only: [:create, :update]
|
# before_action :validate_identifer, only: [:create, :update]
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
|
||||||
@notification = SystemNotification.new(notification_params)
|
@notification = SystemNotification.new(notification_params)
|
||||||
if @notification.save
|
if @notification.save
|
||||||
redirect_to admins_system_notifications_path
|
redirect_to admins_system_notifications_path
|
||||||
flash[:success] = '系统消息创建成功'
|
flash[:success] = '系统公告创建成功'
|
||||||
else
|
else
|
||||||
redirect_to admins_system_notifications_path
|
redirect_to admins_system_notifications_path
|
||||||
flash[:danger] = @notification.errors.full_messages.join(",")
|
flash[:danger] = @notification.errors.full_messages.join(",")
|
||||||
|
@ -37,7 +38,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
|
||||||
if @notification.update_attributes(notification_params)
|
if @notification.update_attributes(notification_params)
|
||||||
format.html do
|
format.html do
|
||||||
redirect_to admins_system_notifications_path
|
redirect_to admins_system_notifications_path
|
||||||
flash[:success] = '系统消息更新成功'
|
flash[:success] = '系统公告更新成功'
|
||||||
end
|
end
|
||||||
format.js {render_ok}
|
format.js {render_ok}
|
||||||
else
|
else
|
||||||
|
@ -53,10 +54,10 @@ class Admins::SystemNotificationsController < Admins::BaseController
|
||||||
def destroy
|
def destroy
|
||||||
if @notification.destroy
|
if @notification.destroy
|
||||||
redirect_to admins_system_notifications_path
|
redirect_to admins_system_notifications_path
|
||||||
flash[:success] = "系统消息删除成功"
|
flash[:success] = "系统公告删除成功"
|
||||||
else
|
else
|
||||||
redirect_to admins_system_notifications_path
|
redirect_to admins_system_notifications_path
|
||||||
flash[:danger] = "系统消息删除失败"
|
flash[:danger] = "系统公告删除失败"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::ActivityForumsController < Admins::Topic::BaseController
|
class Admins::Topic::ActivityForumsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_activity_forum, only: [:edit, :update, :destroy]
|
before_action :find_activity_forum, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::CardsController < Admins::Topic::BaseController
|
class Admins::Topic::CardsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_card, only: [:edit, :update, :destroy]
|
before_action :find_card, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::CooperatorsController < Admins::Topic::BaseController
|
class Admins::Topic::CooperatorsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_cooperator, only: [:edit, :update, :destroy]
|
before_action :find_cooperator, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::ExcellentProjectsController < Admins::Topic::BaseController
|
class Admins::Topic::ExcellentProjectsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_excellent_project, only: [:edit, :update, :destroy]
|
before_action :find_excellent_project, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::ExperienceForumsController < Admins::Topic::BaseController
|
class Admins::Topic::ExperienceForumsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_experience_forum, only: [:edit, :update, :destroy]
|
before_action :find_experience_forum, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
|
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_glcc_admin
|
||||||
before_action :find_glcc, only: [:edit, :update, :destroy]
|
before_action :find_glcc, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::Topic::PinnedForumsController < Admins::Topic::BaseController
|
class Admins::Topic::PinnedForumsController < Admins::Topic::BaseController
|
||||||
|
before_action :require_business
|
||||||
before_action :find_pinned_forum, only: [:edit, :update, :destroy]
|
before_action :find_pinned_forum, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
class Admins::UserActionsController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
|
||||||
|
def index
|
||||||
|
@user_actions = UserAction.order(created_at: :desc)
|
||||||
|
@user_actions = @user_actions.where(action_type: params[:action_type]) if params[:action_type].present?
|
||||||
|
keyword = params[:keyword].to_s.strip.presence
|
||||||
|
if keyword
|
||||||
|
sql = 'login LIKE :keyword OR phone LIKE :keyword OR email LIKE :keyword'
|
||||||
|
@user_actions = @user_actions.where(sql, keyword: "%#{keyword}%")
|
||||||
|
end
|
||||||
|
@user_actions = paginate @user_actions
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::UsersController < Admins::BaseController
|
class Admins::UsersController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
before_action :finder_user, except: [:index]
|
before_action :finder_user, except: [:index]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -25,15 +26,36 @@ class Admins::UsersController < Admins::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@user.destroy!
|
UserAction.create(action_id: @user.id, action_type: "DestroyUser", user_id: current_user.id, :ip => request.remote_ip, data_bank: @user.attributes.to_json)
|
||||||
Gitea::User::DeleteService.call(@user.login)
|
# org_ids = TeamUser.where(user_id: @user.id).pluck(:organization_id) | OrganizationUser.where(user_id: @user.id).pluck(:organization_id)
|
||||||
|
# organizations = Organization.where(id: org_ids)
|
||||||
|
# organizations.each do |org|
|
||||||
|
# # org.team_users.joins(:team).where(user_id: @user.id, teams: {authorize: %w(owner)})
|
||||||
|
# owner_count = org.team_users.joins(:team).where(teams: {authorize: %w(owner)}).count
|
||||||
|
# # 多个owner时,仅将用户从组织移除, 一个时直接删除
|
||||||
|
# if owner_count > 1
|
||||||
|
# org.team_users.joins(:team).where(user_id: @user.id, teams: {authorize: %w(owner)}).destroy_all
|
||||||
|
# org.organization_users.where(user_id: @user.id, organization_id: org.id).destroy_all
|
||||||
|
# else
|
||||||
|
# org.destroy
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# @user.destroy!
|
||||||
|
# Gitea::User::DeleteService.call(@user.login, true)
|
||||||
|
#
|
||||||
|
# render_delete_success
|
||||||
|
|
||||||
|
@result_object = Api::V1::Users::DeleteUserService.call(@user)
|
||||||
|
if @result_object
|
||||||
render_delete_success
|
render_delete_success
|
||||||
|
else
|
||||||
|
render_js_error('删除失败!')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def lock
|
def lock
|
||||||
@user.lock!
|
@user.lock!
|
||||||
|
UserAction.create(action_id: @user.id, action_type: "LockUser", user_id: current_user.id, :ip => request.remote_ip)
|
||||||
render_ok
|
render_ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -72,6 +94,6 @@ class Admins::UsersController < Admins::BaseController
|
||||||
def update_params
|
def update_params
|
||||||
params.require(:user).permit(%i[lastname nickname gender technical_title is_shixun_marker
|
params.require(:user).permit(%i[lastname nickname gender technical_title is_shixun_marker
|
||||||
mail phone location location_city school_id department_id admin
|
mail phone location location_city school_id department_id admin
|
||||||
password login])
|
password login website_permission business glcc_admin])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Admins::UsersRankController < Admins::BaseController
|
class Admins::UsersRankController < Admins::BaseController
|
||||||
|
before_action :require_admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@rank_date = rank_date
|
@rank_date = rank_date
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
class Api::Pm::ActionRunsController < Api::Pm::BaseController
|
||||||
|
before_action :require_login
|
||||||
|
|
||||||
|
def index
|
||||||
|
tip_exception('请输入workflows') if params[:workflows].blank?
|
||||||
|
@owner = Owner.find_by(login: params[:owner_id].to_s) || Owner.find_by(id: params[:owner_id].to_s)
|
||||||
|
tip_exception('组织未找到') if @owner.blank?
|
||||||
|
action_runs = Gitea::ActionRun.where(owner_id: @owner.gitea_uid)
|
||||||
|
group_data = action_runs.where(workflow_id: params[:workflows].to_s.split(",")).where(status: [1,2]).group(:workflow_id, :status).count
|
||||||
|
@result = []
|
||||||
|
params[:workflows].to_s.split(",").each do |file|
|
||||||
|
last_action_run = action_runs.where(workflow_id: file).order(updated: :desc).first
|
||||||
|
last_action_run_json = last_action_run.present? ? {
|
||||||
|
id: last_action_run.id,
|
||||||
|
schedule: last_action_run.schedule_id > 0,
|
||||||
|
title: last_action_run.title,
|
||||||
|
index: last_action_run.index,
|
||||||
|
status: last_action_run.status,
|
||||||
|
started: last_action_run.started,
|
||||||
|
stopped: last_action_run.stopped,
|
||||||
|
length: last_action_run.stopped - last_action_run.started,
|
||||||
|
created: last_action_run.created,
|
||||||
|
updated: last_action_run.updated,
|
||||||
|
} : {}
|
||||||
|
|
||||||
|
total = 0
|
||||||
|
success = 0
|
||||||
|
failure = 0
|
||||||
|
group_data.each do |k,v|
|
||||||
|
total += v if k[0] == file
|
||||||
|
success += v if k[0] == file && k[1] == 1
|
||||||
|
failure += v if k[0] == file && k[1] == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
@result << {
|
||||||
|
name: file,
|
||||||
|
total: total,
|
||||||
|
success: success,
|
||||||
|
failure: failure
|
||||||
|
}.merge(last_action_run_json)
|
||||||
|
end
|
||||||
|
render :json => {data: @result}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,60 @@
|
||||||
|
class Api::Pm::BaseController < ApplicationController
|
||||||
|
|
||||||
|
include Api::ProjectHelper
|
||||||
|
include Api::UserHelper
|
||||||
|
include Api::PullHelper
|
||||||
|
|
||||||
|
# before_action :doorkeeper_authorize!
|
||||||
|
# skip_before_action :user_setup
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def kaminary_select_paginate(relation)
|
||||||
|
limit = params[:limit] || params[:per_page]
|
||||||
|
limit = (limit.to_i.zero? || limit.to_i > 200) ? 200 : limit.to_i
|
||||||
|
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
|
||||||
|
|
||||||
|
relation.page(page).per(limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def limit
|
||||||
|
params.fetch(:limit, 15)
|
||||||
|
end
|
||||||
|
|
||||||
|
def page
|
||||||
|
params.fetch(:page, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = Project.find_by_id(params[:project_id]) || Project.new(id: 0, user_id: 0, name: 'pm_mm', identifier: 'pm_mm', is_public:true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_issue
|
||||||
|
# return render_parameter_missing if params[:pm_project_id].blank?
|
||||||
|
@issue = Issue.issue_issue.find_by_id(params[:issue_id])
|
||||||
|
render_not_found('疑修不存在!') if @issue.blank?
|
||||||
|
end
|
||||||
|
# 具有对仓库的管理权限
|
||||||
|
def require_manager_above
|
||||||
|
@project = load_project
|
||||||
|
return render_forbidden if !current_user.admin? && !@project.manager?(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
# 具有对仓库的操作权限
|
||||||
|
def require_operate_above
|
||||||
|
@project = load_project
|
||||||
|
return render_forbidden if !current_user.admin? && !@project.operator?(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
# 具有仓库的操作权限或者fork仓库的操作权限
|
||||||
|
def require_operate_above_or_fork_project
|
||||||
|
@project = load_project
|
||||||
|
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||||
|
end
|
||||||
|
|
||||||
|
# 具有对仓库的访问权限
|
||||||
|
def require_public_and_member_above
|
||||||
|
@project = load_project
|
||||||
|
return render_forbidden if !@project.is_public && !current_user.admin? && !@project.member?(current_user)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,138 @@
|
||||||
|
class Api::Pm::DashboardsController < Api::Pm::BaseController
|
||||||
|
before_action :require_login
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
def todo
|
||||||
|
return render_error('请输入正确的pm_project_ids.') if params[:pm_project_ids].blank?
|
||||||
|
pm_project_ids = params[:pm_project_ids].split(",") rescue []
|
||||||
|
date = params[:date].present? ? params[:date].to_date : Date.today rescue Date.today
|
||||||
|
@issues = Issue.where("start_date <= ? and due_date >= ?", date, date)
|
||||||
|
@issues = @issues.where(pm_project_id: pm_project_ids).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'})
|
||||||
|
@issues = @issues.where.not(status_id: 5)
|
||||||
|
@issues = kaminari_paginate(@issues.distinct.pm_includes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_issues
|
||||||
|
return render_error('请输入正确的pm_project_ids.') if params[:pm_project_ids].blank?
|
||||||
|
return render_error('请输入正确的pm_issue_types.') if params[:pm_issue_types].blank?
|
||||||
|
pm_project_ids = params[:pm_project_ids].split(",") rescue []
|
||||||
|
pm_issue_types = params[:pm_issue_types].split(",") rescue []
|
||||||
|
@all_issues = Issue.where(pm_project_id: pm_project_ids, pm_issue_type: pm_issue_types)
|
||||||
|
@issues = @all_issues.joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'})
|
||||||
|
@issues = @issues.where.not(status_id: 5) if params[:category] == "opened"
|
||||||
|
|
||||||
|
@issues = kaminari_paginate(@issues.distinct.pm_includes)
|
||||||
|
@my_assign_requirements_count = @all_issues.where(pm_issue_type: 1).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'}).size
|
||||||
|
@my_assign_tasks_count = @all_issues.where(pm_issue_type: 2).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'}).size
|
||||||
|
@my_assign_bugs_count = @all_issues.where(pm_issue_type: 3).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'}).size
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_pm_projects
|
||||||
|
return render_error('请输入正确的pm_project_id.') if params[:pm_project_id].blank?
|
||||||
|
@all_issues = Issue.where(pm_project_id: params[:pm_project_id])
|
||||||
|
time_now = Time.now
|
||||||
|
@last_week_create_issues_count = @all_issues.where("created_on > ? and created_on < ?", time_now - 7.days, time_now).size
|
||||||
|
@before_last_week_create_issue_count = @all_issues.where("created_on > ? and created_on < ?", time_now - 14.days, time_now - 7.days).size
|
||||||
|
@compare_last_week_create_issues = @before_last_week_create_issue_count.zero? ? 0 :(@last_week_create_issues_count - @before_last_week_create_issue_count).to_f / @before_last_week_create_issue_count rescue 0
|
||||||
|
@last_week_close_issues_count = @all_issues.where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 7.days, time_now).size
|
||||||
|
@before_last_week_close_issue_count = @all_issues.where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 14.days, time_now - 7.days).size
|
||||||
|
@compare_last_week_close_issues = @before_last_week_close_issue_count.zero? ? 0 :(@last_week_close_issues_count - @before_last_week_close_issue_count).to_f / @before_last_week_close_issue_count rescue 0
|
||||||
|
@all_requirement_issues_count = @all_issues.where(pm_issue_type: 1).size
|
||||||
|
@open_requirement_issues_count = @all_issues.where(pm_issue_type: 1).where.not(status_id: 5).size
|
||||||
|
@last_week_close_requirement_issues_count = @all_issues.where(pm_issue_type: 1).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 7.days, time_now).size
|
||||||
|
@last_month_close_requirement_issues_count = @all_issues.where(pm_issue_type: 1).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 30.days, time_now).size
|
||||||
|
@all_task_issues_count = @all_issues.where(pm_issue_type: 2).size
|
||||||
|
@open_task_issues_count = @all_issues.where(pm_issue_type: 2).where.not(status_id: 5).size
|
||||||
|
@last_week_close_tast_issues_count = @all_issues.where(pm_issue_type: 2).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 7.days, time_now).size
|
||||||
|
@last_month_close_task_issues_count = @all_issues.where(pm_issue_type: 2).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 30.days, time_now).size
|
||||||
|
@all_bug_issues_count = @all_issues.where(pm_issue_type: 3).size
|
||||||
|
@open_bug_issues_count = @all_issues.where(pm_issue_type: 3).where.not(status_id: 5).size
|
||||||
|
@last_week_close_bug_issues_count = @all_issues.where(pm_issue_type: 3).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 7.days, time_now).size
|
||||||
|
@last_month_close_bug_issues_count = @all_issues.where(pm_issue_type: 3).where(status_id: 5).where("updated_on > ? and updated_on < ?", time_now - 30.days, time_now).size
|
||||||
|
|
||||||
|
|
||||||
|
@requirement_close_trend = [[],[]]
|
||||||
|
@task_close_trend = [[],[]]
|
||||||
|
@bug_close_trend = [[],[]]
|
||||||
|
((time_now-29.days).to_date..time_now.to_date).to_a.each do |i|
|
||||||
|
@requirement_close_trend[0] << i.strftime("%Y.%m.%d")
|
||||||
|
@task_close_trend[0] << i.strftime("%Y.%m.%d")
|
||||||
|
@bug_close_trend[0] << i.strftime("%Y.%m.%d")
|
||||||
|
@requirement_close_trend[1] << @all_issues.where(pm_issue_type: 1, status_id: 5).where("DATE(updated_on) = ?", i).size
|
||||||
|
@task_close_trend[1] << @all_issues.where(pm_issue_type: 2, status_id: 5).where("DATE(updated_on) = ?", i).size
|
||||||
|
@bug_close_trend[1] << @all_issues.where(pm_issue_type: 3, status_id: 5).where("DATE(updated_on) = ?", i).size
|
||||||
|
end
|
||||||
|
@close_trend = {requirement: @requirement_close_trend, task: @task_close_trend, bug: @bug_close_trend}
|
||||||
|
|
||||||
|
render_ok(data: {
|
||||||
|
last_week_close_issues_count: @last_week_close_issues_count,
|
||||||
|
before_last_week_close_issue_count: @before_last_week_close_issue_count,
|
||||||
|
compare_last_week_close_issues: @compare_last_week_close_issues,
|
||||||
|
last_week_create_issues_count: @last_week_create_issues_count,
|
||||||
|
before_last_week_create_issue_count: @before_last_week_create_issue_count,
|
||||||
|
compare_last_week_create_issues: @compare_last_week_create_issues,
|
||||||
|
all_requirement_issues_count: @all_requirement_issues_count,
|
||||||
|
open_requirement_issues_count: @open_requirement_issues_count,
|
||||||
|
last_week_close_requirement_issues_count: @last_week_close_requirement_issues_count,
|
||||||
|
last_month_close_requirement_issues_count: @last_month_close_requirement_issues_count,
|
||||||
|
all_task_issues_count: @all_task_issues_count,
|
||||||
|
open_task_issues_count: @open_task_issues_count,
|
||||||
|
last_week_close_task_issues_count: @last_week_close_tast_issues_count,
|
||||||
|
last_month_close_task_issues_count: @last_month_close_task_issues_count,
|
||||||
|
all_bug_issues_count: @all_bug_issues_count,
|
||||||
|
open_bug_issues_count: @open_bug_issues_count,
|
||||||
|
last_week_close_bug_issues_count: @last_week_close_bug_issues_count,
|
||||||
|
last_month_close_bug_issues_count: @last_month_close_bug_issues_count,
|
||||||
|
close_trend: @close_trend
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_projects
|
||||||
|
return render_error('请输入正确的project_id.') if params[:project_id].blank?
|
||||||
|
|
||||||
|
@project = Project.find_by_id params[:project_id]
|
||||||
|
return render_error('请输入正确的project_id.') unless @project.present?
|
||||||
|
time_now = Time.now
|
||||||
|
|
||||||
|
branch_tag_result = $gitea_hat_client.get_repos_branch_tag_count_by_owner_repo(@project&.owner&.login, @project&.identifier) rescue {}
|
||||||
|
languages_result = $gitea_client.get_repos_languages_by_owner_repo(@project&.owner&.login, @project&.identifier) rescue {}
|
||||||
|
|
||||||
|
@open_pull_requests_count = @project.pull_requests.opening.size
|
||||||
|
@last_week_close_pull_requests_count = @project.pull_requests.where(status: 1).where("updated_at > ? and updated_at < ?", time_now - 7.days, time_now).size
|
||||||
|
@last_month_close_pull_requets_count = @project.pull_requests.where(status: 1).where("updated_at > ? and updated_at < ?", time_now - 30.days, time_now).size
|
||||||
|
|
||||||
|
@commits_count = @project.commit_logs.size
|
||||||
|
@last_week_commits_count = @project.commit_logs.where("created_at > ? and created_at < ?", time_now - 7.days, time_now).size
|
||||||
|
@last_month_commits_count = @project.commit_logs.where("created_at > ? and created_at < ?", time_now - 30.days, time_now).size
|
||||||
|
|
||||||
|
render_ok(data: {
|
||||||
|
branch_count: branch_tag_result["branch_count"].to_i,
|
||||||
|
tag_count: branch_tag_result["tag_count"].to_i,
|
||||||
|
license_name: @project.license&.name,
|
||||||
|
open_pull_requests_count: @open_pull_requests_count,
|
||||||
|
last_week_close_pull_requests_count: @last_week_close_pull_requests_count,
|
||||||
|
last_month_close_pull_requets_count: @last_month_close_pull_requets_count,
|
||||||
|
commits_count: @commits_count,
|
||||||
|
last_week_commits_count: @last_week_commits_count,
|
||||||
|
last_month_commits_count: @last_month_commits_count,
|
||||||
|
language: hash_transform_precentagable(languages_result),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_operate_journals
|
||||||
|
return render_error('请输入正确的pm_project_id.') if params[:pm_project_id].blank?
|
||||||
|
@journals = Journal.operate_journals.joins(:issue).where(issues: {pm_project_id: params[:pm_project_id], pm_issue_type: [1,2,3]})
|
||||||
|
|
||||||
|
@journals = kaminari_paginate(@journals.order(updated_on: :desc))
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def hash_transform_precentagable(hash)
|
||||||
|
total_byte_size = hash.values.sum
|
||||||
|
hash.transform_values { |v|
|
||||||
|
ActionController::Base.helpers
|
||||||
|
.number_to_percentage((v * 100.0 / total_byte_size), precision: 1)
|
||||||
|
}.select{|k,v| v != "0.0%"}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,46 @@
|
||||||
|
class Api::Pm::IssueLinksController < Api::Pm::BaseController
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_issue
|
||||||
|
def index
|
||||||
|
@links = PmLink.where(be_linkable_id: @issue.id,be_linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id,linkable_type: 'Issue'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
begin
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
params[:link_ids].each do |e|
|
||||||
|
@issue.pm_links.find_or_create_by!(be_linkable_type: 'Issue', be_linkable_id: e)
|
||||||
|
tag_issue = Issue.find_by_id(e)
|
||||||
|
next unless tag_issue.present?
|
||||||
|
journal = tag_issue.journals.create!({user_id: current_user.id})
|
||||||
|
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", value: @issue.id.to_s})
|
||||||
|
end
|
||||||
|
journal = @issue.journals.create!({user_id: current_user.id})
|
||||||
|
journal.journal_details.create!({property: "tag_link_issue", prop_key: "#{params[:link_ids].size}", value: params[:link_ids].join(",")})
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
rescue
|
||||||
|
render_error('创建失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
begin
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@links = PmLink.where(be_linkable_id: @issue.id, be_linkable_type: 'Issue', linkable_id: params[:id], linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id, linkable_type: 'Issue', be_linkable_id: params[:id], be_linkable_type: 'Issue'))
|
||||||
|
journal = @issue.journals.create!({user_id: current_user.id})
|
||||||
|
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", old_value: params[:id].to_s})
|
||||||
|
another_issue = Issue.find_by_id(params[:id])
|
||||||
|
if another_issue.present?
|
||||||
|
journal = another_issue.journals.create!({user_id: current_user.id})
|
||||||
|
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", old_value: @issue.id.to_s})
|
||||||
|
end
|
||||||
|
@link = @links.last
|
||||||
|
@link.destroy!
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
rescue
|
||||||
|
render_error('删除失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
class Api::Pm::IssueTagsController < Api::Pm::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
@issue_tags = IssueTag.pm_able
|
||||||
|
if params[:organization_id].present?
|
||||||
|
IssueTag.pm_org_init_data(params[:organization_id]) unless $redis_cache.hget("pm_org_init_issue_tags", params[:organization_id])
|
||||||
|
@issue_tags = @issue_tags.where(organization_id: params[:organization_id])
|
||||||
|
end
|
||||||
|
@issue_tags = @issue_tags.where(pm_project_id: params[:pm_project_id]) if params[:pm_project_id].present?
|
||||||
|
@issue_tags = @issue_tags.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
|
||||||
|
@issue_tags = @issue_tags.reorder("#{tag_sort_by} #{tag_sort_direction}")
|
||||||
|
@issue_tags = kaminari_paginate(@issue_tags)
|
||||||
|
render "api/v1/issues/issue_tags/index"
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
return render_error("请输入正确的OrganizationID") unless Organization.exists?(id: issue_tag_create_params[:organization_id])
|
||||||
|
return render_error("项目标记名称不能为空!") unless issue_tag_create_params[:name].present?
|
||||||
|
@issue_tag = IssueTag.new(issue_tag_create_params.merge!(project_id: 0))
|
||||||
|
if @issue_tag.save!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("创建标记失败!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
before_action :load_issue_tag, only: [:update, :destroy]
|
||||||
|
|
||||||
|
def update
|
||||||
|
@issue_tag.attributes = issue_tag_update_params
|
||||||
|
if @issue_tag.save!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("更新标记失败!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @issue_tag.destroy!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("删除标记失败!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
def tag_sort_by
|
||||||
|
sort_by = params.fetch(:sort_by, "created_at")
|
||||||
|
sort_by = IssueTag.column_names.include?(sort_by) ? sort_by : "created_at"
|
||||||
|
sort_by
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_sort_direction
|
||||||
|
sort_direction = params.fetch(:sort_direction, "desc")&.downcase
|
||||||
|
sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
|
||||||
|
sort_direction
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_tag_create_params
|
||||||
|
params.permit(:name, :description, :color, :pm_project_id, :organization_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_tag_update_params
|
||||||
|
params.permit(:name, :description, :color)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_issue_tag
|
||||||
|
@issue_tag = IssueTag.pm_able.find_by_id(params[:id])
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,376 @@
|
||||||
|
class Api::Pm::IssuesController < Api::Pm::BaseController
|
||||||
|
before_action :require_login, except: [:index]
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_issue, only: %i[show update destroy link_index link_issues parent_issues]
|
||||||
|
before_action :load_issues, only: %i[batch_update batch_destroy]
|
||||||
|
before_action :check_issue_operate_permission, only: %i[update destroy]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@object_result = Api::V1::Issues::ListService.call(@project, query_params, current_user)
|
||||||
|
@total_issues_count = @object_result[:total_issues_count]
|
||||||
|
@opened_issues_count = @object_result[:opened_issues_count]
|
||||||
|
@closed_issues_count = @object_result[:closed_issues_count]
|
||||||
|
@complete_issues_count = @object_result[:complete_issues_count]
|
||||||
|
if params[:only_name].present?
|
||||||
|
@issues = kaminary_select_paginate(
|
||||||
|
@object_result[:data].select(:id, :subject, :project_issues_index, :updated_on, :created_on))
|
||||||
|
else
|
||||||
|
@issues = kaminari_paginate(@object_result[:data])
|
||||||
|
end
|
||||||
|
render 'api/v1/issues/index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_index
|
||||||
|
pm_issue_type = params[:pm_issue_type] || [1, 2, 3]
|
||||||
|
not_join_id = case params[:issue_filter_type]
|
||||||
|
when 'leaf_issue'
|
||||||
|
Issue.where(root_id: @issue.id).pluck(:id)
|
||||||
|
when 'link_issue'
|
||||||
|
@issue.pm_links.pluck(:be_linkable_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
not_join_id << @issue.id
|
||||||
|
object_issues = Issue.where(
|
||||||
|
pm_project_id: params[:pm_project_id],
|
||||||
|
pm_issue_type: pm_issue_type
|
||||||
|
).where.not(id: not_join_id).order(updated_on: :desc)
|
||||||
|
|
||||||
|
object_issues = object_issues.where(root_id: nil, child_count: 0) if params[:issue_filter_type] == 'leaf_issue'
|
||||||
|
@issues = kaminari_paginate(object_issues)
|
||||||
|
render 'api/v1/issues/index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_issues
|
||||||
|
@issues = Issue.where(pm_project_id: params[:pm_project_id])
|
||||||
|
.where.not(id: @issue.id)
|
||||||
|
.where.not(id: Issue.full_children_issues(@issue).map{|i|i.id})
|
||||||
|
@issues = @issues.where(pm_issue_type: params[:pm_issue_type]) if params[:pm_issue_type].present?
|
||||||
|
@issues = @issues.ransack(id_or_project_issues_index_eq: params[:keyword]).result.or(@issues.ransack(subject_or_description_cont: params[:keyword]).result) if params[:keyword].present?
|
||||||
|
@issues = @issues.reorder("#{issue_sort_by} #{issue_sort_direction}")
|
||||||
|
if params[:only_name].present?
|
||||||
|
@issues = kaminary_select_paginate(
|
||||||
|
@issues.select(:id, :subject, :project_issues_index, :updated_on, :created_on))
|
||||||
|
else
|
||||||
|
@issues = @issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
|
||||||
|
@issues = kaminari_paginate(@issues)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@issue.associate_attachment_container
|
||||||
|
render 'api/v1/issues/show'
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@object_result = Api::Pm::Issues::CreateService.call(@project, issue_params, current_user)
|
||||||
|
render 'api/v1/issues/create'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@object_result = Api::Pm::Issues::UpdateService.call(@project, @issue, issue_params, current_user)
|
||||||
|
render 'api/v1/issues/update'
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch_update
|
||||||
|
@object_result = Api::Pm::Issues::BatchUpdateService.call(@project, @issues, batch_issue_params, current_user)
|
||||||
|
if @object_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error('批量更新疑修失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch_destroy
|
||||||
|
return render_ok if params[:ids].is_a?(Array) && params[:ids].blank?
|
||||||
|
@object_result = Api::Pm::Issues::BatchDeleteService.call(@project, @issues, current_user)
|
||||||
|
if @object_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error('批量删除疑修失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def priorities
|
||||||
|
@priorities = IssuePriority.order(position: :asc)
|
||||||
|
@priorities = @priorities.ransack(name_cont: params[:keyword]).result if params[:keyword]
|
||||||
|
@priorities = kaminary_select_paginate(@priorities)
|
||||||
|
render "api/v1/issues/issue_priorities/index"
|
||||||
|
end
|
||||||
|
|
||||||
|
def tags
|
||||||
|
# IssueTag.pm_init_data(params[:pm_project_id]) unless $redis_cache.hget("pm_project_init_issue_tags", params[:pm_project_id])
|
||||||
|
@issue_tags = IssueTag.where(pm_project_id: params[:pm_project_id]).reorder("#{tag_sort_by} #{tag_sort_direction}")
|
||||||
|
@issue_tags = @issue_tags.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
|
||||||
|
params[:only_name] = true #强制渲染 不走project
|
||||||
|
@issue_tags = kaminary_select_paginate(@issue_tags.select(:id, :name, :color))
|
||||||
|
render "api/v1/issues/issue_tags/index"
|
||||||
|
end
|
||||||
|
|
||||||
|
def statues
|
||||||
|
@statues = IssueStatus.order("position asc")
|
||||||
|
@statues = @statues.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
|
||||||
|
@statues = kaminary_select_paginate(@statues)
|
||||||
|
render "api/v1/issues/statues/index"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@object_result = Api::Pm::Issues::DeleteService.call(@project, @issue, current_user)
|
||||||
|
if @object_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error('删除疑修失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
|
||||||
|
Axlsx::Package.new do |p|
|
||||||
|
[['requirement', 1], ['task', 2], ['bug', 3]].each do |type|
|
||||||
|
p.workbook.add_worksheet(:name => type[0]) do |sheet|
|
||||||
|
@issues = Issue.where(pm_project_id: params[:pm_project_id], pm_issue_type: type[1])
|
||||||
|
sheet.add_row ["ID", "标题*", "正文", "创建者*", "创建时间", "修改者", "更新时间", "状态", "负责人", "优先级", "标记", "开始时间","结束时间", "预估工时"]
|
||||||
|
@issues.each do |issue|
|
||||||
|
sheet.add_row [issue.id, issue.subject, issue.description, issue.user.try(:login), issue.created_on.strftime("%Y-%m-%d %H:%M:%S"), issue.changer.try(:login), issue.updated_on.strftime("%Y-%m-%d %H:%M:%S"), issue.status_id, issue.assigners.pluck(:login).join(","), issue.priority_id, issue.issue_tags.pluck(:name, :color).join(","), issue.start_date.present? ? issue.start_date.strftime("%Y-%m-%d") : "", issue.due_date.present? ? issue.due_date.strftime("%Y-%m-%d") : "", issue.time_scale]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.workbook.add_worksheet(:name => 'leaf_relations') do |sheet|
|
||||||
|
leaf_issues = Issue.where(pm_project_id: params[:pm_project_id]).where.not(root_id: nil)
|
||||||
|
sheet.add_row ["ID", "父工作项ID"]
|
||||||
|
leaf_issues.each do |issue|
|
||||||
|
sheet.add_row [issue.id, issue.root_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.workbook.add_worksheet(:name => 'link_relations') do |sheet|
|
||||||
|
# links = PmLink.joins(:linkable_issue).where(issues: {pm_project_id: params[:pm_project_id]})
|
||||||
|
links = PmLink.find_by_sql("SELECT `pm_links`.* FROM `pm_links` INNER JOIN `issues` ON `issues`.`id` = `pm_links`.`linkable_id` AND `pm_links`.`linkable_type` = 'Issue' WHERE `issues`.`pm_project_id` = #{params[:pm_project_id]}")
|
||||||
|
sheet.add_row ["ID", "被关联工作项ID"]
|
||||||
|
links.each do |link|
|
||||||
|
sheet.add_row [link.linkable_id, link.be_linkable_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.serialize('public/导出工作项.xlsx')
|
||||||
|
end
|
||||||
|
|
||||||
|
send_file('public/导出工作项.xlsx', :type => 'application/octet-stream;charset=utf-8')
|
||||||
|
end
|
||||||
|
|
||||||
|
def import
|
||||||
|
begin
|
||||||
|
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
|
||||||
|
return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
|
||||||
|
return render_error('请输入正确的组织ID.') if params[:organization_id].blank?
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
types = {requirement: 1, task: 2, bug: 3}
|
||||||
|
doc = SimpleXlsxReader.open(params[:file].tempfile)
|
||||||
|
doc.sheets.each do |sheet|
|
||||||
|
case sheet.name
|
||||||
|
when 'requirement', 'task', 'bug'
|
||||||
|
|
||||||
|
type = types["#{sheet.name}".to_sym]
|
||||||
|
|
||||||
|
sheet.rows.each.with_index do |row, index|
|
||||||
|
next if index == 0
|
||||||
|
issue = Issue.new(issue_classify: "issue", project_id: 0, pm_project_id: params[:pm_project_id], pm_issue_type: type, tracker_id: Tracker.first.id)
|
||||||
|
issue.fake_id = row[0]
|
||||||
|
issue.subject = row[1]
|
||||||
|
issue.description = row[2]
|
||||||
|
author = User.find_by(login: row[3])
|
||||||
|
issue.user = author
|
||||||
|
issue.created_on = row[4]
|
||||||
|
changer = User.find_by(login: row[5])
|
||||||
|
issue.changer = changer
|
||||||
|
issue.updated_on = row[6]
|
||||||
|
issue.status_id = row[7].to_i
|
||||||
|
if row[8].present?
|
||||||
|
row[8].split(',').each do |a|
|
||||||
|
u = User.find_by(login: a)
|
||||||
|
next unless u.present?
|
||||||
|
issue.assigners << u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
issue.priority_id = row[9]
|
||||||
|
if row[10].present?
|
||||||
|
row[10].split(',').each_slice(2).to_a.each do |t|
|
||||||
|
tag = IssueTag.find_by(project_id: 0, organization_id: params[:organization_id], name: t[0])
|
||||||
|
if tag.present?
|
||||||
|
issue.issue_tags << tag
|
||||||
|
else
|
||||||
|
tag = IssueTag.create(project_id: 0,organization_id: params[:organization_id], name: t[0], color: t[1])
|
||||||
|
issue.issue_tags << tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
issue.start_date = row[11]
|
||||||
|
issue.due_date = row[12]
|
||||||
|
issue.time_scale = row[13]
|
||||||
|
issue.save!
|
||||||
|
end
|
||||||
|
when 'leaf_relations'
|
||||||
|
sheet.rows.each.with_index do |row, index|
|
||||||
|
next if index == 0
|
||||||
|
children_issue = Issue.where(fake_id: row[0]).last
|
||||||
|
parent_issue = Issue.where(fake_id: row[1]).last
|
||||||
|
next if children_issue.blank? || parent_issue.blank?
|
||||||
|
children_issue.root_id = parent_issue.id
|
||||||
|
children_issue.save(touch: false)
|
||||||
|
end
|
||||||
|
when 'link_relations'
|
||||||
|
sheet.rows.each.with_index do |row, index|
|
||||||
|
next if index == 0
|
||||||
|
link_issue = Issue.where(fake_id: row[0]).last
|
||||||
|
be_link_issue = Issue.where(fake_id: row[1]).last
|
||||||
|
next if link_issue.blank? || be_link_issue.blank?
|
||||||
|
PmLink.create!(linkable_type: 'Issue', linkable_id: link_issue.id, be_linkable_type: 'Issue', be_linkable_id: be_link_issue.id)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return render_error('导入失败,请上传正确格式的excel文件')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
rescue
|
||||||
|
return render_error('导入失败,请上传正确格式的excel文件')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_issues
|
||||||
|
children_issues = @issue.pm_issue_type == 1 ? @issue.child_count > 0 ? Issue.where(id: @issue.id) : Issue.none : Issue.where(root_id: @issue.id)
|
||||||
|
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: @issue.id).pluck(:be_linkable_id))
|
||||||
|
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: @issue.id).pluck(:linkable_id))
|
||||||
|
|
||||||
|
full_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
|
||||||
|
compare_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
|
||||||
|
i = compare_link_issues_ids.count
|
||||||
|
while i > 0 do
|
||||||
|
children_issues = Issue.where(root_id: compare_link_issues_ids)
|
||||||
|
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: compare_link_issues_ids).pluck(:be_linkable_id))
|
||||||
|
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: compare_link_issues_ids).pluck(:linkable_id))
|
||||||
|
|
||||||
|
compare_link_issues_ids = (children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)) - full_link_issues_ids
|
||||||
|
full_link_issues_ids = full_link_issues_ids | compare_link_issues_ids
|
||||||
|
i = compare_link_issues_ids.count
|
||||||
|
end
|
||||||
|
exclude_issues_ids = []
|
||||||
|
exclude_issues = Issue.where(id: full_link_issues_ids).where.not(root_id: nil)
|
||||||
|
exclude_issues.each do |i|
|
||||||
|
exclude_issues_ids << i.id if i.pm_issue_type == 1 && full_link_issues_ids.include?(i.root_id)
|
||||||
|
end
|
||||||
|
full_link_issues_ids = full_link_issues_ids - exclude_issues_ids
|
||||||
|
@requirement_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:1, root_id: nil).pm_includes
|
||||||
|
@task_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:2).pm_includes
|
||||||
|
@bug_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:3).pm_includes
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def circle_link_issues(issue_ids)
|
||||||
|
if issue_ids.present?
|
||||||
|
children_issues = Issue.joins(:parent_issue).where(issues: {id: issue_ids})
|
||||||
|
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: issue_ids))
|
||||||
|
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: issue_ids))
|
||||||
|
|
||||||
|
return circle_link_issues(children_issues.pluck(:id))
|
||||||
|
else
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_issue_operate_permission
|
||||||
|
return if params[:project_id].to_i.zero?
|
||||||
|
render_forbidden('您没有操作权限!') unless @project.member?(current_user) || current_user.admin? || @issue.user == current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_issue
|
||||||
|
# return render_parameter_missing if params[:pm_project_id].blank?
|
||||||
|
@issue = Issue.issue_issue.find_by_id(params[:id])
|
||||||
|
render_not_found('疑修不存在!') if @issue.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
# def load_issue_by_index
|
||||||
|
# return render_parameter_missing if params[:pm_project_id].blank? || params[:pm_issue_type].blank? || params[:enterprise_identifier].blank?
|
||||||
|
# @issue = Issue.find_issues_by_pm(params[:enterprise_identifier], params[:pm_issue_type])
|
||||||
|
# .find_by(pm_issue_type_index3: params[:index])
|
||||||
|
# render_not_found('疑修不存在!') if @issue.blank?
|
||||||
|
# end
|
||||||
|
|
||||||
|
def load_issues
|
||||||
|
return render_error('请输入正确的ID数组!') unless params[:ids].is_a?(Array)
|
||||||
|
params[:ids].each do |id|
|
||||||
|
@issue = Issue.find_by(id: id, pm_project_id: params[:pm_project_id])
|
||||||
|
return render_not_found("ID为#{id}的疑修不存在!") if @issue.blank?
|
||||||
|
end
|
||||||
|
if params[:ids].blank?
|
||||||
|
@issues = Issue.where(pm_project_id: params[:pm_project_id])
|
||||||
|
else
|
||||||
|
@issues = Issue.where(id: params[:ids], pm_project_id: params[:pm_project_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def query_params
|
||||||
|
params.permit(
|
||||||
|
:only_name,
|
||||||
|
:category,
|
||||||
|
:participant_category,
|
||||||
|
:keyword, :author_id,
|
||||||
|
:milestone_id, :assigner_id,
|
||||||
|
:status_id, :priority_id,
|
||||||
|
:begin_date, :end_date,
|
||||||
|
:update_begin_date, :update_end_date,
|
||||||
|
:sort_by, :sort_direction, :root_id,
|
||||||
|
:issue_tag_ids, :pm_project_id, :pm_sprint_id, :pm_issue_type, :pm_project_ids,
|
||||||
|
:status_ids, :ids, :exclude_ids, :pm_issue_types, :participator_id, :enterprise_identifier
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def issue_params
|
||||||
|
params.permit(
|
||||||
|
:status_id, :priority_id, :milestone_id,
|
||||||
|
:branch_name, :start_date, :due_date, :time_scale,
|
||||||
|
:subject, :description, :blockchain_token_num, :root_subject,
|
||||||
|
:pm_project_id, :pm_sprint_id, :pm_issue_type, :root_id, :link_able_id, :project_id,
|
||||||
|
:status_msg, :enterprise_identifier,
|
||||||
|
issue_tag_ids: [],
|
||||||
|
assigner_ids: [],
|
||||||
|
attachment_ids: [],
|
||||||
|
receivers_login: []
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch_issue_params
|
||||||
|
params.permit(
|
||||||
|
:status_id, :priority_id, :milestone_id, :pm_sprint_id, :due_date, :pm_issue_type, :root_id, :target_pm_project_id, :project_id,
|
||||||
|
:issue_tag_ids => [],
|
||||||
|
:assigner_ids => [] )
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_sort_by
|
||||||
|
sort_by = params.fetch(:sort_by, "updated_on")
|
||||||
|
sort_by = Issue.column_names.include?(sort_by) ? sort_by : "updated_on"
|
||||||
|
sort_by
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_sort_direction
|
||||||
|
sort_direction = params.fetch(:sort_direction, "desc").downcase
|
||||||
|
sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
|
||||||
|
sort_direction
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_sort_by
|
||||||
|
sort_by = params.fetch(:sort_by, "created_at")
|
||||||
|
sort_by = IssueTag.column_names.include?(sort_by) ? sort_by : "created_at"
|
||||||
|
sort_by
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_sort_direction
|
||||||
|
sort_direction = params.fetch(:sort_direction, "desc").downcase
|
||||||
|
sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
|
||||||
|
sort_direction
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
class Api::Pm::JournalsController < Api::Pm::BaseController
|
||||||
|
before_action :require_login, except: [:index, :children_journals]
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_issue
|
||||||
|
before_action :load_journal, only: [:children_journals, :update, :destroy]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@object_result = Api::V1::Issues::Journals::ListService.call(@issue, query_params, current_user)
|
||||||
|
@total_journals_count = @object_result[:total_journals_count]
|
||||||
|
@total_operate_journals_count = @object_result[:total_operate_journals_count]
|
||||||
|
@total_comment_journals_count = @object_result[:total_comment_journals_count]
|
||||||
|
@journals = kaminary_select_paginate(@object_result[:data])
|
||||||
|
render 'api/pm/issues/journals/index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@object_result = Api::V1::Issues::Journals::CreateService.call(@issue, journal_params, current_user)
|
||||||
|
render 'api/v1/issues/journals/create'
|
||||||
|
end
|
||||||
|
|
||||||
|
def children_journals
|
||||||
|
@object_results = Api::V1::Issues::Journals::ChildrenListService.call(@issue, @journal, query_params, current_user)
|
||||||
|
@journals = kaminari_paginate(@object_results)
|
||||||
|
render 'api/v1/issues/journals/children_journals'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@object_result = Api::V1::Issues::Journals::UpdateService.call(@issue, @journal, journal_params, current_user)
|
||||||
|
render 'api/v1/issues/journals/update'
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueComment', @issue&.id, current_user.id, @journal.id, 'deleted', JSON.parse(@journal.to_builder.target!))
|
||||||
|
if @journal.destroy!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error('删除评论失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def query_params
|
||||||
|
params.permit(:category, :keyword, :sort_by, :sort_direction)
|
||||||
|
end
|
||||||
|
|
||||||
|
def journal_params
|
||||||
|
params.permit(:notes, :parent_id, :reply_id, :attachment_ids => [], :receivers_login => [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_issue
|
||||||
|
@issue = Issue.issue_issue.where(pm_project_id: params[:pm_project_id]).find_by_id(params[:issue_id])
|
||||||
|
render_not_found('疑修不存在!') if @issue.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_journal
|
||||||
|
@journal = Journal.find_by_id(params[:id])
|
||||||
|
render_not_found('评论不存在!') unless @journal.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
class Api::Pm::PipelinesController < Api::Pm::BaseController
|
||||||
|
include RepositoriesHelper
|
||||||
|
|
||||||
|
def index
|
||||||
|
@owner = Owner.find_by(login: params[:owner_id].to_s) || Owner.find_by(id: params[:owner_id].to_s)
|
||||||
|
tip_exception('组织未找到') if @owner.blank?
|
||||||
|
unless @owner.is_a?(Organization) && @owner.is_member?(current_user.id)
|
||||||
|
tip_exception('没有查看组织的权限')
|
||||||
|
end
|
||||||
|
@project_ids = @owner.projects.ids
|
||||||
|
project_gpids = @owner.projects.pluck(:gpid)
|
||||||
|
action_runs = Gitea::ActionRun.where(owner_id: @owner.gitea_uid)
|
||||||
|
group_data = action_runs.where(status: [1,2]).group(:workflow_id, :status).count
|
||||||
|
pipelines = Action::Pipeline.where(project_id: @project_ids).order(updated_at: :desc)
|
||||||
|
run_files = Gitea::ActionRun.select(:workflow_id, :repo_id).where(owner_id: @owner.gitea_uid).group(:workflow_id, :repo_id)
|
||||||
|
db_files = pipelines.pluck(:file_name)
|
||||||
|
@run_result = []
|
||||||
|
run_files.each do |file_info|
|
||||||
|
file = file_info.workflow_id
|
||||||
|
project = Project.find_by(gpid: file_info.repo_id)
|
||||||
|
next if project.blank?
|
||||||
|
unless db_files.include?(".gitea/workflows/#{file}")
|
||||||
|
pipeline = Action::Pipeline.find_or_initialize_by(pipeline_name: file.to_s.gsub(".yml", "").gsub(".yaml", ""),
|
||||||
|
file_name: ".gitea/workflows/#{file}",
|
||||||
|
branch: project.default_branch,
|
||||||
|
is_graphic_design: false,
|
||||||
|
disable: false,
|
||||||
|
project_id: project.id)
|
||||||
|
interactor = Repositories::EntriesInteractor.call(@owner, project.identifier, ".gitea/workflows/#{file}", ref: project.default_branch)
|
||||||
|
if interactor.success?
|
||||||
|
pipeline.yaml = decode64_content(interactor.result, @owner, project.repository, project.default_branch, nil)
|
||||||
|
end
|
||||||
|
pipeline.user_id = current_user.id
|
||||||
|
pipeline.save
|
||||||
|
# 导入的流水线统一先禁用
|
||||||
|
$gitea_hat_client.post_repos_actions_disable(project&.owner&.login, project&.identifier, {query: {workflow: file}}) rescue nil
|
||||||
|
end
|
||||||
|
last_action_run = action_runs.where(repo_id: project.gpid).where(workflow_id: file).order(updated: :desc).first
|
||||||
|
last_action_run_json = last_action_run.present? ? {
|
||||||
|
id: last_action_run.id,
|
||||||
|
schedule: last_action_run.schedule_id > 0,
|
||||||
|
title: last_action_run.title,
|
||||||
|
index: last_action_run.index,
|
||||||
|
status: last_action_run.status,
|
||||||
|
started: last_action_run.started,
|
||||||
|
stopped: last_action_run.stopped,
|
||||||
|
length: last_action_run.stopped-last_action_run.started,
|
||||||
|
created: last_action_run.created,
|
||||||
|
updated: last_action_run.updated,
|
||||||
|
} : {}
|
||||||
|
|
||||||
|
total = 0
|
||||||
|
success = 0
|
||||||
|
failure = 0
|
||||||
|
group_data.each do |k,v|
|
||||||
|
total += v if k[0] == file
|
||||||
|
success += v if k[0] == file && k[1] == 1
|
||||||
|
failure += v if k[0] == file && k[1] == 2
|
||||||
|
end
|
||||||
|
@run_result << {
|
||||||
|
repo_id: last_action_run.repo_id,
|
||||||
|
filename: ".gitea/workflows/#{file}",
|
||||||
|
total: total,
|
||||||
|
success: success,
|
||||||
|
failure: failure
|
||||||
|
}.merge(last_action_run_json)
|
||||||
|
end
|
||||||
|
# Rails.logger.info("@run_result======#{@run_result}")
|
||||||
|
@disabled_workflows = Gitea::RepoUnit.where(repo_id: project_gpids, type: 10).where("config is not null")
|
||||||
|
@pipelines = Action::Pipeline.select("distinct project_id,max(updated_at) as updated_at")
|
||||||
|
.where(project_id: @project_ids).group(:project_id).order("updated_at desc")
|
||||||
|
@pipelines = @pipelines.where("pipeline_name like ?", "%#{params[:pipeline_name]}%") if params[:pipeline_name].present?
|
||||||
|
@pipelines = @pipelines.where(pipeline_type: params[:pipeline_type]) if params[:pipeline_type].present?
|
||||||
|
@pipelines = kaminari_paginate(@pipelines)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,156 @@
|
||||||
|
class Api::Pm::ProjectsController < Api::Pm::BaseController
|
||||||
|
before_action :require_login, except: [:convert]
|
||||||
|
before_action :load_project, only: [:convert]
|
||||||
|
def convert
|
||||||
|
data = {
|
||||||
|
owner: @project.owner.try(:login),
|
||||||
|
identifier: @project.identifier,
|
||||||
|
name: @project.name
|
||||||
|
}
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def issues_count
|
||||||
|
return tip_exception '参数错误' unless params[:pm_project_id].present?
|
||||||
|
@issues = Issue.where(pm_project_id: params[:pm_project_id])
|
||||||
|
case params[:category].to_s
|
||||||
|
when 'closed'
|
||||||
|
@issues = @issues.closed
|
||||||
|
when 'opened'
|
||||||
|
@issues = @issues.opened
|
||||||
|
end
|
||||||
|
@participant_category_count = {}
|
||||||
|
if params[:participant_category].to_s == "authoredme" or params[:participant_category].to_s == "assignedme"
|
||||||
|
issues_category = @issues.joins(:issue_participants).where(pm_issue_type: [1, 2, 3]).where(issue_participants: {participant_type: %w[authored assigned atme], participant_id: current_user&.id})
|
||||||
|
@participant_category_count = issues_category.group(:pm_project_id, "issue_participants.participant_type").count
|
||||||
|
end
|
||||||
|
case params[:participant_category].to_s
|
||||||
|
when 'aboutme' # 关于我的
|
||||||
|
@issues = @issues.joins(:issue_participants).where(issue_participants: {participant_type: %w[authored assigned atme], participant_id: current_user&.id})
|
||||||
|
when 'authoredme' # 我创建的
|
||||||
|
@issues = @issues.joins(:issue_participants).where(issue_participants: {participant_type: 'authored', participant_id: current_user&.id})
|
||||||
|
when 'assignedme' # 我负责的
|
||||||
|
@issues = @issues.joins(:issue_participants).where(issue_participants: {participant_type: 'assigned', participant_id: current_user&.id})
|
||||||
|
when 'atme' # @我的
|
||||||
|
@issues = @issues.joins(:issue_participants).where(issue_participants: {participant_type: 'atme', participant_id: current_user&.id})
|
||||||
|
end
|
||||||
|
data = {}
|
||||||
|
@issues_count = @issues.group(:pm_project_id).count
|
||||||
|
# requirement 1 task 2 bug 3
|
||||||
|
@issues_type_count = @issues.group(:pm_project_id, :pm_issue_type).count
|
||||||
|
params[:pm_project_id].map(&:to_i).map do |project_id|
|
||||||
|
data[project_id] = {
|
||||||
|
total: @issues_count[project_id] || 0,
|
||||||
|
requirement: @issues_type_count[[project_id, 1]] || 0,
|
||||||
|
task: @issues_type_count[[project_id, 2]] || 0,
|
||||||
|
bug: @issues_type_count[[project_id, 3]] || 0,
|
||||||
|
authoredme: @participant_category_count[[project_id, 0]] || 0,
|
||||||
|
assignedme: @participant_category_count[[project_id, 1]] || 0,
|
||||||
|
atme: @participant_category_count[[project_id, 4]] || 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def statistics
|
||||||
|
return tip_exception '参数错误' if params[:pm_project_id].blank?
|
||||||
|
@issues = Issue.where(pm_project_id: params[:pm_project_id], pm_issue_type:[1, 2, 3])
|
||||||
|
@last_week_close_issues = @issues.where(status_id: 5).where("updated_on > ? and updated_on < ?", Time.now - 7.days, Time.now)
|
||||||
|
last_week_close_type_count_data = @last_week_close_issues.group(:pm_issue_type).count
|
||||||
|
type_count_data = @issues.group(:pm_issue_type).count
|
||||||
|
type_status = @issues.group(:pm_issue_type,:status_id).count
|
||||||
|
type_status_data = {}
|
||||||
|
IssueStatus.all.map do |e|
|
||||||
|
# next if e.id == 5
|
||||||
|
[1,2,3].map{ |type|
|
||||||
|
next if type == 1 && [1, 6].include?(e.id)
|
||||||
|
type_status_data[type] = {} if type_status_data[type].nil?
|
||||||
|
if type_status[[type,e.id]].nil?
|
||||||
|
type_status_data[type][e.id] = 0
|
||||||
|
else
|
||||||
|
type_status_data[type][e.id] = type_status[[type,e.id]]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
open_data = {
|
||||||
|
"1": type_status_data[1][1].to_i + type_status_data[1][2].to_i + type_status_data[1][3].to_i + type_status_data[1][6].to_i,
|
||||||
|
"2": type_status_data[2][1].to_i + type_status_data[2][2].to_i + type_status_data[2][3].to_i + type_status_data[2][6].to_i,
|
||||||
|
"3": type_status_data[3][1].to_i + type_status_data[3][2].to_i + type_status_data[3][3].to_i + type_status_data[3][6].to_i,
|
||||||
|
}
|
||||||
|
if type_count_data.keys.size < 3
|
||||||
|
nedd_add = [1,2,3] - type_count_data.keys
|
||||||
|
nedd_add.map{ |e|
|
||||||
|
type_count_data[e] = 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
if last_week_close_type_count_data.keys.size < 3
|
||||||
|
nedd_add = [1,2,3] - last_week_close_type_count_data.keys
|
||||||
|
nedd_add.map{ |e|
|
||||||
|
last_week_close_type_count_data[e] = 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
data = {
|
||||||
|
pie_chart: type_count_data,
|
||||||
|
bar_chart: type_status_data,
|
||||||
|
open_data: open_data,
|
||||||
|
last_week_close_data: last_week_close_type_count_data,
|
||||||
|
}
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def polyline
|
||||||
|
return tip_exception '参数错误' if params[:pm_project_id].blank?
|
||||||
|
time_line = (Time.current.beginning_of_day - 29.day) .. Time.current
|
||||||
|
@create_issues = Issue.where(pm_project_id: params[:pm_project_id],created_on: time_line)
|
||||||
|
@due_issues = Issue.where(pm_project_id: params[:pm_project_id],status_id:[3,5],due_date: time_line)
|
||||||
|
@create_issues_count = @create_issues.group(:pm_issue_type,"DATE(created_on)").count
|
||||||
|
@due_issues_count = @due_issues.group(:pm_issue_type,"DATE(due_date)").count
|
||||||
|
data = {
|
||||||
|
create_issues: {},
|
||||||
|
due_issues: {}
|
||||||
|
}
|
||||||
|
30.times do |time|
|
||||||
|
current_time = Date.current - time.day
|
||||||
|
if @create_issues_count.present?
|
||||||
|
data[:create_issues][current_time] = {
|
||||||
|
"1": @create_issues_count[[1,current_time]] || 0,
|
||||||
|
"2": @create_issues_count[[2,current_time]] || 0,
|
||||||
|
"3": @create_issues_count[[3,current_time]] || 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data[:create_issues][current_time] = {
|
||||||
|
"1": 0,
|
||||||
|
"2": 0,
|
||||||
|
"3": 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
if @due_issues_count.present?
|
||||||
|
data[:due_issues][current_time] = {
|
||||||
|
"1": @due_issues_count[[1,current_time]] || 0,
|
||||||
|
"2": @due_issues_count[[2,current_time]] || 0,
|
||||||
|
"3": @due_issues_count[[3,current_time]] || 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data[:due_issues][current_time] = {
|
||||||
|
"1": 0,
|
||||||
|
"2": 0,
|
||||||
|
"3": 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def bind_project
|
||||||
|
return render_forbidden('您没有操作权限!') unless @project.member?(current_user) || current_user.admin?
|
||||||
|
Issue.where(pm_project_id: params[:pm_project_id], user_id: current_user).update_all(project_id: params[:project_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def load_project
|
||||||
|
@project = Project.joins(:owner).find params[:project_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,109 @@
|
||||||
|
class Api::Pm::SprintIssuesController < Api::Pm::BaseController
|
||||||
|
|
||||||
|
before_action :require_login, except: [:index]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@issues = Api::Pm::SprintIssues::ListService.call(query_params, current_user)
|
||||||
|
@issues = kaminari_paginate(@issues)
|
||||||
|
render 'api/v1/issues/index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def burndown_charts
|
||||||
|
return tip_exception '参数错误' if params[:pm_sprint_id].blank? || params[:start_time].blank? || params[:end_time].blank?
|
||||||
|
@issues = Issue.where(pm_sprint_id: params[:pm_sprint_id])
|
||||||
|
start_time = Date.parse params[:start_time]
|
||||||
|
end_time = Date.parse params[:end_time]
|
||||||
|
time_count = (end_time - start_time).to_i + 1 # 计算间隔时间 加上最后一天
|
||||||
|
data = []
|
||||||
|
curren_issues = @issues.group(:status_id, :due_date).count
|
||||||
|
total_count = @issues.count
|
||||||
|
cardinality = (total_count.zero? || time_count.zero?) ? 0 : total_count.to_f / time_count.to_f
|
||||||
|
# cardinality = BigDecimal.new(total_count) / BigDecimal.new(time_count)
|
||||||
|
time_count.times do |x|
|
||||||
|
e_time = start_time + x
|
||||||
|
completed = curren_issues[[5, e_time]].to_i + curren_issues[[3, e_time]].to_i - @issues.where(pm_issue_type: 3, status_id: 3).size
|
||||||
|
total_count = total_count - completed
|
||||||
|
data << { time: e_time, undone: total_count, completed: completed, base_number: (cardinality * (time_count - x - 1)).to_f.round(2) }
|
||||||
|
end
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def statistics
|
||||||
|
pm_sprint_ids = params[:pm_sprint_ids].split(",") rescue []
|
||||||
|
return tip_exception '参数错误' if pm_sprint_ids.blank?
|
||||||
|
@issues = Issue.where(pm_sprint_id: pm_sprint_ids)
|
||||||
|
data = {}
|
||||||
|
# requirement 1 task 2 bug 3
|
||||||
|
@issues_count = @issues.group(:pm_sprint_id).count
|
||||||
|
@issues_type_count = @issues.group(:pm_sprint_id, :status_id).count
|
||||||
|
@issues_pm_type_count = @issues.group(:pm_sprint_id, :pm_issue_type).count
|
||||||
|
@issues_hour_count = @issues.group(:pm_sprint_id).sum(:time_scale)
|
||||||
|
@issues_hour_type_count = @issues.group(:pm_sprint_id, :status_id).sum(:time_scale)
|
||||||
|
@issues_hour_pm_type_count = @issues.group(:pm_sprint_id, :pm_issue_type).sum(:time_scale)
|
||||||
|
@issues_status_pm_type_count = @issues.group(:pm_sprint_id, :pm_issue_type, :status_id).count
|
||||||
|
pm_sprint_ids.map(&:to_i).map do |sprint_id|
|
||||||
|
# count_closed 工作项已完成/已关闭数量,需排除已修复的缺陷数量
|
||||||
|
count_closed = @issues_type_count[[sprint_id, 5]].to_i + @issues_type_count[[sprint_id, 3]].to_i - @issues.where(pm_sprint_id: sprint_id, pm_issue_type: 3, status_id: 3).size
|
||||||
|
# hour_closed 已完成/已关闭 预估工时之和,需排除已修复的缺陷预估工时
|
||||||
|
hour_closed = @issues_hour_type_count[[sprint_id, 5]].to_f + @issues_hour_type_count[[sprint_id, 3]].to_f - @issues.where(pm_sprint_id: sprint_id, pm_issue_type: 3, status_id: 3).sum(:time_scale).to_f
|
||||||
|
data[sprint_id] = {
|
||||||
|
count_total: @issues_count[sprint_id] || 0,
|
||||||
|
count_closed: count_closed || 0,
|
||||||
|
hour_total: @issues_hour_count[sprint_id].to_f || 0,
|
||||||
|
hour_closed: hour_closed || 0,
|
||||||
|
requirement: @issues_pm_type_count[[sprint_id, 1]] || 0,
|
||||||
|
task: @issues_pm_type_count[[sprint_id, 2]] || 0,
|
||||||
|
bug: @issues_pm_type_count[[sprint_id, 3]] || 0,
|
||||||
|
requirement_hour: @issues_hour_pm_type_count[[sprint_id, 1]].to_i || 0,
|
||||||
|
task_hour: @issues_hour_pm_type_count[[sprint_id, 2]].to_i || 0,
|
||||||
|
bug_hour: @issues_hour_pm_type_count[[sprint_id, 3]].to_i || 0,
|
||||||
|
requirement_open: (@issues_status_pm_type_count[[sprint_id, 1, 1]].to_i + @issues_status_pm_type_count[[sprint_id, 1, 2]].to_i) || 0,
|
||||||
|
task_open: @issues_status_pm_type_count[[sprint_id, 2, 1]].to_i + @issues_status_pm_type_count[[sprint_id, 2, 2]].to_i || 0,
|
||||||
|
bug_open: @issues_status_pm_type_count[[sprint_id, 3, 1]].to_i + @issues_status_pm_type_count[[sprint_id, 3, 2]].to_i || 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
render_ok(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
before_action :load_uncomplete_issues, only: [:complete]
|
||||||
|
|
||||||
|
def complete
|
||||||
|
begin
|
||||||
|
case complete_params[:complete_type].to_i
|
||||||
|
when 1
|
||||||
|
@issues.update_all(status_id: 5, due_date: Time.now)
|
||||||
|
when 2
|
||||||
|
@issues.update_all(pm_sprint_id: 0)
|
||||||
|
when 3
|
||||||
|
@issues.update_all(pm_sprint_id: complete_params[:target_pm_project_sprint_id])
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
rescue => e
|
||||||
|
render_error(e.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_uncomplete_issues
|
||||||
|
@issues = Issue.where(pm_sprint_id: complete_params[:pm_project_sprint_id]).where.not(status_id: 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
def complete_params
|
||||||
|
params.permit(:pm_project_sprint_id, :complete_type, :target_pm_project_sprint_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def query_params
|
||||||
|
params.permit(
|
||||||
|
:category,
|
||||||
|
:pm_project_id,
|
||||||
|
:pm_issue_type, # 需求1 任务2 缺陷3
|
||||||
|
:assigner_id,
|
||||||
|
:priority_id,
|
||||||
|
:status_id,
|
||||||
|
:keyword, :status_ids, :pm_issue_types,
|
||||||
|
:sort_by, :sort_direction
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,82 @@
|
||||||
|
class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
|
||||||
|
|
||||||
|
def personal
|
||||||
|
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||||
|
return render_error('请输入正确的用户ID.') if params[:user_id].blank?
|
||||||
|
@all_issues = Issue.joins(:issue_participants).where(issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||||
|
@all_issues = @all_issues.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||||
|
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s).distinct
|
||||||
|
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||||
|
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (Date.today.beginning_of_week+1.week).to_s, (Date.today.end_of_week+1.week).to_s).distinct
|
||||||
|
@next_week_all_issues = @next_week_all_issues.order('created_on desc')
|
||||||
|
@this_week_requirement_issues = @this_week_all_issues.where(pm_issue_type: 1)
|
||||||
|
@this_week_task_issues = @this_week_all_issues.where(pm_issue_type: 2)
|
||||||
|
@this_week_bug_issues = @this_week_all_issues.where(pm_issue_type: 3)
|
||||||
|
@close_requirement_issues = @this_week_requirement_issues.where(status_id: [3,5])
|
||||||
|
@close_task_issues = @this_week_task_issues.where(status_id: [3,5])
|
||||||
|
@close_bug_issues = @this_week_bug_issues.where(status_id: [3,5])
|
||||||
|
this_week_page = params[:this_week_page] || 1
|
||||||
|
this_week_limit = params[:this_week_limit] || 15
|
||||||
|
@this_week_all_issues = @this_week_all_issues.page(this_week_page).per(this_week_limit)
|
||||||
|
next_week_page = params[:next_week_page] || 1
|
||||||
|
next_week_limit = params[:next_week_limit] || 15
|
||||||
|
@next_week_all_issues = @next_week_all_issues.page(next_week_page).per(next_week_limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def group
|
||||||
|
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||||
|
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||||
|
@all_issues = @all_issues.where(pm_project_id: params[:pm_project_ids].split(",")) if params[:pm_project_ids].present?
|
||||||
|
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s)
|
||||||
|
@this_week_all_issues_group_count = @this_week_all_issues.group(:pm_project_id).count
|
||||||
|
data = {}
|
||||||
|
@this_week_all_issues_group_count.keys.each do |pm_project_id|
|
||||||
|
this_project_id_requirements = @this_week_all_issues.where(pm_project_id: pm_project_id, pm_issue_type: 1)
|
||||||
|
this_project_id_tasks = @this_week_all_issues.where(pm_project_id: pm_project_id, pm_issue_type: 2)
|
||||||
|
this_project_id_bugs = @this_week_all_issues.where(pm_project_id: pm_project_id, pm_issue_type: 3)
|
||||||
|
this_project_id_close_requirements = this_project_id_requirements.where(status_id: [3,5])
|
||||||
|
this_project_id_close_tasks = this_project_id_tasks.where(status_id: [3,5])
|
||||||
|
this_project_id_close_bugs = this_project_id_bugs.where(status_id: [3,5])
|
||||||
|
data[pm_project_id] = {
|
||||||
|
this_week_requirement_issues_count: this_project_id_requirements.count,
|
||||||
|
this_week_task_issues_count: this_project_id_tasks.count,
|
||||||
|
this_week_bug_issues_count: this_project_id_bugs.count,
|
||||||
|
close_requirement_issues_count: this_project_id_close_requirements.count,
|
||||||
|
close_task_issues_count: this_project_id_close_tasks.count,
|
||||||
|
close_bug_issues_count: this_project_id_close_bugs.count,
|
||||||
|
this_week_task_issues: this_project_id_tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
render :json => data
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_issues
|
||||||
|
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||||
|
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||||
|
@all_issues = @all_issues.where(pm_project_id: params[:pm_project_ids].split(",")) if params[:pm_project_ids].present?
|
||||||
|
@all_issues = @all_issues.where(pm_issue_type: params[:pm_issue_type].to_i) if params[:pm_issue_type].present?
|
||||||
|
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s)
|
||||||
|
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||||
|
@this_week_all_issues = kaminari_paginate(@this_week_all_issues)
|
||||||
|
end
|
||||||
|
def personal_issues
|
||||||
|
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||||
|
return render_error('请输入正确的用户ID.') if params[:user_id].blank?
|
||||||
|
@all_issues = Issue.joins(:issue_participants).where(issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||||
|
@all_issues = @all_issues.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||||
|
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s).distinct
|
||||||
|
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||||
|
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (Date.today.beginning_of_week+1.week).to_s, (Date.today.end_of_week+1.week).to_s).distinct
|
||||||
|
@next_week_all_issues = @next_week_all_issues.order('created_on desc')
|
||||||
|
this_week_page = params[:this_week_page] || 1
|
||||||
|
this_week_limit = params[:this_week_limit] || 15
|
||||||
|
@this_week_all_issues = @this_week_all_issues.page(this_week_page).per(this_week_limit)
|
||||||
|
next_week_page = params[:next_week_page] || 1
|
||||||
|
next_week_limit = params[:next_week_limit] || 15
|
||||||
|
@next_week_all_issues = @next_week_all_issues.page(next_week_page).per(next_week_limit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -55,6 +55,11 @@ class Api::V1::BaseController < ApplicationController
|
||||||
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def require_member_above
|
||||||
|
@project = load_project
|
||||||
|
return render_forbidden if !current_user.admin? && !@project.member?(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
# 具有对仓库的访问权限
|
# 具有对仓库的访问权限
|
||||||
def require_public_and_member_above
|
def require_public_and_member_above
|
||||||
@project = load_project
|
@project = load_project
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
class Api::V1::GitlinkCompetitionAppliesController < Api::V1::BaseController
|
||||||
|
|
||||||
|
def create
|
||||||
|
return render_error("请输入正确的竞赛ID") unless params[:competition_id].present?
|
||||||
|
return render_error("请输入正确的队伍ID") unless params[:team_id].present?
|
||||||
|
return render_error("请输入正确的队伍成员信息") unless params[:team_members].is_a?(Array)
|
||||||
|
params[:team_members].each do |member|
|
||||||
|
apply = GitlinkCompetitionApply.find_or_create_by(competition_id: params[:competition_id], team_id: params[:team_id], educoder_login: member[:login])
|
||||||
|
apply.competition_identifier = params[:competition_identifier]
|
||||||
|
apply.team_name = params[:team_name]
|
||||||
|
apply.school_name = member[:school_name]
|
||||||
|
apply.nickname = member[:nickname]
|
||||||
|
apply.identity = member[:identity]
|
||||||
|
apply.role = member[:role]
|
||||||
|
apply.email = member[:email]
|
||||||
|
user_info = get_user_info_by_educoder_login(member[:login])
|
||||||
|
apply.phone = user_info["phone"]
|
||||||
|
apply.save
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_user_info_by_educoder_login(edu_login)
|
||||||
|
req_params = { "login" => "#{edu_login}", "private_token" => "hriEn3UwXfJs3PmyXnqQ" }
|
||||||
|
api_url= "https://data.educoder.net"
|
||||||
|
client = Faraday.new(url: api_url)
|
||||||
|
response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params)
|
||||||
|
result = JSON.parse(response.body)
|
||||||
|
|
||||||
|
return nil if result["status"].to_s != "0"
|
||||||
|
|
||||||
|
# login 邮箱 手机号 姓名 学校/单位
|
||||||
|
user_info = result["data"]
|
||||||
|
|
||||||
|
return user_info
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
class Api::V1::Issues::IssueTagsController < Api::V1::BaseController
|
class Api::V1::Issues::IssueTagsController < Api::V1::BaseController
|
||||||
before_action :require_login, except: [:index]
|
before_action :require_login, except: [:index, :pm_index]
|
||||||
before_action :require_public_and_member_above, only: [:index]
|
before_action :require_public_and_member_above, only: [:index]
|
||||||
before_action :require_operate_above, only: [:create, :update, :destroy]
|
before_action :require_operate_above, only: [:create, :update, :destroy]
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Api::V1::Issues::JournalsController < Api::V1::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_issue
|
def load_issue
|
||||||
@issue = @project.issues.issue_issue.where(project_issues_index: params[:index]).where.not(id: params[:index]).take || Issue.find_by_id(params[:index])
|
@issue = @project.issues.issue_issue.where(project_issues_index: params[:index]).where.not(id: params[:index]).take || @project.issues.issue_issue.find_by_id(params[:index])
|
||||||
if @issue.blank?
|
if @issue.blank?
|
||||||
render_not_found("疑修不存在!")
|
render_not_found("疑修不存在!")
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class Api::V1::IssuesController < Api::V1::BaseController
|
class Api::V1::IssuesController < Api::V1::BaseController
|
||||||
before_action :require_login, except: [:index, :show]
|
before_action :require_login, except: [:index, :show, :show_by_id]
|
||||||
before_action :require_public_and_member_above, only: [:index, :show, :create, :update, :destroy]
|
before_action :require_public_and_member_above, only: [:index, :show, :show_by_id, :create, :update, :destroy]
|
||||||
before_action :require_operate_above, only: [:batch_update, :batch_destroy]
|
before_action :require_operate_above, only: [:batch_update, :batch_destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -22,8 +22,15 @@ class Api::V1::IssuesController < Api::V1::BaseController
|
||||||
|
|
||||||
before_action :load_issue, only: [:show, :update, :destroy]
|
before_action :load_issue, only: [:show, :update, :destroy]
|
||||||
before_action :check_issue_operate_permission, only: [:update, :destroy]
|
before_action :check_issue_operate_permission, only: [:update, :destroy]
|
||||||
|
before_action :load_issue_by_id, only: [:show_by_id]
|
||||||
|
|
||||||
|
def show_by_id
|
||||||
|
@issue.associate_attachment_container
|
||||||
|
@user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user)
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@issue.associate_attachment_container
|
||||||
@user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user)
|
@user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,7 +70,14 @@ class Api::V1::IssuesController < Api::V1::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_issue
|
def load_issue
|
||||||
@issue = @project.issues.issue_issue.where(project_issues_index: params[:index]).where.not(id: params[:index]).take || Issue.find_by_id(params[:index])
|
@issue = @project.issues.issue_issue.where(project_issues_index: params[:index]).where.not(id: params[:index]).take || @project.issues.issue_issue.find_by_id(params[:index])
|
||||||
|
if @issue.blank?
|
||||||
|
render_not_found("疑修不存在!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_issue_by_id
|
||||||
|
@issue = Issue.find_by_id(params[:index])
|
||||||
if @issue.blank?
|
if @issue.blank?
|
||||||
render_not_found("疑修不存在!")
|
render_not_found("疑修不存在!")
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
class Api::V1::PmIssuesController < ApplicationController
|
||||||
|
before_action :require_login, except: [:index, :show]
|
||||||
|
|
||||||
|
def index
|
||||||
|
project = Project.find_by_id(params[:project_id]) || Project.new( id: 0, user_id: 0, name:"pm_mm", identifier:"pm_mm" )
|
||||||
|
object_result = Api::V1::Issues::ListService.call(@project, query_params, current_user)
|
||||||
|
@total_issues_count = @object_result[:total_issues_count]
|
||||||
|
@opened_issues_count = @object_result[:opened_issues_count]
|
||||||
|
@closed_issues_count = @object_result[:closed_issues_count]
|
||||||
|
if params[:only_name].present?
|
||||||
|
@issues = kaminary_select_paginate(@object_result[:data].select(:id, :subject, :project_issues_index, :updated_on, :created_on))
|
||||||
|
else
|
||||||
|
@issues = kaminari_paginate(@object_result[:data])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
project = Project.find_by_id(params[:project_id]) || Project.new( id: 0, user_id: 0, name:"pm_mm", identifier:"pm_mm" )
|
||||||
|
@object_result = Api::V1::Issues::CreateService.call(project, issue_params, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def issue_params
|
||||||
|
params.permit(
|
||||||
|
:status_id, :priority_id, :milestone_id,
|
||||||
|
:branch_name, :start_date, :due_date,
|
||||||
|
:subject, :description, :blockchain_token_num,
|
||||||
|
:pm_project_id, :pm_sprint_id,
|
||||||
|
:issue_tag_ids => [],
|
||||||
|
:assigner_ids => [],
|
||||||
|
:attachment_ids => [],
|
||||||
|
:receivers_login => []
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,10 @@
|
||||||
|
class Api::V1::ProjectDatasetsController < Api::V1::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
return render_error("请输入正确的项目id字符串") unless params[:ids].present?
|
||||||
|
ids = params[:ids].split(",")
|
||||||
|
@project_datasets = ProjectDataset.where(project_id: ids).includes(:license, :project)
|
||||||
|
@project_datasets = kaminari_unlimit_paginate(@project_datasets)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,93 @@
|
||||||
|
class Api::V1::Projects::Actions::ActionsController < Api::V1::Projects::Actions::BaseController
|
||||||
|
|
||||||
|
def new_index
|
||||||
|
@files = $gitea_client.get_repos_contents_by_owner_repo_filepath(@project&.owner&.login, @project&.identifier, ".gitea/workflows") rescue []
|
||||||
|
@workflows = params[:workflows].split(",") if params[:workflows].present?
|
||||||
|
@action_runs = Gitea::ActionRun.where(repo_id: @project.gpid)
|
||||||
|
disabled_config = Gitea::RepoUnit.where(repo_id: @project.gpid, type: 10)&.first&.config
|
||||||
|
disabled_workflows = disabled_config.present? ? JSON.parse(disabled_config)["DisabledWorkflows"] : []
|
||||||
|
@action_runs = @action_runs.where(id: params[:ids].split(",")) if params[:ids].present?
|
||||||
|
@action_runs = @action_runs.where(workflow_id: @workflows) if params[:workflows].present?
|
||||||
|
group_data = @action_runs.where(status: [1,2]).group(:workflow_id, :status).count
|
||||||
|
@result = []
|
||||||
|
@files.map{|i|i['name']}.each do |file|
|
||||||
|
if @workflows.present?
|
||||||
|
next if !@workflows.include?(file)
|
||||||
|
end
|
||||||
|
last_action_run = @action_runs.where(workflow_id: file).order(updated: :desc).first
|
||||||
|
last_action_run_json = last_action_run.present? ? {
|
||||||
|
pipeline_id: Action::Pipeline.find_by(pipeline_name: file, project_id: @project.id),
|
||||||
|
id: last_action_run.id,
|
||||||
|
schedule: last_action_run.schedule_id > 0,
|
||||||
|
title: last_action_run.title,
|
||||||
|
index: last_action_run.index,
|
||||||
|
status: last_action_run.status,
|
||||||
|
started: last_action_run.started,
|
||||||
|
stopped: last_action_run.stopped,
|
||||||
|
length: last_action_run.stopped-last_action_run.started,
|
||||||
|
created: last_action_run.created,
|
||||||
|
updated: last_action_run.updated,
|
||||||
|
} : {}
|
||||||
|
|
||||||
|
total = 0
|
||||||
|
success = 0
|
||||||
|
failure = 0
|
||||||
|
group_data.each do |k,v|
|
||||||
|
total += v if k[0] == file
|
||||||
|
success += v if k[0] == file && k[1] == 1
|
||||||
|
failure += v if k[0] == file && k[1] == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline_type = 1
|
||||||
|
begin
|
||||||
|
content = Gitea::Repository::Entries::GetService.call(@project&.owner, @project&.identifier, URI.escape(file), ref: last_action_run.present? ? last_action_run.ref.gsub("refs/heads/","") : @project.default_branch)['content']
|
||||||
|
yaml_string = Base64.decode64(content).force_encoding("GBK").encode("UTF-8") unless Base64.decode64(content).force_encoding('UTF-8').valid_encoding?
|
||||||
|
yaml_string = Base64.decode64(content).force_encoding('UTF-8')
|
||||||
|
yml = YAML.safe_load(yaml_string)
|
||||||
|
pipeline_type = yml.name == file.to_s.gsub(".yml","").gsub(".yaml","") ? 2 : 1
|
||||||
|
rescue
|
||||||
|
Rails.logger.info("#{file}不能识别流水线类型")
|
||||||
|
end
|
||||||
|
@result << {
|
||||||
|
filename: file,
|
||||||
|
disabled: disabled_workflows.include?(file.to_s),
|
||||||
|
name: file.to_s.gsub(".yml","").gsub(".yaml","") ,
|
||||||
|
branch: last_action_run.present? ? last_action_run.ref.gsub("refs/heads/","") : @project.default_branch,
|
||||||
|
pipeline_type: pipeline_type,
|
||||||
|
total: total,
|
||||||
|
success: success,
|
||||||
|
failure: failure
|
||||||
|
}.merge(last_action_run_json)
|
||||||
|
end
|
||||||
|
render :json => {data: @result}
|
||||||
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
begin
|
||||||
|
gitea_result = $gitea_hat_client.get_repos_actions_by_owner_repo(@project&.owner&.login, @project&.identifier)
|
||||||
|
@data = gitea_result[:data]["Workflows"]
|
||||||
|
rescue
|
||||||
|
@data = []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
return render_error("请输入正确的流水线文件!") if params[:workflow].blank?
|
||||||
|
gitea_result = $gitea_hat_client.post_repos_actions_disable(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow]}}) rescue nil
|
||||||
|
if gitea_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("禁用流水线失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
return render_error("请输入正确的流水线文件!") if params[:workflow].blank?
|
||||||
|
gitea_result = $gitea_hat_client.post_repos_actions_enable(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow]}}) rescue nil
|
||||||
|
if gitea_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("取消禁用流水线失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
class Api::V1::Projects::Actions::BaseController < Api::V1::BaseController
|
||||||
|
before_action :require_public_and_member_above
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
class Api::V1::Projects::Actions::RunsController < Api::V1::Projects::Actions::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
@files = $gitea_client.get_repos_contents_by_owner_repo_filepath(@project&.owner&.login, @project&.identifier, ".gitea/workflows") rescue []
|
||||||
|
@has_file = @files.select { |i| i['name'] == params[:workflow] }.present?
|
||||||
|
if @has_file
|
||||||
|
@result_object = Api::V1::Projects::Actions::Runs::ListService.call(@project, {workflow: params[:workflow], page: page, limit: limit}, current_user&.gitea_token)
|
||||||
|
@begin_num = (page.to_i - 1) * limit.to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
return render_error("请输入正确的流水线文件!") if params[:workflow].blank?
|
||||||
|
return render_error("请输入正确的分支!") if params[:ref].blank?
|
||||||
|
gitea_result = $gitea_hat_client.post_repos_actions_runs_by_owner_repo(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow], ref: params[:ref]}})
|
||||||
|
if gitea_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
ender_error("启动流水线任务失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def rerun
|
||||||
|
return render_error("请输入正确的流水线记录ID!") if params[:run_id].blank?
|
||||||
|
gitea_result = $gitea_hat_client.post_repos_actions_runs_rerun_by_owner_repo_run(@project&.owner&.login, @project&.identifier, params[:run_id]) rescue nil
|
||||||
|
if gitea_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("重启所有流水线任务失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_rerun
|
||||||
|
return render_error("请输入正确的流水线记录ID!") if params[:run_id].blank?
|
||||||
|
return render_error("请输入正确的流水线任务ID") if params[:job].blank?
|
||||||
|
gitea_result = $gitea_hat_client.post_repos_actions_runs_jobs_rerun_by_owner_repo_run_job(@project&.owner&.login, @project&.identifier, params[:run_id], params[:job]) rescue nil
|
||||||
|
if gitea_result
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("重启流水线任务失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_show
|
||||||
|
@result_object = Api::V1::Projects::Actions::Runs::JobShowService.call(@project, params[:run_id], params[:job], params[:log_cursors], current_user&.gitea_token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_logs
|
||||||
|
return render_error("请输入正确的流水线记录ID!") if params[:run_id].blank?
|
||||||
|
return render_error("请输入正确的流水线任务ID") if params[:job].blank?
|
||||||
|
domain = GiteaService.gitea_config[:domain]
|
||||||
|
api_url = GiteaService.gitea_config[:hat_base_url]
|
||||||
|
|
||||||
|
url = "/repos/#{@owner.login}/#{@repository.identifier}/actions/runs/#{CGI.escape(params[:run_id])}/jobs/#{CGI.escape(params[:job])}/logs"
|
||||||
|
file_path = [domain, api_url, url].join
|
||||||
|
file_path = [file_path, "access_token=#{@owner&.gitea_token}"].join("?")
|
||||||
|
|
||||||
|
redirect_to file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,34 +1,79 @@
|
||||||
class Api::V1::Projects::BranchesController < Api::V1::BaseController
|
class Api::V1::Projects::BranchesController < Api::V1::BaseController
|
||||||
before_action :require_public_and_member_above, only: [:index, :all]
|
before_action :require_public_and_member_above, only: [:index, :all]
|
||||||
|
|
||||||
|
def gitee
|
||||||
|
url = URI("https://gitee.com/api/v5/repos/#{params[:owner]}/#{params[:repo]}/branches?access_token=#{params[:token]}&page=#{page}&per_page=#{limit}")
|
||||||
|
https = Net::HTTP.new(url.host, url.port)
|
||||||
|
https.use_ssl = true
|
||||||
|
request = Net::HTTP::Get.new(url)
|
||||||
|
response = https.request(request)
|
||||||
|
render :json => response.read_body
|
||||||
|
end
|
||||||
|
|
||||||
|
def github
|
||||||
|
url = URI("https://api.github.com/repos/#{params[:owner]}/#{params[:repo]}/branches?page=#{page}&per_page=#{limit}")
|
||||||
|
https = Net::HTTP.new(url.host, url.port)
|
||||||
|
https.use_ssl = true
|
||||||
|
|
||||||
|
request = Net::HTTP::Get.new(url)
|
||||||
|
request["Authorization"] = "Bearer #{params[:token]}"
|
||||||
|
request["Accept"] = "application/vnd.github+json"
|
||||||
|
request["X-GitHub-Api-Version"] = "2022-11-28"
|
||||||
|
|
||||||
|
response = https.request(request)
|
||||||
|
render :json => response.read_body
|
||||||
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@result_object = Api::V1::Projects::Branches::ListService.call(@project, {name: params[:keyword], page: page, limit: limit}, current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Branches::ListService.call(@project, {name: params[:keyword], state: params[:state], page: page, limit: limit}, current_user&.gitea_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
def all
|
def all
|
||||||
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
before_action :require_operate_above, only: [:create, :destroy]
|
before_action :require_operate_above, only: [:create, :destroy, :restore]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
|
||||||
|
@project.update_column(:updated_on, Time.now)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@result_object = Api::V1::Projects::Branches::DeleteService.call(@project, params[:name], current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Branches::DeleteService.call(@project, params[:name], current_user&.gitea_token)
|
||||||
if @result_object
|
if @result_object
|
||||||
|
@project.update_column(:updated_on, Time.now)
|
||||||
|
# 有开启的pr需要一同关闭
|
||||||
|
# 1、删除本仓库中存在未关闭的pr,即本仓库分支1->分支2
|
||||||
|
# 2、如果是fork仓库,考虑删除主仓库中存在未关闭的pr,即本仓库:分支1->主:分支2,同时分两种删除:1删除本仓库分支1,2删除主仓库分支2
|
||||||
|
close_pull_requests_by(@project, params[:name])
|
||||||
|
if @project.forked_from_project_id.present?
|
||||||
|
# fork项目中删除分支
|
||||||
|
close_pull_requests_by(@project.fork_project, params[:name])
|
||||||
|
end
|
||||||
|
|
||||||
return render_ok
|
return render_ok
|
||||||
else
|
else
|
||||||
return render_error('删除分支失败!')
|
return render_error('删除分支失败!')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restore
|
||||||
|
@result_object = Api::V1::Projects::Branches::RestoreService.call(@project, params[:branch_id], params[:branch_name], current_user&.gitea_token)
|
||||||
|
if @result_object
|
||||||
|
@project.update_column(:updated_on, Time.now)
|
||||||
|
return render_ok
|
||||||
|
else
|
||||||
|
return render_error('恢复分支失败!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
before_action :require_manager_above, only: [:update_default_branch]
|
before_action :require_manager_above, only: [:update_default_branch]
|
||||||
|
|
||||||
def update_default_branch
|
def update_default_branch
|
||||||
@result_object = Api::V1::Projects::Branches::UpdateDefaultBranchService.call(@project, params[:name], current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Branches::UpdateDefaultBranchService.call(@project, params[:name], current_user&.gitea_token)
|
||||||
if @result_object
|
if @result_object
|
||||||
|
@project.update_column(:updated_on, Time.now)
|
||||||
return render_ok
|
return render_ok
|
||||||
else
|
else
|
||||||
return render_error('更新默认分支失败!')
|
return render_error('更新默认分支失败!')
|
||||||
|
@ -39,4 +84,19 @@ class Api::V1::Projects::BranchesController < Api::V1::BaseController
|
||||||
def branch_params
|
def branch_params
|
||||||
params.require(:branch).permit(:new_branch_name, :old_branch_name)
|
params.require(:branch).permit(:new_branch_name, :old_branch_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def close_pull_requests_by(project, branch_name)
|
||||||
|
open_pull_requests = project.pull_requests.opening.where(head: branch_name).or(project.pull_requests.opening.where(base: branch_name))
|
||||||
|
if open_pull_requests.present?
|
||||||
|
open_pull_requests.each do |pull_request|
|
||||||
|
closed = PullRequests::CloseService.call(project.owner, project.repository, pull_request, current_user)
|
||||||
|
if closed === true
|
||||||
|
pull_request.project_trends.create!(user: current_user, project: project,action_type: ProjectTrend::CLOSE)
|
||||||
|
# 合并请求下issue处理为关闭
|
||||||
|
pull_request.issue&.update_attributes!({status_id:5})
|
||||||
|
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
class Api::V1::Projects::CommitsController < Api::V1::BaseController
|
class Api::V1::Projects::CommitsController < Api::V1::BaseController
|
||||||
before_action :require_public_and_member_above, only: [:index, :diff]
|
before_action :require_public_and_member_above, only: [:index, :diff, :recent, :files]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
|
||||||
|
@ -9,4 +9,19 @@ class Api::V1::Projects::CommitsController < Api::V1::BaseController
|
||||||
def diff
|
def diff
|
||||||
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
|
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def files
|
||||||
|
if params[:filepath].present?
|
||||||
|
@result_object = $gitea_hat_client.get_repos_commits_files_by_owner_repo_sha_filepath(@project&.owner.login, @project&.identifier, params[:sha], CGI.escape(params[:filepath]), {query: {token: current_user&.gitea_token}})
|
||||||
|
else
|
||||||
|
@result_object = $gitea_hat_client.get_repos_commits_files_by_owner_repo_sha(@project&.owner.login, @project&.identifier, params[:sha], {query: {token: current_user&.gitea_token, page: page, limit: limit}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def recent
|
||||||
|
hash = Api::V1::Projects::Commits::RecentService.call(@project, {keyword: params[:keyword], page: page, limit: limit}, current_user&.gitea_token)
|
||||||
|
@result_object = hash[:result]
|
||||||
|
@object_detail = hash[:detail]
|
||||||
|
puts @object_detail
|
||||||
|
end
|
||||||
end
|
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue