forked from Gitlink/forgeplus
Compare commits
1304 Commits
master
...
dev_jk_ser
Author | SHA1 | Date |
---|---|---|
|
46a11d20d9 | |
|
c8151bd472 | |
|
70e0754315 | |
|
4d9e36a683 | |
|
f9ce7e27cc | |
|
3bcb06d9e3 | |
|
f8a525edff | |
|
ee6af7fb7a | |
|
23581902fb | |
|
3d22022042 | |
|
996195b5f4 | |
|
4290b60f7e | |
|
36b34aebe0 | |
|
68bdf7856e | |
|
96d3b9eb2c | |
|
516f0a9f4e | |
|
83ed606912 | |
|
cc6d9c668e | |
|
9bbb66f890 | |
|
07324662e5 | |
|
8922593e3d | |
|
c03693dd07 | |
|
d1f2236f56 | |
|
c646865024 | |
|
74d99b3785 | |
|
e3393eb101 | |
|
364a83f496 | |
|
27e0683f3f | |
|
ae7209cdfe | |
|
1fddae4f95 | |
|
17f58f8871 | |
|
d9a8e7ea0d | |
|
796d95a8f8 | |
|
6c2b897aff | |
|
ce0f70c836 | |
|
baf2d03668 | |
|
8e846b5884 | |
|
207da14a72 | |
|
2db2ebe9a3 | |
|
2c3cfb0dd6 | |
|
01a6aaafdc | |
|
e84664bec1 | |
|
f12b8a300d | |
|
36ae4a9cb5 | |
|
a37e3fd91d | |
|
4374115512 | |
|
f6c6d4d671 | |
|
ac2d50f125 | |
|
3134081577 | |
|
0188dcb435 | |
|
816b95caf9 | |
|
7129518a0a | |
|
679d630b6f | |
|
f3f797fef1 | |
|
8d124a5128 | |
|
35f724c901 | |
|
9106bb5d47 | |
|
f3ccf7c03c | |
|
8b8fb883cc | |
|
54c6d7d8df | |
|
8e5feb4da9 | |
|
05453a6283 | |
|
7062397ea3 | |
|
8e6fdf3b3e | |
|
e7f279ca41 | |
|
132d2fbf0c | |
|
2594a4ba1b | |
|
4b9b10c914 | |
|
a5b0973dcc | |
|
af033bb8d0 | |
|
482578ced7 | |
|
72469f9104 | |
|
3ff361ebb9 | |
|
569dd6820a | |
|
7c5e58cae0 | |
|
75e9c47bef | |
|
0f4ca060da | |
|
34118ff816 | |
|
edf0655fb2 | |
|
4121a90a16 | |
|
023c23991b | |
|
9d54310f1f | |
|
9fc47bc675 | |
|
6132641ef5 | |
|
50adbd74df | |
|
449762b3ea | |
|
f307158909 | |
|
1b1bb860f7 | |
|
e375851a37 | |
|
de4376f91f | |
|
c1ee08ffa4 | |
|
c795a2a36d | |
|
5372183776 | |
|
c42e8c4b80 | |
|
448a6c17da | |
|
e60445057a | |
|
b32cbccb80 | |
|
25d1c5f13d | |
|
238e5fc65c | |
|
7eca07fc06 | |
|
fdd62a602e | |
|
b86eba4725 | |
|
49c96df25d | |
|
0266968d2c | |
|
f6ef2f5648 | |
|
b468740b15 | |
|
fce38e3fb7 | |
|
019e0a540b | |
|
517678f5ae | |
|
7632fa3988 | |
|
bd45e7167e | |
|
66927793fa | |
|
2b613ecc7b | |
|
ccfb367a88 | |
|
75faa6bf76 | |
|
e4e0b0ce57 | |
|
7fdf1af411 | |
|
2a956d02ed | |
|
7c249ea9fa | |
|
73d441397c | |
|
dc1d6ce219 | |
|
7e019e95ab | |
|
ec0846f223 | |
|
4ca3b66228 | |
|
1010b2a863 | |
|
1d832d1ba7 | |
|
3b3fad7e3c | |
|
16d8bf8f81 | |
|
5604ee036d | |
|
31797af44c | |
|
d369741900 | |
|
f69d423672 | |
|
28d45a48a1 | |
|
ccec8e9819 | |
|
bf5c226117 | |
|
0f8d2e6a5d | |
|
6cdaafe4e0 | |
|
0e49f81eaf | |
|
204554b34c | |
|
bc2992cc3d | |
|
a631d423c6 | |
|
edd1d27b0a | |
|
3edac3656a | |
|
d0b638cbc0 | |
|
1c16b74f1b | |
|
983f488177 | |
|
dfa0f1161d | |
|
bc6f5cec4d | |
|
ee27c90205 | |
|
aab1e42240 | |
|
0ec06bf54d | |
|
5d9f9cdfb0 | |
|
534ee80523 | |
|
daf7514afe | |
|
4b1f1c697e | |
|
77c7acd582 | |
|
025a6a53e9 | |
|
6b846b10bb | |
|
763d7b499e | |
|
9b39446dfb | |
|
c6e77ac7ee | |
|
f5cdb6f02d | |
|
f7ca03db81 | |
|
8da8b021f6 | |
|
70ba78a9b5 | |
|
6191ddd233 | |
|
35cf298f5d | |
|
ee5d959404 | |
|
7f47cd8d46 | |
|
06c0ac65bf | |
|
8f8dab10c3 | |
|
a6923bf7ed | |
![]() |
667dca0553 | |
![]() |
f23f02cb80 | |
|
38a8191b74 | |
|
e183f48c02 | |
![]() |
a1731f91a9 | |
|
ea7cf1cd1f | |
|
255b615327 | |
|
64c6f69f56 | |
|
49abadfa3f | |
|
4cde7c374e | |
|
b56930b9ab | |
|
f98886b3a0 | |
|
30572aa41c | |
|
ef83697cb8 | |
|
570f664c27 | |
|
e24921bba3 | |
|
e4d62c5335 | |
|
6d9cf8aad2 | |
|
e3179dfd6e | |
|
7817487ab7 | |
|
83b46fcb50 | |
![]() |
7cc9d207b6 | |
![]() |
abfb62f342 | |
![]() |
ccbbab0741 | |
|
3e5c1da2c5 | |
![]() |
1731d5fc20 | |
![]() |
8cce97258c | |
![]() |
4ea60a5114 | |
![]() |
dd7be1c392 | |
![]() |
dbc1ea107c | |
![]() |
a4df928c5a | |
![]() |
ab842a6f1a | |
![]() |
4636a1b3b6 | |
![]() |
591119016e | |
![]() |
16fc6ebc4e | |
|
6a3cc56f85 | |
|
eac812a7bf | |
![]() |
4560b9231e | |
![]() |
f3d7938750 | |
![]() |
23dc04b560 | |
|
07aefa79eb | |
|
423d5a9316 | |
|
9664ca001e | |
![]() |
f0a67c2f98 | |
![]() |
b3c1845dbf | |
|
d613b1f3bb | |
|
c8e063343e | |
![]() |
75a78c839d | |
|
e15809c186 | |
|
7d4c0df691 | |
|
e72dfa4973 | |
|
84a8339a04 | |
|
3d5b2e76d7 | |
|
8b14ee3c72 | |
![]() |
10b3eb8a7b | |
![]() |
f39873efd8 | |
![]() |
f880b316b9 | |
![]() |
074b999b2b | |
![]() |
ee17acf7cf | |
![]() |
e7af767d02 | |
|
5b30943feb | |
|
722f355fe4 | |
|
f8f9f3fbb6 | |
![]() |
84186fe694 | |
![]() |
d080727633 | |
![]() |
96165a3eec | |
![]() |
14d8a248d7 | |
![]() |
eb7f4e6da3 | |
![]() |
ef867e1e83 | |
![]() |
4c4f4396fe | |
![]() |
e99333113f | |
![]() |
7b63fd6b9f | |
![]() |
20b97286e3 | |
![]() |
3a4f6888fb | |
![]() |
da48675900 | |
![]() |
74b84f9f86 | |
![]() |
dbafeb5cee | |
![]() |
5ce3b4cea4 | |
|
3f7366fbcd | |
|
cfdbc5a682 | |
|
9b880e3209 | |
|
c2ef23b746 | |
|
8a33ea6707 | |
|
9ee4c85b7c | |
![]() |
97da0f908f | |
![]() |
3ea9f0017d | |
|
8da237e5b9 | |
|
e9b23d6577 | |
|
64d9c334ce | |
|
d832939038 | |
|
c0e1ed9d12 | |
|
cad7e24299 | |
|
2a9448517c | |
|
5e5fb6e122 | |
|
3b15dd84fc | |
|
2bf84c0d5e | |
|
58a43a8b80 | |
|
e25231738a | |
|
35965f542a | |
|
fa48e3f5ca | |
|
e4e0564228 | |
|
13e2738fb5 | |
![]() |
e5f95fa9b5 | |
![]() |
4416e8bd4f | |
![]() |
5391c97873 | |
|
b5df0bb93b | |
|
30437d828c | |
|
dcc7ab6738 | |
|
57a7a17f73 | |
|
5196f33f24 | |
![]() |
480f2b6516 | |
![]() |
ee3cacb6c8 | |
![]() |
b3cbed2963 | |
![]() |
dd1af6712c | |
![]() |
fc37f18022 | |
![]() |
bab6efb23d | |
![]() |
c20599d742 | |
![]() |
817b8d3650 | |
|
8807be6e4d | |
|
8d41c27044 | |
|
53fe554d1e | |
![]() |
4e02dbe06b | |
![]() |
620ddff9bb | |
![]() |
54bd088ae5 | |
![]() |
2af3671811 | |
|
630a7aadeb | |
|
6383384287 | |
|
83f1263f85 | |
|
e4158d7d3a | |
|
d328108d9e | |
|
304fd72f27 | |
![]() |
9e62d959fc | |
![]() |
63b349c9f3 | |
![]() |
538d0f7d0f | |
![]() |
edc0d16c52 | |
![]() |
548a983a7a | |
![]() |
1852070f5b | |
![]() |
433e94de3c | |
![]() |
9362201452 | |
![]() |
b416b12914 | |
|
89f57fa4fc | |
|
9c11cd79e8 | |
![]() |
86b5d9cb20 | |
![]() |
ca33c77ff1 | |
![]() |
9464aadd95 | |
![]() |
803c468a80 | |
![]() |
46c57186b4 | |
![]() |
2e116548db | |
![]() |
3777fa26a0 | |
![]() |
65b12bb93a | |
![]() |
4e4f68bd2c | |
![]() |
22983c518e | |
![]() |
b075fdc3c1 | |
![]() |
4c450a6bbc | |
![]() |
16205927d8 | |
![]() |
d446fecbef | |
![]() |
1c1450a9a4 | |
![]() |
56921a1801 | |
![]() |
f0be159722 | |
|
a7384bc1c3 | |
![]() |
4b4dfc17e1 | |
![]() |
997ab5a8f8 | |
|
e11a5c0848 | |
|
f1df84d725 | |
|
26bac63c8e | |
|
9263676f01 | |
![]() |
4ab868acc5 | |
![]() |
127a4c6998 | |
![]() |
026916abb1 | |
![]() |
dc0c493970 | |
![]() |
a77f070f69 | |
![]() |
6cf7b86cc4 | |
![]() |
328e6d1192 | |
![]() |
3fb184e3cc | |
|
55170c7693 | |
![]() |
6b5d19916b | |
![]() |
c086eb5f83 | |
|
2cde13eabb | |
|
d68e7f38a3 | |
|
2fd6d3619c | |
![]() |
1fb0b27630 | |
![]() |
3abd2c13e9 | |
|
649d9c4ea6 | |
![]() |
ca57477dcb | |
![]() |
043e1b5237 | |
![]() |
bcc2579910 | |
![]() |
3836270622 | |
![]() |
b7c3c7c5eb | |
![]() |
15d4336c00 | |
![]() |
c367eaca10 | |
![]() |
9fbbd9805f | |
![]() |
095e1c7b7b | |
![]() |
d401634af3 | |
![]() |
14022c0ccc | |
![]() |
95303c5394 | |
![]() |
1701890e1a | |
![]() |
63f8ca06df | |
![]() |
a74335fd12 | |
![]() |
497342bcff | |
![]() |
0f6ebbbf2f | |
![]() |
cb302b50dd | |
![]() |
a8cf9b21c8 | |
![]() |
60eebead05 | |
![]() |
fce8166ba7 | |
![]() |
81d29d3809 | |
![]() |
b0e6f2bcd3 | |
![]() |
c44755f8d7 | |
![]() |
f5f74f7333 | |
![]() |
ae0efc1115 | |
![]() |
dfc2edd62d | |
![]() |
84de681777 | |
![]() |
260737f417 | |
|
d7f3a21add | |
![]() |
fd07a8c6ae | |
|
ef9592ef30 | |
![]() |
f072a2a7f3 | |
|
cc42683316 | |
![]() |
8d28b41357 | |
![]() |
a247d5fc7a | |
![]() |
3d9aeef8b4 | |
![]() |
2790f91f1b | |
![]() |
dfe884ec47 | |
![]() |
da28624c0a | |
![]() |
05ca426004 | |
|
70f1e6827f | |
|
b5188e3272 | |
|
ff881732d2 | |
![]() |
0373d08fdc | |
![]() |
3ef6ed306f | |
![]() |
9ab130f81e | |
![]() |
20790f7548 | |
![]() |
2adf87a289 | |
![]() |
6954a860af | |
![]() |
bb8e6aeaf8 | |
![]() |
b38daf634f | |
![]() |
6d7b7dd058 | |
![]() |
ec0358d6b2 | |
![]() |
03075b8d48 | |
![]() |
6b67344493 | |
![]() |
ede998ebef | |
![]() |
fba7c7f8b9 | |
![]() |
4e29cabdef | |
![]() |
199240962a | |
![]() |
8608e2d67a | |
![]() |
acaea1901d | |
![]() |
28d2bbe9a1 | |
![]() |
a954081f74 | |
|
c12f49a987 | |
![]() |
180fd51395 | |
![]() |
4a566bb0f4 | |
![]() |
3f1803b2e5 | |
![]() |
ddeea66dc1 | |
![]() |
1f6fa921e8 | |
![]() |
f780d3a91e | |
![]() |
f2d652fafe | |
![]() |
369e87ab92 | |
![]() |
9850adfdb5 | |
|
007b90c284 | |
|
481d1b7db0 | |
|
733f64eaec | |
|
383660c778 | |
![]() |
5674800c97 | |
![]() |
2609908d6b | |
![]() |
2352e1a677 | |
![]() |
618d4ad995 | |
![]() |
32823ce9f9 | |
|
daa098abf2 | |
|
0cfe16a8d3 | |
![]() |
80ec837964 | |
![]() |
090d76ad69 | |
![]() |
517d84c3bd | |
![]() |
851577ea7c | |
![]() |
8fdb2df0ef | |
![]() |
12c91ca680 | |
![]() |
d3967f25ad | |
|
9509dc5af2 | |
|
cd39370fe5 | |
|
4ed846a68b | |
|
f22ffcb7c4 | |
|
bd5ffae6ad | |
|
708d66361c | |
|
f997a8a101 | |
|
17cf3b6c87 | |
|
1ae1188421 | |
|
ed84b387d5 | |
|
4bab6d1876 | |
![]() |
35b4fa0e94 | |
![]() |
3b4d84fef9 | |
|
8168329ba9 | |
|
89ab25974d | |
![]() |
e8ce1e46d4 | |
![]() |
2e046f313f | |
![]() |
63c40a2025 | |
|
4bd77a870b | |
|
4ca4bcac02 | |
|
3350b80e92 | |
|
b1f460d760 | |
![]() |
eaa0364e97 | |
![]() |
f2b7ae2f22 | |
![]() |
3ec44cbfa3 | |
|
1ca3db70b8 | |
![]() |
1193acc3a9 | |
![]() |
640094def7 | |
![]() |
6c0bd6a6fe | |
![]() |
f3b78cb40d | |
|
a438ab6f3e | |
![]() |
f5ebe5c5f1 | |
![]() |
ba97339821 | |
![]() |
240e2b22ab | |
![]() |
fef03e6d22 | |
![]() |
c42fa03b8b | |
![]() |
783474cbd9 | |
![]() |
ed909f620d | |
![]() |
3a34d8682c | |
![]() |
60894f00b1 | |
![]() |
925b05e004 | |
![]() |
9b465dd6cb | |
|
4878d66620 | |
|
632ade9d25 | |
|
5acd45bf85 | |
|
d03b45eecf | |
|
0193381d1f | |
![]() |
32a9d762d8 | |
![]() |
0a79950046 | |
![]() |
4b7c58b13f | |
![]() |
7148957368 | |
|
aa50c50254 | |
|
60b3c7925d | |
|
0f41cabe71 | |
![]() |
d04ed7e008 | |
![]() |
c6b35d83d3 | |
![]() |
8776f48f62 | |
![]() |
197c70927d | |
![]() |
8ac0c1fcd1 | |
![]() |
fc5aff287f | |
![]() |
82835969be | |
![]() |
b5409fa7e5 | |
![]() |
3303d801ea | |
|
6168256897 | |
|
62c5345889 | |
|
e8b8dc682a | |
|
73f41d555c | |
![]() |
6eadacb3f0 | |
|
4b167dacbb | |
|
911c47df8d | |
|
a37d7b9840 | |
![]() |
217ab920a9 | |
![]() |
98ae62d181 | |
![]() |
98f1723411 | |
|
68a38e75bc | |
|
ee29c6be5c | |
|
c0ee0a694c | |
![]() |
25fa6f427b | |
![]() |
467d722d25 | |
![]() |
f552fef4e2 | |
|
3e352d3c7c | |
![]() |
fbdb4cbf39 | |
|
13472b2311 | |
![]() |
bdddd655bf | |
![]() |
6ec7a13293 | |
![]() |
716b29c25f | |
![]() |
5c4930a362 | |
![]() |
ad8fed9440 | |
![]() |
964bef7896 | |
![]() |
7e48e5e8b8 | |
![]() |
48846a7e31 | |
|
32db15aad5 | |
![]() |
8ec3e4bbaa | |
|
4b05838498 | |
![]() |
2fe5fc369c | |
|
b8be0c23cb | |
|
d20a7b1318 | |
|
f8268accc0 | |
|
a9811768d4 | |
|
024bc289de | |
|
96d34d0237 | |
|
fea11bdc2e | |
![]() |
d0a164434c | |
|
ab5d273f98 | |
![]() |
8bf4e9b8d2 | |
|
096b0b954d | |
|
df57312056 | |
![]() |
59b256dd78 | |
![]() |
cfadde830f | |
![]() |
f12cfabee3 | |
![]() |
350783b833 | |
![]() |
b22909a654 | |
![]() |
579b45dfa4 | |
![]() |
fbc1f95cd1 | |
![]() |
4ccf8ea5ff | |
![]() |
45a2661f99 | |
![]() |
2d306e20fb | |
![]() |
f306a5008f | |
![]() |
fc064a53d1 | |
![]() |
dc6e62b784 | |
![]() |
20b8a6c005 | |
|
d5c141f892 | |
![]() |
e467794901 | |
![]() |
e098216af8 | |
![]() |
809cce9085 | |
|
35c6cb98db | |
|
f417e42864 | |
|
6e54203ebb | |
![]() |
79a6841bbc | |
![]() |
b3d78741a3 | |
![]() |
91884b9d2d | |
![]() |
6182405108 | |
![]() |
35336701fa | |
![]() |
ac82e14eba | |
|
935f3ddf7f | |
![]() |
5ca2cc69ac | |
|
a2549f7ff1 | |
![]() |
0a87973e71 | |
![]() |
a6099973d7 | |
![]() |
8b6ae143c0 | |
![]() |
862186a8f2 | |
![]() |
fcfd64f353 | |
![]() |
755c1f9492 | |
![]() |
f85e50a5f0 | |
![]() |
0f0d348d9f | |
|
d6b5dc326a | |
![]() |
53b6ffb15a | |
![]() |
380ef5e057 | |
![]() |
e69f9263b2 | |
![]() |
003bfe7884 | |
![]() |
df5efa0dc6 | |
|
a35db9fe80 | |
|
6183f1f76d | |
|
e72273f3b2 | |
|
cc09f724cc | |
|
7a54c5f536 | |
![]() |
bb3f5cec76 | |
![]() |
19ffd9fea1 | |
![]() |
5877474f59 | |
![]() |
1bbde165c2 | |
|
3f5754a3a5 | |
|
5463c22518 | |
|
5db43bf768 | |
|
1feb166fd5 | |
|
0df1e5fdd0 | |
|
8ba70a33be | |
![]() |
b21f44b59e | |
![]() |
92a310c916 | |
![]() |
42815c0812 | |
![]() |
231bf39283 | |
|
7793eacf75 | |
|
25afedcdfd | |
|
d95a689815 | |
|
b386dc51e4 | |
|
1882120df3 | |
|
274cd81655 | |
|
6273349334 | |
|
e8deb83004 | |
|
52701d1c2f | |
|
b248f770f1 | |
|
04b9e43382 | |
|
3580a8653d | |
|
d9653e461e | |
|
d9a1d32ec8 | |
|
b5dfd83527 | |
|
df7b91a8ba | |
|
8dae15225e | |
|
5fcf789e63 | |
|
ed0655452c | |
|
0dd062ce1c | |
|
bd3cbf33fd | |
|
b8d4b15b40 | |
|
24d83133e7 | |
|
4ed3a9d478 | |
|
0f5fd424fb | |
|
fbbacfa983 | |
|
169ec9e0b0 | |
|
a95ac23c49 | |
|
30acbec322 | |
|
08292d86ee | |
|
158ba9707d | |
|
d0988e42b4 | |
|
73b5c0f63f | |
|
d154f0aecc | |
|
29d9410e42 | |
|
dbae651abc | |
|
3b62f09669 | |
|
5864352049 | |
|
1d6d48fc94 | |
|
484c91a581 | |
|
aabb7518c0 | |
|
de2afba910 | |
|
a465e8de66 | |
|
e4a79a4049 | |
|
fa1e858a97 | |
|
2080d44bdb | |
|
97c1da579e | |
|
5ab66e0c40 | |
|
b1b7b6a1e0 | |
|
16f2aecb6d | |
|
a583d3156a | |
|
4ca5d4b234 | |
|
77a8e75e87 | |
|
7b91ad37e5 | |
|
9dbb9a42d6 | |
|
09f9f138f0 | |
|
f8aa5ddb00 | |
|
18d65c169c | |
|
3b3cd46b76 | |
|
a608803aa8 | |
|
76cc185a1d | |
|
10f8ff28e1 | |
|
25a686e4f3 | |
|
e76503ae26 | |
|
50991f503f | |
|
acd031ca7d | |
|
b59b76be4a | |
|
211581cef0 | |
|
7cad953413 | |
|
fe58175ee0 | |
|
5d0849a148 | |
|
d14bf35ca1 | |
|
9a5ce74d98 | |
|
d7dd3901b8 | |
|
aefd6c08dc | |
|
3c2c742121 | |
|
9221e55752 | |
|
44db7c48f9 | |
|
861a84d8ec | |
|
d496e1c01e | |
|
e4b2563780 | |
|
944fb3b89e | |
|
ba1fa8b685 | |
|
29e3a55a0c | |
|
c426467a68 | |
|
9fe8df3c1b | |
|
531495429c | |
|
bed2469014 | |
|
45b7f70d9f | |
|
1ebb6cb561 | |
|
21ccedab9c | |
|
8f45bcf959 | |
|
1f9caeece5 | |
|
5b4e6f4902 | |
|
3d0e323801 | |
|
f6fb50529c | |
|
c42f3d5928 | |
|
42d2b51f7f | |
|
66c40d4791 | |
|
ce467736a7 | |
|
3e4dd90e17 | |
|
8ae5587516 | |
|
0b543f7dda | |
|
a07204111a | |
|
d243fff299 | |
|
038df804c0 | |
|
877948b0cd | |
|
9a17c4865f | |
|
9427db3e5a | |
|
81da71d478 | |
|
169dc84e22 | |
|
d6fd85f536 | |
|
6448a30e03 | |
|
17fb43cea8 | |
|
a6e50d2a25 | |
|
bd16ca476d | |
|
7ddb59800d | |
|
2ea78b4f20 | |
|
e36c7a4b6a | |
|
8e8ec821f2 | |
|
cedaeda60c | |
|
5cf257c3cc | |
|
aa18fe0ad4 | |
|
1358c23ca6 | |
|
c27cc063e6 | |
|
b0092487e6 | |
|
555df176cc | |
|
fbebd0a623 | |
|
fe23c2afbf | |
|
779c86108a | |
|
83e43f0c97 | |
|
20f892a4f0 | |
|
f77dcd3b30 | |
|
701c05c39e | |
|
853c33cb24 | |
|
0bd8c19a87 | |
|
c2171eab9b | |
|
72fb2738db | |
|
1cb406e1e8 | |
|
5b33da0aa5 | |
|
ca78b04f6e | |
|
f93c1dff0b | |
|
e237fd46f7 | |
|
ca3c564529 | |
|
ef33193f01 | |
|
b648774b42 | |
|
9cd18397f7 | |
|
0ffb919242 | |
|
6d4fb8df34 | |
|
d9c1c3d3a2 | |
|
083a839bf5 | |
|
551edde13d | |
|
768f9a7847 | |
|
a8adf6f140 | |
|
77620f7735 | |
|
59cd230658 | |
|
79a6cea623 | |
|
45fdf9bb59 | |
|
50dc5cce5d | |
|
a6cee63d17 | |
|
000197b0d1 | |
|
6aa3321d17 | |
|
d44308fc82 | |
|
ae7d0d1329 | |
|
dc7c326ffe | |
|
f560723d5a | |
|
55c74de8e4 | |
|
7c88ea3d67 | |
|
f36dbf9c26 | |
|
29f6950e7c | |
|
cf164ff5f8 | |
|
d6f9530637 | |
|
f15cd44dff | |
|
babdec4788 | |
|
8731506992 | |
|
d90ab310cc | |
|
f0e2277f1c | |
|
88a9194aca | |
|
53dcd9de71 | |
|
6c68a51091 | |
|
3abd6037d9 | |
|
ec3a556a6f | |
|
793cbb372a | |
|
396ac55429 | |
|
97507c2203 | |
|
50db13a7ef | |
|
8115858c47 | |
|
357cd6d628 | |
|
20a69528fa | |
|
a5021df2ac | |
|
703c2c5bad | |
|
2d067f0a18 | |
|
0b34f49ea7 | |
|
088c617cc1 | |
|
2a2c8361b8 | |
|
8a3be40410 | |
|
8ce75ed2d3 | |
|
8052ae832d | |
|
adc9936566 | |
|
c00a8a67f9 | |
|
854ef5ca45 | |
|
dc43b3542c | |
|
fc3cf01d3f | |
|
8f5bb0e2d9 | |
|
1b8006f438 | |
|
5c123edfaa | |
|
3f94cf3637 | |
|
689a91ab49 | |
|
2dfd69ae21 | |
|
720c073f32 | |
|
0076468a15 | |
|
910ae48556 | |
|
eac7331070 | |
|
551f333261 | |
|
dec264d169 | |
|
7055974443 | |
|
a517d1df68 | |
|
547cf7ce86 | |
|
560adc458c | |
|
6dfffb8a6d | |
|
1c5b42e01b | |
|
85302102d6 | |
|
316fb0ff58 | |
|
d475413fd6 | |
|
cd40efc760 | |
|
76ed52b68a | |
|
3536918938 | |
|
56278b84f2 | |
|
882a50cf56 | |
|
db4031b8bf | |
|
ecfc39565c | |
|
9ced678f91 | |
|
7951ca28d5 | |
|
4bbb843edf | |
|
d1b5ead752 | |
|
972373a277 | |
|
66dead1e6a | |
|
f901ff8920 | |
|
00a4be2879 | |
|
90738a6117 | |
|
dea5a223d1 | |
|
bd88870405 | |
|
9b11bccd42 | |
|
fae11267f7 | |
|
747646cd9d | |
|
f0fc456a1c | |
|
2f06e89b54 | |
|
ae3057d150 | |
|
033865df66 | |
|
7ca13fb387 | |
|
2fb263d6c9 | |
|
fda21d782c | |
|
71836ca3ae | |
|
4dadce904d | |
|
e4ec205890 | |
|
aa9006bfe5 | |
|
00c1486e89 | |
|
f8ef2d48a0 | |
|
0f83639565 | |
|
0607a62b17 | |
|
3f0ded057b | |
|
1e1d07e697 | |
|
a72a0de2b9 | |
|
d0d906d04c | |
|
6079441f8a | |
|
f0bc08cd47 | |
|
39526b091b | |
|
bcd5c6bee0 | |
|
cf0565ddb6 | |
|
c4843da207 | |
|
cb184792cd | |
|
78cee5f7d1 | |
|
b852b8cf08 | |
|
cee09d9f8f | |
|
7ab87df7fc | |
|
78fd1d158f | |
|
9b91557bb6 | |
|
521a1a2c8a | |
|
bc639488aa | |
|
9ca85d8e8d | |
|
64ed6b93c9 | |
|
f9e613f856 | |
|
b508fd6cf4 | |
|
43334935d9 | |
|
958b1618b1 | |
|
99fbecc834 | |
|
e489c57fe8 | |
|
8d0a6d267a | |
|
cd85fea841 | |
|
b1c03ed5e8 | |
|
e9daacc1b2 | |
|
d48009fab6 | |
|
0b93a3a787 | |
|
d4c860bf29 | |
|
ce4aee366a | |
|
747bc4ab45 | |
|
fc3344c78a | |
|
ef12f85687 | |
|
e120c4dac2 | |
|
e1cf2fcdeb | |
|
c4f380873e | |
|
5cb2e55f74 | |
|
1dd3fbc69a | |
|
9b08a09a1b | |
|
01ccbe89cd | |
|
643dedc8cb | |
|
fbd1533a53 | |
|
49d1317d21 | |
|
31d7103da3 | |
|
0b0a57035a | |
|
7449d915ab | |
|
33c0e026fd | |
|
b97c42d0ae | |
|
60245b4558 | |
|
751187a3da | |
|
1bf858c10c | |
|
9e2db8a7f6 | |
|
c575376b44 | |
|
8564930dfc | |
|
8e362e902f | |
|
abf3541201 | |
|
a2612d8009 | |
|
2f2655525f | |
|
ec9f3a3058 | |
|
5d102f9ef4 | |
|
b7914e54f6 | |
|
1a93477635 | |
|
68cc2999ed | |
|
66ca7fd1f0 | |
|
b1c3d62e41 | |
|
a94493ce0d | |
|
c1ea0232bb | |
|
7c664addbd | |
|
c6b79f82bc | |
|
58ca8e2651 | |
|
692d51792a | |
|
fcc827522c | |
|
4e3f9cc019 | |
|
fe08cab2e5 | |
|
5ed7b3e4ad | |
|
2e511655f6 | |
|
4e2c46260c | |
|
9ba00b21c9 | |
|
b11f5fd228 | |
|
90dbe0730a | |
|
d6633cb73a | |
|
a7a6abd22a | |
|
c956667ce0 | |
|
5701c818ed | |
|
1ac2ddfaa5 | |
|
4aac05d4e1 | |
|
84b56bfcb8 | |
|
7485564bb9 | |
|
b5acf2308a | |
|
e3f4313c80 | |
|
b223abe229 | |
|
b3bede308c | |
|
2f170a54c6 | |
|
36c4b32acb | |
|
ada03e45ea | |
|
cad35e3757 | |
|
f38d6bc976 | |
|
22293572ac | |
|
8720cab1e9 | |
|
959c1e8d95 | |
|
3fc62ca1d5 | |
|
29dc3fff39 | |
|
298abdd1b1 | |
|
26f87fba16 | |
|
1e9a32a93e | |
|
2dc79052c2 | |
|
380ca3a066 | |
|
237b0afb08 | |
|
e14936e820 | |
|
655c85851f | |
|
1c7e414aa4 | |
|
099fc52e00 | |
|
490957ec3b | |
|
b1884d30d5 | |
|
87d2cc3e25 | |
|
98d8ee1fb6 | |
|
2ca77732c8 | |
|
c5063e513d | |
|
63e50e36ac | |
|
dca4ef6a34 | |
|
7a2270956c | |
|
b380afaf5c | |
|
e7af0e2e47 | |
|
04f2dbee9a | |
|
70d22f7c4f | |
|
25d0e784bb | |
|
5d45b24299 | |
|
b6b8befde7 | |
|
f33b9559cd | |
|
f9bc2258ec | |
|
2a09ced1ce | |
|
7a1e6cfbad | |
|
47d1f727ce | |
|
a7665df0ea | |
|
84f12adce8 | |
|
7fde1e0e12 | |
|
499734ebf9 | |
|
f339df699e | |
|
cfd94cb3b7 | |
|
43e0617429 | |
|
d6b66d5324 | |
|
0c1df3b2cb | |
|
fa86d3ea10 | |
|
8c99b754fb | |
|
f3cf2c87c9 | |
|
8e4e6fc0ac | |
|
75f3166ffa | |
|
04bf423fcb | |
|
51e8c9d908 | |
|
4304a35b80 | |
|
076375633a | |
|
dbf5e711a5 | |
|
4432e65683 | |
|
dcf44a78f0 | |
|
74cbca2421 | |
|
01bf13ddd9 | |
|
12edc620df | |
|
4ce03145df | |
|
3e04a37ece | |
|
78f464ccba | |
|
64423f1999 | |
|
05c3f60dab | |
|
0083ef33cb | |
|
36b68df273 | |
|
e1a5918c22 | |
|
26ae9b35df | |
|
8e79b43aaf | |
|
d28eba6423 | |
|
688be1bb7d | |
|
df69dee282 | |
|
45a77e5c07 | |
|
7849bd0ebf | |
|
ea2de5910a | |
|
a5d4799a21 | |
|
335d24bc8b | |
|
e97eacbbf6 | |
|
3649bf1fd0 | |
|
6ffc2938a1 | |
|
aa60de1dac | |
|
29f98513e2 | |
|
e35cdf39fb | |
|
2c17ae096e | |
|
e51b86538b | |
|
da4fd3a762 | |
|
399f6c2a17 | |
|
fb335162fc | |
|
c7b40c1230 | |
|
293121ab91 | |
|
efc82b9841 | |
|
e3df503dd2 | |
|
6a2ad67386 | |
|
3d12db3a07 | |
|
1faaf1d7d1 | |
|
f8a6f62342 | |
|
66d1246a6c | |
|
f79beef3f9 | |
|
43cccc5429 | |
|
81e6691632 | |
|
38d6519381 | |
|
16418675ac | |
|
102858bc8c | |
|
0d64768e4b | |
|
beccac652f | |
|
30eb1958c1 | |
|
33e17e8439 | |
|
e0c47c2abd | |
|
422549f9e7 | |
|
0358229b95 | |
|
c4586fbb36 | |
|
f94006abfd | |
|
4d61e7618a | |
|
36286d9003 | |
|
51356da7f3 | |
|
ebe893022f | |
|
c5f22e6c70 | |
|
fcc5429bbd | |
|
1f8f2abcf6 | |
|
a2140574cd | |
|
ab47dd0524 | |
|
4310cc9f26 | |
|
9648afb0bb | |
|
557b6ccc13 | |
|
d94b3ff2f4 | |
|
4a7878d16e | |
|
0a00a4bc0e | |
|
b81d92af46 | |
|
922561afb1 | |
|
6f7899d16f | |
|
4e3c8e414c | |
|
d588a78f62 | |
|
a7d681c4dd | |
|
7a93db9ed2 | |
|
74e5fa0e31 | |
|
de995c8714 | |
|
ea156cec7e | |
|
7499d8af89 | |
|
f8654edc3b | |
|
d16f290aa6 | |
|
9385d346f1 | |
|
22f3371090 | |
|
c0a4f8f4ec | |
|
7586a0fb21 | |
|
c0e3a91a46 | |
|
7ebd8681fa | |
|
72553dec57 | |
|
dee68808b1 | |
|
96d7917bbf | |
|
abca0fe432 | |
|
d7612a0921 | |
|
c54950a95f | |
|
be0f68cede | |
|
1b92b53099 | |
|
5634413cac | |
|
1a9ed1425e | |
|
f9d4316a8e | |
|
6f7f815fd4 | |
|
ddb826733b | |
|
1f989d0a37 | |
|
d63626424e | |
|
55ab694505 | |
|
0885575cc4 | |
|
a188648287 | |
|
8011dabaac | |
|
88a08e73c0 | |
|
6713f9b280 | |
![]() |
ef6f2c7b42 | |
![]() |
689b24da8f | |
![]() |
369877da5f | |
![]() |
96c67d359e | |
![]() |
3e633ea6cc | |
![]() |
4fe3f88de6 | |
![]() |
a5fd87a475 | |
![]() |
e8bbc7d856 | |
![]() |
9a0d7aa02a | |
![]() |
25e1bf1565 | |
![]() |
574f6561d1 | |
![]() |
eaddf52cbd | |
![]() |
ef0a0e5ddd | |
![]() |
ef81d61a0d | |
![]() |
071f913123 | |
![]() |
6096fdd7bf | |
![]() |
9ba297ccf6 | |
![]() |
66fd6a71e5 | |
![]() |
89bc20e540 | |
![]() |
184a6bf1bf | |
![]() |
8ee089b82d | |
![]() |
abc21413ac | |
|
ce89ce5169 | |
|
b8a4c467fe | |
|
300658f8dd | |
|
9553740960 | |
|
1a8d9bb0ce | |
|
8c43f74b69 | |
|
3e7ae82258 | |
|
0aa75e077e | |
|
8aefcad510 | |
|
622dcbaf4f | |
![]() |
6570125a36 | |
![]() |
d91e8dcbfe | |
![]() |
0c2507b1e9 | |
|
8d29c2bd50 | |
|
774f632d9a | |
|
2969afd333 | |
|
cc978c8dea | |
|
ce105b4c07 | |
|
b5870b1020 | |
|
1edb3ce7ad | |
![]() |
59257b1caa | |
![]() |
b552e29aa3 | |
![]() |
21424a23f2 | |
![]() |
a82af669bd | |
![]() |
0f01abd45f | |
|
80002be670 | |
![]() |
f7e19cb3a4 | |
![]() |
5cd6620413 | |
![]() |
f3a9124bdd | |
![]() |
d97a39a3a2 | |
![]() |
987ff74690 | |
![]() |
37be604e82 | |
|
83e2c1f889 | |
|
46a1c8877b | |
![]() |
0aa39efe9b | |
![]() |
15d562d7b1 | |
![]() |
5b261d6e81 | |
|
4693e77e02 | |
|
fbf22ff0df | |
![]() |
0794f77a87 | |
![]() |
e5a46a242f | |
![]() |
4902237bd7 | |
![]() |
4ddc60a1c3 | |
|
cfa14fff9d | |
|
ef327f2994 | |
|
bf91c5e382 | |
|
9b687f7885 | |
|
a072162324 | |
|
8f1e0f39ea | |
|
aaa6483958 | |
![]() |
bf730ca18f | |
![]() |
132af875bc | |
|
a862d994ab | |
![]() |
604da93c5c | |
![]() |
3f525f5779 | |
|
05d1e66ea9 | |
|
10c1cccf2c | |
|
27ec7ec7dd | |
![]() |
43b4907565 | |
![]() |
cb90e1a13f | |
|
749cd058c4 | |
|
47cc70f2c5 | |
|
5447d54d30 | |
|
6c436dd631 | |
|
9eb7219b9a | |
|
ad5fcb25c4 | |
|
d42053ce0c | |
|
36bae71947 | |
![]() |
837aa1ea9e | |
|
c283c7ed58 | |
|
4cf8588343 | |
|
e75fad98f8 | |
|
bc37c59f00 | |
|
a6a745da93 | |
|
5bef80ee58 | |
|
f9bcc7e02b | |
|
d35faf3935 | |
|
8d7dc9cb60 | |
|
248d78d8c1 | |
|
f632424f13 | |
|
95ede63220 | |
|
8fac294d04 | |
|
d67c12beba | |
|
a7e4b85352 | |
![]() |
2ac2920399 | |
![]() |
230b934de4 | |
|
e0bedf175f | |
|
c9a263e03c | |
![]() |
2bd15d9746 | |
|
fc9588fb63 | |
|
e611b519ab | |
|
3dd3944ebd | |
|
f417bf3308 | |
|
9c7c914d12 | |
|
b088befae7 | |
|
d3636e686b | |
|
88d98f0ac4 | |
|
db6aa954b1 | |
|
04a611a4aa | |
|
9ecea83506 | |
|
82a9907fdc | |
|
c56c98fd6e | |
|
2948ad2033 | |
|
fc611140cf | |
|
fcb5f58b69 | |
|
0f38a130f3 | |
|
fc54632a08 | |
|
5963af5c7b | |
|
c1f2f7f6e2 | |
|
271699daf1 | |
|
98da7ea34d | |
|
645e4a3586 | |
|
7beca24a05 | |
|
d1368c7612 | |
|
28e762810e | |
|
0f60d0adc9 | |
|
e634317675 | |
|
6b1a0a96c6 | |
|
298859bd10 | |
|
d4d412ab40 | |
|
57d1a1474e | |
|
055b7dbac5 | |
|
30aad87e5a | |
|
aecd68fe9a | |
|
998a6828d9 | |
|
12c04d02e5 | |
|
d6ef3d8aa3 | |
|
c7a89d1660 | |
|
1939c0d33f | |
![]() |
561b9efd92 | |
![]() |
6c0b87fdd1 | |
![]() |
5d309d1dc4 | |
![]() |
89c230c362 | |
![]() |
d4156a5582 | |
![]() |
ee8cbb8553 |
|
@ -23,7 +23,7 @@
|
|||
* Fix 版本库中附件下载400(#51625)
|
||||
* Fix loading页面优化(#51588)
|
||||
* Fix 提交详情页面优化(#51577)
|
||||
* Fix 修复易修复制功能(#51569)
|
||||
* Fix 修复疑修复制功能(#51569)
|
||||
* Fix 修复新建发行版用户信息显示错误的问题(#51665)
|
||||
* Fix 修复查看文件详细信息报错的问题(#51561)
|
||||
* Fix 修复提交记录中时间显示格式问题(#51526)
|
||||
|
@ -62,7 +62,7 @@
|
|||
## [v3.0.3](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-05-08
|
||||
|
||||
* BUGFIXES
|
||||
* Fix 解决易修标题过长导致的排版问题(45469)
|
||||
* Fix 解决疑修标题过长导致的排版问题(45469)
|
||||
* Fix 解决合并请求详情页面排版错误的问题(45457)
|
||||
* FIX 解决转移仓库界面专有名词描述错误的问题(45455)
|
||||
* Fix 解决markdown格式文件自动生成数字排序的问题(45454)
|
||||
|
|
273
Gemfile
273
Gemfile
|
@ -1,130 +1,143 @@
|
|||
source 'https://gems.ruby-china.com'
|
||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
|
||||
gem 'rails', '~> 5.2.0'
|
||||
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
|
||||
gem 'puma', '~> 3.11'
|
||||
gem 'sass-rails', '~> 5.0'
|
||||
gem 'uglifier', '>= 1.3.0'
|
||||
|
||||
# gem 'coffee-rails', '~> 4.2'
|
||||
gem 'turbolinks', '~> 5'
|
||||
gem 'jbuilder', '~> 2.5'
|
||||
gem 'groupdate', '~> 4.1.0'
|
||||
gem 'chartkick'
|
||||
gem 'grape-entity', '~> 0.7.1'
|
||||
gem 'kaminari', '~> 1.1', '>= 1.1.1'
|
||||
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
|
||||
gem 'chinese_pinyin'
|
||||
|
||||
gem 'rack-cors'
|
||||
gem 'redis-rails'
|
||||
gem 'roo-xls'
|
||||
gem 'simple_xlsx_reader'
|
||||
|
||||
gem 'rubyzip'
|
||||
|
||||
gem 'spreadsheet'
|
||||
gem 'ruby-ole'
|
||||
# 导出为xlsx
|
||||
gem 'axlsx', '~> 3.0.0.pre'
|
||||
gem 'axlsx_rails', '~> 0.5.2'
|
||||
|
||||
gem 'oauth2'
|
||||
#导出为pdf
|
||||
gem 'pdfkit'
|
||||
gem 'wkhtmltopdf-binary'
|
||||
# gem 'request_store'
|
||||
#gem 'iconv'
|
||||
# markdown 转html
|
||||
gem 'redcarpet', '~> 3.4'
|
||||
|
||||
gem 'rqrcode', '~> 0.10.1'
|
||||
gem 'rqrcode_png'
|
||||
|
||||
gem 'acts-as-taggable-on', '~> 6.0'
|
||||
|
||||
# a tree structure
|
||||
gem 'ancestry'
|
||||
gem 'acts_as_list'
|
||||
gem 'omniauth-cas'
|
||||
|
||||
# profiler Middleware
|
||||
gem 'rack-mini-profiler'
|
||||
|
||||
# object-based searching
|
||||
gem 'ransack'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '~> 3.8'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'prettier'
|
||||
gem 'rubocop', '~> 0.52.0'
|
||||
gem 'solargraph', '~> 0.38.0'
|
||||
gem 'awesome_print'
|
||||
gem 'web-console', '>= 3.3.0'
|
||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||
gem 'spring'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
gem "annotate", "~> 2.6.0"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '>= 2.15', '< 4.0'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'chromedriver-helper'
|
||||
end
|
||||
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
||||
|
||||
#编码检测
|
||||
gem 'rchardet', '~> 1.8'
|
||||
|
||||
# http client
|
||||
gem 'faraday', '~> 0.15.4'
|
||||
|
||||
# view
|
||||
gem 'active_decorator'
|
||||
gem 'bootstrap', '~> 4.3.1'
|
||||
gem 'jquery-rails'
|
||||
gem 'simple_form'
|
||||
gem 'font-awesome-sass', '4.7.0'
|
||||
|
||||
# i18n
|
||||
gem 'rails-i18n', '~> 5.1'
|
||||
|
||||
# job
|
||||
gem 'sidekiq'
|
||||
gem 'sinatra'
|
||||
gem "sidekiq-cron", "~> 1.1"
|
||||
|
||||
# batch insert
|
||||
gem 'bulk_insert'
|
||||
|
||||
# elasticsearch
|
||||
gem 'searchkick'
|
||||
|
||||
gem 'aasm'
|
||||
gem 'enumerize'
|
||||
|
||||
gem 'diffy'
|
||||
|
||||
gem 'deep_cloneable', '~> 3.0.0'
|
||||
|
||||
# oauth2
|
||||
gem 'omniauth', '~> 1.9.0'
|
||||
gem 'omniauth-oauth2', '~> 1.6.0'
|
||||
|
||||
# global var
|
||||
gem 'request_store'
|
||||
|
||||
# 敏感词汇
|
||||
gem 'harmonious_dictionary', '~> 0.0.1'
|
||||
|
||||
gem 'parallel', '~> 1.19', '>= 1.19.1'
|
||||
|
||||
gem 'letter_avatar'
|
||||
#source 'https://gems.ruby-china.com'
|
||||
source 'https://mirrors.cloud.tencent.com/rubygems/'
|
||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
|
||||
gem 'rails', '~> 5.2.0'
|
||||
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
|
||||
gem 'puma', '~> 3.11'
|
||||
gem 'sass-rails', '~> 5.0'
|
||||
gem 'uglifier', '>= 1.3.0'
|
||||
|
||||
# gem 'coffee-rails', '~> 4.2'
|
||||
gem 'turbolinks', '~> 5'
|
||||
gem 'jbuilder', '~> 2.5'
|
||||
gem 'groupdate', '~> 4.1.0'
|
||||
gem 'chartkick'
|
||||
gem 'grape-entity', '~> 0.7.1'
|
||||
gem 'kaminari', '~> 1.1', '>= 1.1.1'
|
||||
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
|
||||
gem 'chinese_pinyin'
|
||||
|
||||
gem 'rack-cors'
|
||||
gem 'redis-rails'
|
||||
gem 'roo-xls'
|
||||
gem 'simple_xlsx_reader', '~>1.0.4'
|
||||
|
||||
gem 'rubyzip'
|
||||
|
||||
gem 'spreadsheet'
|
||||
gem 'ruby-ole'
|
||||
# 导出为xlsx
|
||||
gem 'axlsx', '~> 3.0.0.pre'
|
||||
gem 'axlsx_rails', '~> 0.5.2'
|
||||
|
||||
gem 'oauth2'
|
||||
#导出为pdf
|
||||
gem 'pdfkit'
|
||||
gem 'wkhtmltopdf-binary'
|
||||
# gem 'request_store'
|
||||
#gem 'iconv'
|
||||
# markdown 转html
|
||||
gem 'redcarpet', '~> 3.4'
|
||||
|
||||
gem 'rqrcode', '~> 0.10.1'
|
||||
gem 'rqrcode_png'
|
||||
|
||||
gem 'acts-as-taggable-on', '~> 6.0'
|
||||
|
||||
# a tree structure
|
||||
gem 'ancestry'
|
||||
gem 'acts_as_list'
|
||||
gem 'omniauth-cas'
|
||||
|
||||
# profiler Middleware
|
||||
# gem 'rack-mini-profiler'
|
||||
|
||||
# object-based searching
|
||||
gem 'ransack'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '~> 3.8'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'prettier'
|
||||
gem 'rubocop', '~> 0.52.0'
|
||||
gem 'solargraph', '~> 0.38.0'
|
||||
gem 'awesome_print'
|
||||
gem 'web-console', '>= 3.3.0'
|
||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||
gem 'spring'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
gem "annotate", "~> 2.6.0"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '>= 2.15', '< 4.0'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'chromedriver-helper'
|
||||
end
|
||||
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
||||
|
||||
#编码检测
|
||||
gem 'rchardet', '~> 1.8'
|
||||
|
||||
# http client
|
||||
gem 'faraday', '~> 0.15.4'
|
||||
|
||||
# view
|
||||
gem 'active_decorator'
|
||||
gem 'bootstrap', '~> 4.3.1'
|
||||
gem 'jquery-rails'
|
||||
gem 'simple_form'
|
||||
gem 'font-awesome-sass', '4.7.0'
|
||||
|
||||
# i18n
|
||||
gem 'rails-i18n', '~> 5.1'
|
||||
|
||||
# job
|
||||
gem 'sidekiq'
|
||||
gem 'sinatra'
|
||||
gem "sidekiq-cron", "~> 1.1"
|
||||
|
||||
# batch insert
|
||||
gem 'bulk_insert'
|
||||
|
||||
# elasticsearch
|
||||
gem 'searchkick'
|
||||
|
||||
gem 'aasm'
|
||||
gem 'enumerize'
|
||||
|
||||
gem 'diffy'
|
||||
|
||||
gem 'deep_cloneable', '~> 3.0.0'
|
||||
|
||||
# oauth2
|
||||
gem 'omniauth', '~> 1.9.0'
|
||||
gem 'omniauth-oauth2', '~> 1.6.0'
|
||||
gem "omniauth-github"
|
||||
gem "omniauth-rails_csrf_protection"
|
||||
gem 'omniauth-gitee', '~> 1.0.0'
|
||||
gem "omniauth-wechat-oauth2"
|
||||
|
||||
# global var
|
||||
gem 'request_store'
|
||||
|
||||
# 敏感词汇
|
||||
gem 'harmonious_dictionary', '~> 0.0.1'
|
||||
|
||||
gem 'parallel', '~> 1.19', '>= 1.19.1'
|
||||
|
||||
gem 'letter_avatar'
|
||||
|
||||
gem 'jwt'
|
||||
|
||||
gem 'doorkeeper'
|
||||
|
||||
gem 'doorkeeper-jwt'
|
||||
|
||||
gem 'gitea-client', '~> 0.11.1'
|
|
@ -106,6 +106,10 @@ GEM
|
|||
activerecord (>= 3.1.0, < 7)
|
||||
diff-lcs (1.3)
|
||||
diffy (3.3.0)
|
||||
doorkeeper (5.5.1)
|
||||
railties (>= 5)
|
||||
doorkeeper-jwt (0.4.1)
|
||||
jwt (>= 2.1)
|
||||
e2mmap (0.1.0)
|
||||
elasticsearch (7.5.0)
|
||||
elasticsearch-api (= 7.5.0)
|
||||
|
@ -450,6 +454,8 @@ DEPENDENCIES
|
|||
chromedriver-helper
|
||||
deep_cloneable (~> 3.0.0)
|
||||
diffy
|
||||
doorkeeper
|
||||
doorkeeper-jwt
|
||||
enumerize
|
||||
faraday (~> 0.15.4)
|
||||
font-awesome-sass (= 4.7.0)
|
||||
|
@ -458,6 +464,7 @@ DEPENDENCIES
|
|||
harmonious_dictionary (~> 0.0.1)
|
||||
jbuilder (~> 2.5)
|
||||
jquery-rails
|
||||
jwt
|
||||
kaminari (~> 1.1, >= 1.1.1)
|
||||
letter_avatar
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
|
|
218
api_document.md
218
api_document.md
|
@ -329,6 +329,7 @@ http://localhost:3000/api/licenses/ | jq
|
|||
|licenses|array |返回数据|
|
||||
|-- id |int |id |
|
||||
|-- name |string|开源许可证名称|
|
||||
|-- is_secret |string|是否为特殊许可证|
|
||||
|
||||
|
||||
返回值
|
||||
|
@ -337,23 +338,33 @@ http://localhost:3000/api/licenses/ | jq
|
|||
"licenses": [
|
||||
{
|
||||
"id": 57,
|
||||
"name": "AFL-1.2"
|
||||
"name": "AFL-1.2",
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"name": "AFL-3.0"
|
||||
"name": "AFL-3.0",
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"id": 214,
|
||||
"name": "AFL-1.1"
|
||||
"name": "AFL-1.1",
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"id": 326,
|
||||
"name": "AFL-2.1"
|
||||
"name": "AFL-2.1",
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"id": 350,
|
||||
"name": "AFL-2.0"
|
||||
"name": "AFL-2.0",
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"id": 359,
|
||||
"name": "PHengLEI",
|
||||
"is_secret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -597,6 +608,8 @@ curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq
|
|||
|project_category_id |int|项目类别id|
|
||||
|project_language_id |int|项目语言id|
|
||||
|private |boolean|项目是否私有, true:为私有,false: 公开 |
|
||||
|is_secret |boolean|项目是否为特殊协议项目, true:是,false: 否 |
|
||||
|
||||
|
||||
|
||||
返回值
|
||||
|
@ -609,7 +622,8 @@ curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq
|
|||
"project_description": "my first project mirror_demo",
|
||||
"project_category_id": 1,
|
||||
"project_language_id": 2,
|
||||
"private": false
|
||||
"private": false,
|
||||
"is_secret": true
|
||||
}
|
||||
```
|
||||
---
|
||||
|
@ -1189,6 +1203,7 @@ http://localhost:3000/api/projects | jq
|
|||
|forked_count |int|被fork的数量|
|
||||
|praises_count |int|star数量|
|
||||
|is_public |boolean|是否公开, true:公开,false:未公开|
|
||||
|is_secret |boolean|是否为特殊许可证项目, true:是,false:否|
|
||||
|mirror_url |string|镜像url|
|
||||
|last_update_time|int|最后更新时间,为UNIX格式的时间戳|
|
||||
|author |object|项目创建者|
|
||||
|
@ -1199,6 +1214,10 @@ http://localhost:3000/api/projects | jq
|
|||
|language |object|项目语言|
|
||||
|-- id |int|项目语言id|
|
||||
|-- name |string|项目语言名称|
|
||||
|user_apply_signatures |object|用户创建的特殊许可申请|
|
||||
|-- id |int|用户创建的特殊许可申请id|
|
||||
|-- status |int|用户创建的特殊许可申请审核状态, 'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|
||||
|
||||
|
||||
|
||||
返回值
|
||||
|
@ -1214,6 +1233,7 @@ http://localhost:3000/api/projects | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": true,
|
||||
"is_secret": true,
|
||||
"mirror_url": null,
|
||||
"last_update_time": 1577697461,
|
||||
"author": {
|
||||
|
@ -1227,7 +1247,13 @@ http://localhost:3000/api/projects | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[
|
||||
{
|
||||
"id": 1,
|
||||
"status": "waiting"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
|
@ -1237,6 +1263,7 @@ http://localhost:3000/api/projects | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": true,
|
||||
"is_secret": false,
|
||||
"mirror_url": null,
|
||||
"last_update_time": 1577697403,
|
||||
"author": {
|
||||
|
@ -1250,7 +1277,8 @@ http://localhost:3000/api/projects | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
|
@ -1260,6 +1288,7 @@ http://localhost:3000/api/projects | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": true,
|
||||
"is_secret": true,
|
||||
"mirror_url": null,
|
||||
"last_update_time": 1577415173,
|
||||
"author": {
|
||||
|
@ -1273,7 +1302,8 @@ http://localhost:3000/api/projects | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
|
@ -1283,6 +1313,7 @@ http://localhost:3000/api/projects | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": false,
|
||||
"is_secret": true,
|
||||
"mirror_url": "https://gitea.com/CasperVector/slew.git",
|
||||
"last_update_time": 1577346228,
|
||||
"author": {
|
||||
|
@ -1296,7 +1327,8 @@ http://localhost:3000/api/projects | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
|
@ -1306,6 +1338,7 @@ http://localhost:3000/api/projects | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": true,
|
||||
"is_secret": true,
|
||||
"mirror_url": null,
|
||||
"last_update_time": 1577341572,
|
||||
"author": {
|
||||
|
@ -1319,7 +1352,8 @@ http://localhost:3000/api/projects | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -5059,6 +5093,7 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|
|||
|forked_count |int|被fork的数量|
|
||||
|praises_count |int|star数量|
|
||||
|is_public |boolean|是否公开, true:公开,false:未公开|
|
||||
|is_secret |boolean|是否为特殊许可证项目, true:是,false:否|
|
||||
|mirror_url |string|镜像url|
|
||||
|last_update_time|int|最后更新时间,为UNIX格式的时间戳|
|
||||
|author |object|项目创建者|
|
||||
|
@ -5069,7 +5104,9 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|
|||
|language |object|项目语言|
|
||||
|-- id |int|项目语言id|
|
||||
|-- name |string|项目语言名称|
|
||||
|
||||
|user_apply_signatures |object|用户创建的特殊许可申请|
|
||||
|-- id |int|用户创建的特殊许可申请id|
|
||||
|-- status |int|用户创建的特殊许可申请审核状态, 'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|
||||
|
||||
返回值
|
||||
```json
|
||||
|
@ -5084,6 +5121,7 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|
|||
"praises_count": 0,
|
||||
"forked_count": 0,
|
||||
"is_public": true,
|
||||
"is_secret": false,
|
||||
"mirror_url": null,
|
||||
"last_update_time": 1577697461,
|
||||
"author": {
|
||||
|
@ -5097,9 +5135,163 @@ http://localhost:3000/api/users/Jason/projects.json | jq
|
|||
"language": {
|
||||
"id": 2,
|
||||
"name": "C"
|
||||
}
|
||||
},
|
||||
"user_apply_signatures":[
|
||||
{
|
||||
"id": 1,
|
||||
"status": "waiting"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
#### 特殊许可证项目申请列表
|
||||
```
|
||||
GET /api/apply_signatures
|
||||
```
|
||||
*示例*
|
||||
```bash
|
||||
curl -X GET \
|
||||
-d "project_id=36" \
|
||||
-d "page=1" \
|
||||
-d "limit=5" \
|
||||
-d "search=16895620" \
|
||||
-d "status=waiting" \
|
||||
http://localhost:3000/api/apply_signatures | jq
|
||||
```
|
||||
*请求参数说明:*
|
||||
|
||||
|参数名|必选|类型|说明|
|
||||
|-|-|-|-|
|
||||
|project_id |是|int |项目id |
|
||||
|page |否|string |页数,第几页 |
|
||||
|limit |否|string |每页多少条数据,默认15条 |
|
||||
|search |否|string |用户名、登录名匹配搜索 |
|
||||
|status |否|string |状态匹配搜索,'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过 |
|
||||
|
||||
|
||||
*返回参数说明:*
|
||||
|
||||
|参数名|类型|说明|
|
||||
|-|-|-|
|
||||
|total_count |int |返回记录总条数 |
|
||||
|apply_signatures |array|特殊许可证项目申请信息|
|
||||
|-- id |int|特殊许可证项目申请id|
|
||||
|-- status |int|特殊许可证项目申请状态,'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|
||||
|user |object|用户|
|
||||
|-- id |int|用户id|
|
||||
|-- name |string|用户名称|
|
||||
|-- login |string|用户登录名/标识|
|
||||
|-- image_url |string|用户头像|
|
||||
|-- email |string|用户邮箱|
|
||||
|-- is_owner |boolean|是否是项目的拥有者,true:是, false:不是|
|
||||
|attachment |object|上传附件|
|
||||
|--filename |string|附件名称|
|
||||
|--path |string|附件地址|
|
||||
|
||||
|
||||
返回值
|
||||
```json
|
||||
{
|
||||
"total_count": 1,
|
||||
"apply_signatures": [
|
||||
{
|
||||
"id": 18,
|
||||
"status": "passed",
|
||||
"user": {
|
||||
"id": 3,
|
||||
"name": "16895620",
|
||||
"login": "16895620",
|
||||
"image_url": "avatars/User/boy.jpg",
|
||||
"email": "2456233122@qq.com",
|
||||
"is_owner": false
|
||||
},
|
||||
"attachment": {
|
||||
"filename": "PHengLEI软件开源协议.docx",
|
||||
"path": "/api/attachments/23"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
---
|
||||
#### 特殊许可证项目用户创建申请
|
||||
```
|
||||
POST /api/apply_signatures
|
||||
```
|
||||
|
||||
*示例*
|
||||
```bash
|
||||
curl -X POST \
|
||||
-d "project_id=8" \
|
||||
-d "attachment_id=4" \
|
||||
http://localhost:3000/api/apply_signatures.json | jq
|
||||
```
|
||||
|
||||
*请求参数说明:*
|
||||
|
||||
|参数名|必选|类型|说明|
|
||||
|-|-|-|-|
|
||||
|project_id |是|int |项目id |
|
||||
|attachment_id |是|int |上传的文件id |
|
||||
|
||||
*返回参数说明:*
|
||||
|
||||
|参数名|类型|说明|
|
||||
|-|-|-|
|
||||
|id |int|特殊许可证项目用户创建申请的id|
|
||||
|attachment |object|上传的文件|
|
||||
|--filename |string|上传的文件的文件名|
|
||||
|
||||
返回值
|
||||
```json
|
||||
{
|
||||
"id": 5,
|
||||
"attachment": {
|
||||
"filename": "timg.jpeg"
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
#### 特殊许可证项目申请修改
|
||||
```
|
||||
PATCH /api/apply_signatures/:id
|
||||
```
|
||||
|
||||
*示例*
|
||||
```bash
|
||||
curl -X POST \
|
||||
-d "id=18" \
|
||||
-d "status=passed" \
|
||||
-d "project_id=36" \
|
||||
http://localhost:3000/api/apply_signatures/18 | jq
|
||||
```
|
||||
|
||||
*请求参数说明:*
|
||||
|
||||
|参数名|必选|类型|说明|
|
||||
|-|-|-|-|
|
||||
|id |是|int |特殊许可证项目申请id |
|
||||
|status |是|string |特殊许可证项目申请状态 ,'unpassed': 审核未通过,'waiting': 等待审核 'passed':审核通过|
|
||||
|project_id |是|int |项目id|
|
||||
|
||||
|
||||
*返回参数说明:*
|
||||
|
||||
|参数名|类型|说明|
|
||||
|-|-|-|
|
||||
|status |int |0:添加成功, -1: 更改失败, 1: 表示已经是该状态了 |
|
||||
|message |string|返回信息说明|
|
||||
|
||||
|
||||
返回值
|
||||
```json
|
||||
{
|
||||
"status": 0,
|
||||
"message": "success"
|
||||
}
|
||||
```
|
||||
---
|
|
@ -1,136 +1,154 @@
|
|||
//= require rails-ujs
|
||||
//= require activestorage
|
||||
//= require turbolinks
|
||||
//= require jquery3
|
||||
//= require popper
|
||||
//= require bootstrap-sprockets
|
||||
//= require jquery.validate.min
|
||||
//= require additional-methods.min
|
||||
//= require bootstrap-notify
|
||||
//= require jquery.cookie.min
|
||||
//= require select2
|
||||
//= require moment.min
|
||||
//= require jquery.cxselect
|
||||
//= require bootstrap-datepicker
|
||||
//= require bootstrap-datetimepicker
|
||||
//= require bootstrap.viewer
|
||||
//= require jquery.mloading
|
||||
//= require jquery-confirm.min
|
||||
//= require common
|
||||
|
||||
//= require echarts
|
||||
//= require codemirror/lib/codemirror
|
||||
//= require codemirror/mode/shell/shell
|
||||
//= require editormd/editormd
|
||||
//= require editormd/languages/zh-tw
|
||||
//= require dragula/dragula
|
||||
|
||||
//= require_tree ./i18n
|
||||
//= require_tree ./admins
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
||||
}
|
||||
});
|
||||
|
||||
// ******** select2 global config ********
|
||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||
|
||||
Turbolinks.setProgressBarDelay(200);
|
||||
|
||||
$.notifyDefaults({
|
||||
type: 'success',
|
||||
z_index: 9999,
|
||||
delay: 2000
|
||||
});
|
||||
|
||||
function show_success_flash(){
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
||||
// 图片查看大图
|
||||
$('img.preview-image').bootstrapViewer();
|
||||
|
||||
// flash alert提示框自动关闭
|
||||
if($('.admin-alert-container .alert').length > 0){
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
||||
}, 2000);
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert.alert-danger').alert('close');
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("turbolinks:before-cache", function () {
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
});
|
||||
// var progressBar = new Turbolinks.ProgressBar();
|
||||
|
||||
// $(document).on('ajax:send', function(event){
|
||||
// console.log('ajax send', event);
|
||||
// progressBar.setValue(0)
|
||||
// progressBar.show()
|
||||
// });
|
||||
//
|
||||
// $(document).on('ajax:complete', function(event){
|
||||
// console.log('ajax complete', event);
|
||||
// progressBar.setValue(1)
|
||||
// progressBar.hide() // 分页时不触发,奇怪
|
||||
// });
|
||||
// $(document).on('ajax:success', function(event){
|
||||
// console.log('ajax success', event);
|
||||
// });
|
||||
// $(document).on('ajax:error', function(event){
|
||||
// console.log('ajax error', event);
|
||||
// });
|
||||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
//= require rails-ujs
|
||||
//= require activestorage
|
||||
//= require turbolinks
|
||||
//= require jquery3
|
||||
//= require popper
|
||||
//= require bootstrap-sprockets
|
||||
//= require jquery.validate.min
|
||||
//= require additional-methods.min
|
||||
//= require bootstrap-notify
|
||||
//= require jquery.cookie.min
|
||||
//= require select2
|
||||
//= require moment.min
|
||||
//= require jquery.cxselect
|
||||
//= require bootstrap-datepicker
|
||||
//= require bootstrap-datetimepicker
|
||||
//= require bootstrap.viewer
|
||||
//= require bootstrap/bootstrap-toggle
|
||||
//= require jquery.mloading
|
||||
//= require jquery-confirm.min
|
||||
//= require common
|
||||
|
||||
//= require echarts
|
||||
//= require codemirror/lib/codemirror
|
||||
//= require codemirror/mode/shell/shell
|
||||
//= require editormd/editormd
|
||||
//= require editormd/languages/zh-tw
|
||||
//= require dragula/dragula
|
||||
|
||||
//= require_tree ./i18n
|
||||
//= require_tree ./admins
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
||||
}
|
||||
});
|
||||
|
||||
// ******** select2 global config ********
|
||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||
|
||||
Turbolinks.setProgressBarDelay(200);
|
||||
|
||||
$.notifyDefaults({
|
||||
type: 'success',
|
||||
z_index: 9999,
|
||||
delay: 2000
|
||||
});
|
||||
|
||||
function show_success_flash(){
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function(){
|
||||
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
||||
// 图片查看大图
|
||||
$('img.preview-image').bootstrapViewer();
|
||||
|
||||
// flash alert提示框自动关闭
|
||||
if($('.admin-alert-container .alert').length > 0){
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
||||
}, 2000);
|
||||
setTimeout(function(){
|
||||
$('.admin-alert-container .alert.alert-danger').alert('close');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(document).on("turbolinks:before-cache", function () {
|
||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
});
|
||||
// var progressBar = new Turbolinks.ProgressBar();
|
||||
|
||||
// $(document).on('ajax:send', function(event){
|
||||
// console.log('ajax send', event);
|
||||
// progressBar.setValue(0)
|
||||
// progressBar.show()
|
||||
// });
|
||||
//
|
||||
// $(document).on('ajax:complete', function(event){
|
||||
// console.log('ajax complete', event);
|
||||
// progressBar.setValue(1)
|
||||
// progressBar.hide() // 分页时不触发,奇怪
|
||||
// });
|
||||
// $(document).on('ajax:success', function(event){
|
||||
// console.log('ajax success', event);
|
||||
// });
|
||||
// $(document).on('ajax:error', function(event){
|
||||
// console.log('ajax error', event);
|
||||
// });
|
||||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
})
|
|
@ -6,7 +6,7 @@ $(document).on('turbolinks:load', function(){
|
|||
});
|
||||
|
||||
var sidebarController = $('#sidebar').data('current-controller');
|
||||
if (sidebarController.length > 0) {
|
||||
if (sidebarController && sidebarController.length > 0) {
|
||||
$('#sidebar a.active').removeClass('active');
|
||||
$('#sidebar ul.collapse.show').removeClass('show');
|
||||
var activeLi = $('#sidebar a[data-controller="' + sidebarController + '"]');
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// TOGGLE PUBLIC CLASS DEFINITION
|
||||
// ==============================
|
||||
|
||||
var Toggle = function (element, options) {
|
||||
this.$element = $(element)
|
||||
this.options = $.extend({}, this.defaults(), options)
|
||||
this.render()
|
||||
}
|
||||
|
||||
Toggle.VERSION = '2.2.0'
|
||||
|
||||
Toggle.DEFAULTS = {
|
||||
on: 'On',
|
||||
off: 'Off',
|
||||
onstyle: 'primary',
|
||||
offstyle: 'default',
|
||||
size: 'normal',
|
||||
style: '',
|
||||
width: null,
|
||||
height: null
|
||||
}
|
||||
|
||||
Toggle.prototype.defaults = function() {
|
||||
return {
|
||||
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||
}
|
||||
}
|
||||
|
||||
Toggle.prototype.render = function () {
|
||||
this._onstyle = 'btn-' + this.options.onstyle
|
||||
this._offstyle = 'btn-' + this.options.offstyle
|
||||
var size = this.options.size === 'large' ? 'btn-lg'
|
||||
: this.options.size === 'small' ? 'btn-sm'
|
||||
: this.options.size === 'mini' ? 'btn-xs'
|
||||
: ''
|
||||
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||
.addClass(this._onstyle + ' ' + size)
|
||||
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||
.addClass(this._offstyle + ' ' + size + ' active')
|
||||
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||
.addClass(size)
|
||||
var $toggleGroup = $('<div class="toggle-group">')
|
||||
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||
.addClass(size).addClass(this.options.style)
|
||||
|
||||
this.$element.wrap($toggle)
|
||||
$.extend(this, {
|
||||
$toggle: this.$element.parent(),
|
||||
$toggleOn: $toggleOn,
|
||||
$toggleOff: $toggleOff,
|
||||
$toggleGroup: $toggleGroup
|
||||
})
|
||||
this.$toggle.append($toggleGroup)
|
||||
|
||||
var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
|
||||
var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
|
||||
$toggleOn.addClass('toggle-on')
|
||||
$toggleOff.addClass('toggle-off')
|
||||
this.$toggle.css({ width: width, height: height })
|
||||
if (this.options.height) {
|
||||
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||
}
|
||||
this.update(true)
|
||||
this.trigger(true)
|
||||
}
|
||||
|
||||
Toggle.prototype.toggle = function () {
|
||||
if (this.$element.prop('checked')) this.off()
|
||||
else this.on()
|
||||
}
|
||||
|
||||
Toggle.prototype.on = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||
this.$element.prop('checked', true)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.off = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||
this.$element.prop('checked', false)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.enable = function () {
|
||||
this.$toggle.removeAttr('disabled')
|
||||
this.$element.prop('disabled', false)
|
||||
}
|
||||
|
||||
Toggle.prototype.disable = function () {
|
||||
this.$toggle.attr('disabled', 'disabled')
|
||||
this.$element.prop('disabled', true)
|
||||
}
|
||||
|
||||
Toggle.prototype.update = function (silent) {
|
||||
if (this.$element.prop('disabled')) this.disable()
|
||||
else this.enable()
|
||||
if (this.$element.prop('checked')) this.on(silent)
|
||||
else this.off(silent)
|
||||
}
|
||||
|
||||
Toggle.prototype.trigger = function (silent) {
|
||||
this.$element.off('change.bs.toggle')
|
||||
if (!silent) this.$element.change()
|
||||
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||
this.update()
|
||||
}, this))
|
||||
}
|
||||
|
||||
Toggle.prototype.destroy = function() {
|
||||
this.$element.off('change.bs.toggle')
|
||||
this.$toggleGroup.remove()
|
||||
this.$element.removeData('bs.toggle')
|
||||
this.$element.unwrap()
|
||||
}
|
||||
|
||||
// TOGGLE PLUGIN DEFINITION
|
||||
// ========================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.toggle')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||
if (typeof option == 'string' && data[option]) data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.bootstrapToggle
|
||||
|
||||
$.fn.bootstrapToggle = Plugin
|
||||
$.fn.bootstrapToggle.Constructor = Toggle
|
||||
|
||||
// TOGGLE NO CONFLICT
|
||||
// ==================
|
||||
|
||||
$.fn.toggle.noConflict = function () {
|
||||
$.fn.bootstrapToggle = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TOGGLE DATA-API
|
||||
// ===============
|
||||
|
||||
$(function() {
|
||||
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||
})
|
||||
|
||||
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||
var $checkbox = $(this).find('input[type=checkbox]')
|
||||
$checkbox.bootstrapToggle('toggle')
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||
//# sourceMappingURL=bootstrap-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"bootstrap-toggle.min.js","sources":["bootstrap-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","outerHeight","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,SAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,SACV,SAAtBjB,KAAKI,QAAQa,KAAkB,SAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUa,aAAcV,EAAWU,cAAeT,EAAcS,aAAa,EACpHlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUc,cAAeX,EAAWW,cACjFd,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQQ,KAAMrB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUe,IAAI,cAAef,EAAUL,SAAW,MAClDQ,EAAWY,IAAI,cAAeZ,EAAWR,SAAW,OAErDpB,KAAKyC,QAAO,GACZzC,KAAK0C,SAAQ,IAGdrC,EAAOgB,UAAUsB,OAAS,WACrB3C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU+B,GAC/B,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUP,IAAM,SAAU8B,GAChC,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUyB,OAAS,WACzB9C,KAAKgC,QAAQe,WAAW,YACxB/C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU2B,QAAU,WAC1BhD,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUoB,OAAS,SAAUG,GAC/B5C,KAAKO,SAAS0B,KAAK,YAAajC,KAAKgD,UACpChD,KAAK8C,SACN9C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG+B,GACtC5C,KAAKc,IAAI8B,IAGfvC,EAAOgB,UAAUqB,QAAU,SAAUE,GACpC5C,KAAKO,SAASO,IAAI,oBACb8B,GAAQ5C,KAAKO,SAAS0C,SAC3BjD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEqD,MAAM,WAC5ClD,KAAKyC,UACHzC,QAGJK,EAAOgB,UAAU8B,QAAU,WAC1BnD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAasB,SAClBpD,KAAKO,SAAS8C,WAAW,aACzBrD,KAAKO,SAAS+C,SAiBf,IAAIC,GAAM1D,EAAE2D,GAAGC,eAEf5D,GAAE2D,GAAGC,gBAA8B3D,EACnCD,EAAE2D,GAAGC,gBAAgBC,YAAcrD,EAKnCR,EAAE2D,GAAGb,OAAOgB,WAAa,WAExB,MADA9D,GAAE2D,GAAGC,gBAAkBF,EAChBvD,MAMRH,EAAE,WACDA,EAAE,6CAA6C4D,oBAGhD5D,EAAE+D,UAAU/C,GAAG,kBAAmB,2BAA4B,SAASgD,GACtE,GAAIC,GAAYjE,EAAEG,MAAM+D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -0,0 +1,180 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// TOGGLE PUBLIC CLASS DEFINITION
|
||||
// ==============================
|
||||
|
||||
var Toggle = function (element, options) {
|
||||
this.$element = $(element)
|
||||
this.options = $.extend({}, this.defaults(), options)
|
||||
this.render()
|
||||
}
|
||||
|
||||
Toggle.VERSION = '2.2.0'
|
||||
|
||||
Toggle.DEFAULTS = {
|
||||
on: 'On',
|
||||
off: 'Off',
|
||||
onstyle: 'primary',
|
||||
offstyle: 'default',
|
||||
size: 'normal',
|
||||
style: '',
|
||||
width: null,
|
||||
height: null
|
||||
}
|
||||
|
||||
Toggle.prototype.defaults = function() {
|
||||
return {
|
||||
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||
}
|
||||
}
|
||||
|
||||
Toggle.prototype.render = function () {
|
||||
this._onstyle = 'btn-' + this.options.onstyle
|
||||
this._offstyle = 'btn-' + this.options.offstyle
|
||||
var size = this.options.size === 'large' ? 'btn-large'
|
||||
: this.options.size === 'small' ? 'btn-small'
|
||||
: this.options.size === 'mini' ? 'btn-mini'
|
||||
: ''
|
||||
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||
.addClass(this._onstyle + ' ' + size)
|
||||
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||
.addClass(this._offstyle + ' ' + size + ' active')
|
||||
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||
.addClass(size)
|
||||
var $toggleGroup = $('<div class="toggle-group">')
|
||||
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||
.addClass(size).addClass(this.options.style)
|
||||
|
||||
this.$element.wrap($toggle)
|
||||
$.extend(this, {
|
||||
$toggle: this.$element.parent(),
|
||||
$toggleOn: $toggleOn,
|
||||
$toggleOff: $toggleOff,
|
||||
$toggleGroup: $toggleGroup
|
||||
})
|
||||
this.$toggle.append($toggleGroup)
|
||||
|
||||
var width = this.options.width || Math.max($toggleOn.width(), $toggleOff.width())+($toggleHandle.outerWidth()/2)
|
||||
var height = this.options.height || Math.max($toggleOn.height(), $toggleOff.height())
|
||||
$toggleOn.addClass('toggle-on')
|
||||
$toggleOff.addClass('toggle-off')
|
||||
this.$toggle.css({ width: width, height: height })
|
||||
if (this.options.height) {
|
||||
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||
}
|
||||
this.update(true)
|
||||
this.trigger(true)
|
||||
}
|
||||
|
||||
Toggle.prototype.toggle = function () {
|
||||
if (this.$element.prop('checked')) this.off()
|
||||
else this.on()
|
||||
}
|
||||
|
||||
Toggle.prototype.on = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||
this.$element.prop('checked', true)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.off = function (silent) {
|
||||
if (this.$element.prop('disabled')) return false
|
||||
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||
this.$element.prop('checked', false)
|
||||
if (!silent) this.trigger()
|
||||
}
|
||||
|
||||
Toggle.prototype.enable = function () {
|
||||
this.$toggle.removeAttr('disabled')
|
||||
this.$element.prop('disabled', false)
|
||||
}
|
||||
|
||||
Toggle.prototype.disable = function () {
|
||||
this.$toggle.attr('disabled', 'disabled')
|
||||
this.$element.prop('disabled', true)
|
||||
}
|
||||
|
||||
Toggle.prototype.update = function (silent) {
|
||||
if (this.$element.prop('disabled')) this.disable()
|
||||
else this.enable()
|
||||
if (this.$element.prop('checked')) this.on(silent)
|
||||
else this.off(silent)
|
||||
}
|
||||
|
||||
Toggle.prototype.trigger = function (silent) {
|
||||
this.$element.off('change.bs.toggle')
|
||||
if (!silent) this.$element.change()
|
||||
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||
this.update()
|
||||
}, this))
|
||||
}
|
||||
|
||||
Toggle.prototype.destroy = function() {
|
||||
this.$element.off('change.bs.toggle')
|
||||
this.$toggleGroup.remove()
|
||||
this.$element.removeData('bs.toggle')
|
||||
this.$element.unwrap()
|
||||
}
|
||||
|
||||
// TOGGLE PLUGIN DEFINITION
|
||||
// ========================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.toggle')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||
if (typeof option == 'string' && data[option]) data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.bootstrapToggle
|
||||
|
||||
$.fn.bootstrapToggle = Plugin
|
||||
$.fn.bootstrapToggle.Constructor = Toggle
|
||||
|
||||
// TOGGLE NO CONFLICT
|
||||
// ==================
|
||||
|
||||
$.fn.toggle.noConflict = function () {
|
||||
$.fn.bootstrapToggle = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TOGGLE DATA-API
|
||||
// ===============
|
||||
|
||||
$(function() {
|
||||
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||
})
|
||||
|
||||
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||
var $checkbox = $(this).find('input[type=checkbox]')
|
||||
$checkbox.bootstrapToggle('toggle')
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-large":"small"===this.options.size?"btn-small":"mini"===this.options.size?"btn-mini":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.width(),d.width())+e.outerWidth()/2,i=this.options.height||Math.max(c.height(),d.height());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||
//# sourceMappingURL=bootstrap2-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"bootstrap2-toggle.min.js","sources":["bootstrap2-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,YAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,YACV,SAAtBjB,KAAKI,QAAQa,KAAkB,WAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUN,QAASS,EAAWT,SAAUU,EAAcS,aAAa,EAC1GlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUL,SAAUQ,EAAWR,SAC5EK,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQO,KAAMpB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUc,IAAI,cAAed,EAAUL,SAAW,MAClDQ,EAAWW,IAAI,cAAeX,EAAWR,SAAW,OAErDpB,KAAKwC,QAAO,GACZxC,KAAKyC,SAAQ,IAGdpC,EAAOgB,UAAUqB,OAAS,WACrB1C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU8B,GAC/B,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUP,IAAM,SAAU6B,GAChC,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUwB,OAAS,WACzB7C,KAAKgC,QAAQc,WAAW,YACxB9C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU0B,QAAU,WAC1B/C,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUmB,OAAS,SAAUG,GAC/B3C,KAAKO,SAAS0B,KAAK,YAAajC,KAAK+C,UACpC/C,KAAK6C,SACN7C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG8B,GACtC3C,KAAKc,IAAI6B,IAGftC,EAAOgB,UAAUoB,QAAU,SAAUE,GACpC3C,KAAKO,SAASO,IAAI,oBACb6B,GAAQ3C,KAAKO,SAASyC,SAC3BhD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEoD,MAAM,WAC5CjD,KAAKwC,UACHxC,QAGJK,EAAOgB,UAAU6B,QAAU,WAC1BlD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAaqB,SAClBnD,KAAKO,SAAS6C,WAAW,aACzBpD,KAAKO,SAAS8C,SAiBf,IAAIC,GAAMzD,EAAE0D,GAAGC,eAEf3D,GAAE0D,GAAGC,gBAA8B1D,EACnCD,EAAE0D,GAAGC,gBAAgBC,YAAcpD,EAKnCR,EAAE0D,GAAGb,OAAOgB,WAAa,WAExB,MADA7D,GAAE0D,GAAGC,gBAAkBF,EAChBtD,MAMRH,EAAE,WACDA,EAAE,6CAA6C2D,oBAGhD3D,EAAE8D,UAAU9C,GAAG,kBAAmB,2BAA4B,SAAS+C,GACtE,GAAIC,GAAYhE,EAAEG,MAAM8D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -8,6 +8,7 @@
|
|||
@import "jquery.mloading";
|
||||
@import "jquery-confirm.min";
|
||||
@import "bootstrap-datetimepicker.min";
|
||||
@import "bootstrap/bootstrap-toggle.min";
|
||||
|
||||
@import "codemirror/lib/codemirror";
|
||||
@import "editormd/css/editormd.min";
|
||||
|
@ -203,4 +204,14 @@ input.form-control {
|
|||
color: #23272B;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.table th, .table td {
|
||||
padding: 0.75rem 0.1rem;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.table .thead-light th{
|
||||
white-space: nowrap;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
.checkbox label .toggle,
|
||||
.checkbox-inline .toggle {
|
||||
margin-left: -20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toggle input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: left 0.35s;
|
||||
-webkit-transition: left 0.35s;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.toggle.off .toggle-group {
|
||||
left: -100%;
|
||||
}
|
||||
.toggle-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
border-width: 0 1px;
|
||||
}
|
||||
|
||||
.toggle.btn { min-width: 59px; min-height: 34px; }
|
||||
.toggle-on.btn { padding-right: 24px; }
|
||||
.toggle-off.btn { padding-left: 24px; }
|
||||
|
||||
.toggle.btn-lg { min-width: 79px; min-height: 45px; }
|
||||
.toggle-on.btn-lg { padding-right: 31px; }
|
||||
.toggle-off.btn-lg { padding-left: 31px; }
|
||||
.toggle-handle.btn-lg { width: 40px; }
|
||||
|
||||
.toggle.btn-sm { min-width: 50px; min-height: 30px;}
|
||||
.toggle-on.btn-sm { padding-right: 20px; }
|
||||
.toggle-off.btn-sm { padding-left: 20px; }
|
||||
|
||||
.toggle.btn-xs { min-width: 35px; min-height: 22px;}
|
||||
.toggle-on.btn-xs { padding-right: 12px; }
|
||||
.toggle-off.btn-xs { padding-left: 12px; }
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
|
||||
.toggle{position:relative;overflow:hidden}
|
||||
.toggle input[type=checkbox]{display:none}
|
||||
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||
.toggle.off .toggle-group{left:-100%}
|
||||
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||
.toggle.btn{min-width:59px;min-height:34px}
|
||||
.toggle-on.btn{padding-right:24px}
|
||||
.toggle-off.btn{padding-left:24px}
|
||||
.toggle.btn-lg{min-width:79px;min-height:45px}
|
||||
.toggle-on.btn-lg{padding-right:31px}
|
||||
.toggle-off.btn-lg{padding-left:31px}
|
||||
.toggle-handle.btn-lg{width:40px}
|
||||
.toggle.btn-sm{min-width:50px;min-height:30px}
|
||||
.toggle-on.btn-sm{padding-right:20px}
|
||||
.toggle-off.btn-sm{padding-left:20px}
|
||||
.toggle.btn-xs{min-width:35px;min-height:22px}
|
||||
.toggle-on.btn-xs{padding-right:12px}
|
||||
.toggle-off.btn-xs{padding-left:12px}
|
|
@ -0,0 +1,85 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
label.checkbox .toggle,
|
||||
label.checkbox.inline .toggle {
|
||||
margin-left: -20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.toggle {
|
||||
min-width: 40px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toggle input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: left 0.35s;
|
||||
-webkit-transition: left 0.35s;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.toggle.off .toggle-group {
|
||||
left: -100%;
|
||||
}
|
||||
.toggle-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
border-width: 0 1px;
|
||||
}
|
||||
.toggle-handle.btn-mini {
|
||||
top: -1px;
|
||||
}
|
||||
.toggle.btn { min-width: 30px; }
|
||||
.toggle-on.btn { padding-right: 24px; }
|
||||
.toggle-off.btn { padding-left: 24px; }
|
||||
|
||||
.toggle.btn-large { min-width: 40px; }
|
||||
.toggle-on.btn-large { padding-right: 35px; }
|
||||
.toggle-off.btn-large { padding-left: 35px; }
|
||||
|
||||
.toggle.btn-small { min-width: 25px; }
|
||||
.toggle-on.btn-small { padding-right: 20px; }
|
||||
.toggle-off.btn-small { padding-left: 20px; }
|
||||
|
||||
.toggle.btn-mini { min-width: 20px; }
|
||||
.toggle-on.btn-mini { padding-right: 12px; }
|
||||
.toggle-off.btn-mini { padding-left: 12px; }
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*! ========================================================================
|
||||
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||
* http://www.bootstraptoggle.com
|
||||
* ========================================================================
|
||||
* Copyright 2014 Min Hur, The New York Times Company
|
||||
* Licensed under MIT
|
||||
* ======================================================================== */
|
||||
label.checkbox .toggle,label.checkbox.inline .toggle{margin-left:-20px;margin-right:5px}
|
||||
.toggle{min-width:40px;height:20px;position:relative;overflow:hidden}
|
||||
.toggle input[type=checkbox]{display:none}
|
||||
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||
.toggle.off .toggle-group{left:-100%}
|
||||
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||
.toggle-handle.btn-mini{top:-1px}
|
||||
.toggle.btn{min-width:30px}
|
||||
.toggle-on.btn{padding-right:24px}
|
||||
.toggle-off.btn{padding-left:24px}
|
||||
.toggle.btn-large{min-width:40px}
|
||||
.toggle-on.btn-large{padding-right:35px}
|
||||
.toggle-off.btn-large{padding-left:35px}
|
||||
.toggle.btn-small{min-width:25px}
|
||||
.toggle-on.btn-small{padding-right:20px}
|
||||
.toggle-off.btn-small{padding-left:20px}
|
||||
.toggle.btn-mini{min-width:20px}
|
||||
.toggle-on.btn-mini{padding-right:12px}
|
||||
.toggle-off.btn-mini{padding-left:12px}
|
|
@ -1,371 +1,465 @@
|
|||
class AccountsController < ApplicationController
|
||||
include ApplicationHelper
|
||||
|
||||
#skip_before_action :check_account, :only => [:logout]
|
||||
|
||||
def index
|
||||
render json: session
|
||||
end
|
||||
|
||||
# 其他平台同步注册的用户
|
||||
def remote_register
|
||||
username = params[:username]&.gsub(/\s+/, "")
|
||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
||||
email = params[:email]&.gsub(/\s+/, "")
|
||||
password = params[:password]
|
||||
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
result = autologin_register(username, email, password, platform)
|
||||
if result[:message].blank?
|
||||
render_ok({user: result[:user]})
|
||||
else
|
||||
render_error(result[:message])
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
|
||||
# 其他平台修改用户的信息,这边同步修改
|
||||
def remote_update
|
||||
ActiveRecord::Base.transaction do
|
||||
user_params = params[:user_params]
|
||||
user_extension_params = params[:user_extension_params]
|
||||
|
||||
u = User.find_by(login: params[:old_user_login])
|
||||
user_mail = u.try(:mail)
|
||||
|
||||
if u.present?
|
||||
ue = u.user_extension
|
||||
u.login = user_params["login"] if user_params["login"]
|
||||
u.mail = user_params["mail"] if user_params["mail"]
|
||||
u.lastname = user_params["lastname"] if user_params["lastname"]
|
||||
|
||||
ue.gender = user_extension_params["gender"]
|
||||
ue.school_id = user_extension_params["school_id"]
|
||||
ue.location = user_extension_params["location"]
|
||||
ue.location_city = user_extension_params["location_city"]
|
||||
ue.identity = user_extension_params["identity"]
|
||||
ue.technical_title = user_extension_params["technical_title"]
|
||||
ue.student_id = user_extension_params["student_id"]
|
||||
ue.description = user_extension_params["description"]
|
||||
ue.save!
|
||||
u.save!
|
||||
|
||||
sync_params = {}
|
||||
|
||||
if (user_params["mail"] && user_params["mail"] != user_mail)
|
||||
sync_params = sync_params.merge(email: user_params["mail"])
|
||||
end
|
||||
|
||||
if sync_params.present?
|
||||
interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params)
|
||||
if interactor.success?
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
|
||||
# 其他平台同步登录
|
||||
def remote_login
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
if @user
|
||||
successful_authentication(@user)
|
||||
render_ok({user: {id: @user.id, token: @user.gitea_token}})
|
||||
else
|
||||
render_error("用户不存在")
|
||||
end
|
||||
end
|
||||
|
||||
#修改密码
|
||||
def remote_password
|
||||
@user = User.find_by(login: params[:login])
|
||||
return render_error("未找到相关用户!") if @user.blank?
|
||||
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: @user.mail
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
if interactor.success?
|
||||
@user.update_attribute(:password, params[:password])
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# 用户注册
|
||||
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
|
||||
# params[:login] 邮箱或者手机号
|
||||
# params[:namespace] 登录名
|
||||
# params[:code] 验证码
|
||||
# code_type 1:注册手机验证码 8:邮箱注册验证码
|
||||
# 本地forge注册入口需要重新更改逻辑
|
||||
def register
|
||||
# type只可能是1或者8
|
||||
user = nil
|
||||
begin
|
||||
Register::Form.new(register_params).validate!
|
||||
|
||||
user = Users::RegisterService.call(register_params)
|
||||
password = register_params[:password].strip
|
||||
|
||||
# gitea用户注册, email, username, password
|
||||
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(user.login, password)
|
||||
user.gitea_token = result['sha1']
|
||||
user.gitea_uid = gitea_user[:body]['id']
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
successful_authentication(user)
|
||||
render_ok
|
||||
end
|
||||
else
|
||||
tip_exception(-1, interactor.error)
|
||||
end
|
||||
rescue Register::BaseForm::EmailError => e
|
||||
render_error(-2, e.message)
|
||||
rescue Register::BaseForm::LoginError => e
|
||||
render_error(-3, e.message)
|
||||
rescue Register::BaseForm::PhoneError => e
|
||||
render_error(-4, e.message)
|
||||
rescue Register::BaseForm::PasswordFormatError => e
|
||||
render_error(-5, e.message)
|
||||
rescue Register::BaseForm::VerifiCodeError => e
|
||||
render_error(-6, e.message)
|
||||
rescue Exception => e
|
||||
Gitea::User::DeleteService.call(user.login) unless user.nil?
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
end
|
||||
|
||||
# 用户登录
|
||||
def login
|
||||
Users::LoginForm.new(account_params).validate!
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
|
||||
return normal_status(-2, "错误的账号或密码") if @user.blank?
|
||||
# user is already in local database
|
||||
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
|
||||
|
||||
login_control = LimitForbidControl::UserLogin.new(@user)
|
||||
return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
|
||||
|
||||
password_ok = @user.check_password?(params[:password].to_s)
|
||||
unless password_ok
|
||||
if login_control.remain_times-1 == 0
|
||||
normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
|
||||
else
|
||||
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
|
||||
end
|
||||
login_control.increment!
|
||||
return
|
||||
end
|
||||
|
||||
successful_authentication(@user)
|
||||
sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步
|
||||
|
||||
# session[:user_id] = @user.id
|
||||
end
|
||||
|
||||
def change_password
|
||||
@user = User.find_by(login: params[:login])
|
||||
return render_error("未找到相关用户!") if @user.blank?
|
||||
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
|
||||
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: @user.mail
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
if interactor.success?
|
||||
@user.update_attribute(:password, params[:password])
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
# 忘记密码
|
||||
def reset_password
|
||||
begin
|
||||
code = params[:code]
|
||||
login_type = phone_mail_type(params[:login].strip)
|
||||
# 获取验证码
|
||||
if login_type == 1
|
||||
phone = params[:login]
|
||||
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last
|
||||
user = User.find_by_phone(phone)
|
||||
else
|
||||
email = params[:login]
|
||||
verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last
|
||||
user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs
|
||||
end
|
||||
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
|
||||
return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
|
||||
return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
|
||||
|
||||
user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
|
||||
ActiveRecord::Base.transaction do
|
||||
user.save!
|
||||
LimitForbidControl::UserLogin.new(user).clear
|
||||
end
|
||||
sucess_status
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def successful_authentication(user)
|
||||
uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}")
|
||||
# Valid user
|
||||
self.logged_user = user
|
||||
# generate a key and set cookie if autologin
|
||||
|
||||
set_autologin_cookie(user)
|
||||
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
|
||||
user.update_column(:last_login_on, Time.now)
|
||||
session[:"#{default_yun_session}"] = user.id
|
||||
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
|
||||
# 注册完成后有一天的试用申请(先去掉)
|
||||
# UserDayCertification.create(user_id: user.id, status: 1)
|
||||
end
|
||||
|
||||
def set_autologin_cookie(user)
|
||||
token = Token.get_or_create_permanent_login_token(user, "autologin")
|
||||
sync_user_token_to_trustie(user.login, token.value)
|
||||
|
||||
cookie_options = {
|
||||
:value => token.value,
|
||||
:expires => 1.month.from_now,
|
||||
:path => '/',
|
||||
:secure => false,
|
||||
:httponly => true
|
||||
}
|
||||
if edu_setting('cookie_domain').present?
|
||||
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
|
||||
end
|
||||
cookies[autologin_cookie_name] = cookie_options
|
||||
cookies.signed[:user_id] ||= user.id
|
||||
|
||||
logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}")
|
||||
end
|
||||
|
||||
def logout
|
||||
Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}")
|
||||
UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
|
||||
logout_user
|
||||
render :json => {status: 1, message: "退出成功!"}
|
||||
end
|
||||
|
||||
# 检验邮箱是否已被注册及邮箱或者手机号是否合法
|
||||
# 参数type为事件类型 1:注册;2:忘记密码;3:绑定
|
||||
def valid_email_and_phone
|
||||
check_mail_and_phone_valid(params[:login], params[:type])
|
||||
end
|
||||
|
||||
# 发送验证码
|
||||
# params[:login] 手机号或者邮箱号
|
||||
# params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
|
||||
# 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱
|
||||
# 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效
|
||||
def get_verification_code
|
||||
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||
value = params[:login]
|
||||
type = params[:type].strip.to_i
|
||||
login_type = phone_mail_type(value)
|
||||
send_type = verify_type(login_type, type)
|
||||
verification_code = code.sample(6).join
|
||||
|
||||
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
|
||||
tip_exception(501, "请求不合理") if sign != params[:smscode]
|
||||
|
||||
logger.info "########### 验证码:#{verification_code}"
|
||||
logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ")
|
||||
|
||||
# 记录验证码
|
||||
check_verification_code(verification_code, send_type, value)
|
||||
render_ok
|
||||
end
|
||||
|
||||
# check user's login or email or phone is used
|
||||
# params[:value] 手机号或者邮箱号或者登录名
|
||||
# params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号)
|
||||
def check
|
||||
Register::CheckColumnsForm.new(check_params).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
||||
# login_type 1:手机类型 2:邮箱类型
|
||||
def verify_type login_type, type
|
||||
case type
|
||||
when 1
|
||||
login_type == 1 ? 1 : 8
|
||||
when 2
|
||||
login_type == 1 ? 2 : 3
|
||||
when 3
|
||||
login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
|
||||
when 4
|
||||
login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
|
||||
when 5
|
||||
login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
|
||||
end
|
||||
end
|
||||
|
||||
def generate_login(login)
|
||||
type = phone_mail_type(login.strip)
|
||||
|
||||
if type == 1
|
||||
uid_logger("start register by phone: type is #{type}")
|
||||
pre = 'p'
|
||||
email = nil
|
||||
phone = login
|
||||
else
|
||||
uid_logger("start register by email: type is #{type}")
|
||||
pre = 'm'
|
||||
email = login
|
||||
phone = nil
|
||||
end
|
||||
code = generate_identifier User, 8, pre
|
||||
|
||||
{ login: pre + code, email: email, phone: phone }
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:login, :email, :phone)
|
||||
end
|
||||
|
||||
def account_params
|
||||
params.require(:account).permit(:login, :password)
|
||||
end
|
||||
|
||||
def check_params
|
||||
params.permit(:type, :value)
|
||||
end
|
||||
|
||||
def register_params
|
||||
params.permit(:login, :namespace, :password, :code)
|
||||
end
|
||||
|
||||
end
|
||||
class AccountsController < ApplicationController
|
||||
before_action :require_login, only: [:login_check, :simple_update]
|
||||
include ApplicationHelper
|
||||
|
||||
#skip_before_action :check_account, :only => [:logout]
|
||||
skip_before_action :verify_authenticity_token, :only => [:remote_password]
|
||||
|
||||
def simple_update
|
||||
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
|
||||
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
|
||||
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
|
||||
Register::RemoteForm.new(simple_update_params).validate!
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
result = auto_update(current_user, simple_update_params)
|
||||
if result[:message].blank?
|
||||
render_ok
|
||||
else
|
||||
render_error(result[:message])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
render json: session
|
||||
end
|
||||
|
||||
# 其他平台同步注册的用户
|
||||
def remote_register
|
||||
# Register::RemoteForm.new(remote_register_params).validate!
|
||||
username = params[:username]&.gsub(/\s+/, "")
|
||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
||||
email = params[:email]&.gsub(/\s+/, "")
|
||||
phone = params[:phone]&.gsub(/\s+/, "")
|
||||
password = params[:password]
|
||||
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
||||
need_send_pwd_sms = false
|
||||
if params[:password].blank?
|
||||
password = SecureRandom.hex(4)
|
||||
need_send_pwd_sms = true
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
return render_error("该手机号已注册") if phone.present? && User.where(phone: phone).exists?
|
||||
result = autologin_register(username, email, password, platform, phone)
|
||||
if result[:message].blank?
|
||||
PlatformStatistic.data.increment!(:users_count)
|
||||
Gitlink::Sms.send(mobile: phone, send_type: 'init_password', code: password, user_name: username) if need_send_pwd_sms
|
||||
render_ok({user: result[:user]})
|
||||
else
|
||||
render_error(result[:message])
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
|
||||
# 其他平台同步注册的用户
|
||||
def wx_register
|
||||
#Register::RemoteForm.new(remote_register_params).validate!
|
||||
username = params[:username]&.gsub(/\s+/, "")
|
||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
||||
email = params[:email]&.gsub(/\s+/, "")
|
||||
phone = params[:phone]&.gsub(/\s+/, "")
|
||||
code = params[:code]&.gsub(/\s+/, "")
|
||||
password = SecureRandom.hex(4)
|
||||
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
||||
check_phone_code(phone, code)
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
return render_error("该手机号已注册") if phone.present? && User.where(phone: phone).exists?
|
||||
result = autologin_register(username, email, password, platform, phone)
|
||||
if result[:message].blank?
|
||||
Gitlink::Sms.send(mobile: phone, send_type: 'init_password', code: password, user_name: username)
|
||||
PlatformStatistic.data.increment!(:users_count)
|
||||
render_ok({user: result[:user]})
|
||||
else
|
||||
render_error(result[:message])
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
|
||||
# 其他平台修改用户的信息,这边同步修改
|
||||
def remote_update
|
||||
ActiveRecord::Base.transaction do
|
||||
user_params = params[:user_params]
|
||||
user_extension_params = params[:user_extension_params]
|
||||
|
||||
u = User.find_by(login: params[:old_user_login])
|
||||
user_mail = u.try(:mail)
|
||||
|
||||
if u.present?
|
||||
ue = u.user_extension
|
||||
u.login = user_params["login"] if user_params["login"]
|
||||
u.mail = user_params["mail"] if user_params["mail"]
|
||||
u.lastname = user_params["lastname"] if user_params["lastname"]
|
||||
|
||||
ue.gender = user_extension_params["gender"]
|
||||
ue.school_id = user_extension_params["school_id"]
|
||||
ue.location = user_extension_params["location"]
|
||||
ue.location_city = user_extension_params["location_city"]
|
||||
ue.identity = user_extension_params["identity"]
|
||||
ue.technical_title = user_extension_params["technical_title"]
|
||||
ue.student_id = user_extension_params["student_id"]
|
||||
ue.description = user_extension_params["description"]
|
||||
ue.save!
|
||||
u.save!
|
||||
|
||||
sync_params = {}
|
||||
|
||||
if (user_params["mail"] && user_params["mail"] != user_mail)
|
||||
sync_params = sync_params.merge(email: user_params["mail"])
|
||||
end
|
||||
|
||||
if sync_params.present?
|
||||
interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params)
|
||||
if interactor.success?
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
|
||||
# 其他平台同步登录
|
||||
def remote_login
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
if @user
|
||||
successful_authentication(@user)
|
||||
render_ok({user: {id: @user.id, token: @user.gitea_token}})
|
||||
else
|
||||
render_error("用户不存在")
|
||||
end
|
||||
end
|
||||
|
||||
#修改密码
|
||||
def remote_password
|
||||
@user = User.find_by(login: params[:login])
|
||||
return render_error("未找到相关用户!") if @user.blank?
|
||||
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: @user.mail,
|
||||
login_name: @user.login,
|
||||
source_id: 0
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
if interactor.success?
|
||||
@user.update_attribute(:password, params[:password])
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# 用户注册
|
||||
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
|
||||
# params[:login] 邮箱或者手机号
|
||||
# params[:namespace] 登录名
|
||||
# params[:code] 验证码
|
||||
# code_type 1:注册手机验证码 8:邮箱注册验证码
|
||||
# 本地forge注册入口需要重新更改逻辑
|
||||
def register
|
||||
# type只可能是1或者8
|
||||
user = nil
|
||||
begin
|
||||
Register::Form.new(register_params).validate!
|
||||
|
||||
user = Users::RegisterService.call(register_params)
|
||||
user.nickname = params[:nick_name] if params[:nick_name].present?
|
||||
user.company_name = params[:company_name] if params[:company_name].present?
|
||||
user.user_type = params[:user_type] if params[:user_type].present?
|
||||
user.professional_field = params[:professional_field] if params[:professional_field].present?
|
||||
user.mail = "#{user.login}@example.org"
|
||||
password = register_params[:password].strip
|
||||
|
||||
# gitea用户注册, email, username, password
|
||||
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(user.login, password)
|
||||
user.gitea_token = result['sha1']
|
||||
user.gitea_uid = gitea_user[:body]['id']
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
successful_authentication(user)
|
||||
render_ok
|
||||
end
|
||||
else
|
||||
tip_exception(-1, interactor.error)
|
||||
end
|
||||
rescue Register::BaseForm::EmailError => e
|
||||
render_result(-2, e.message)
|
||||
rescue Register::BaseForm::LoginError => e
|
||||
render_result(-3, e.message)
|
||||
rescue Register::BaseForm::PhoneError => e
|
||||
render_result(-4, e.message)
|
||||
rescue Register::BaseForm::PasswordFormatError => e
|
||||
render_result(-5, e.message)
|
||||
# rescue Register::BaseForm::PasswordConfirmationError => e
|
||||
# render_result(-7, e.message)
|
||||
rescue Register::BaseForm::VerifiCodeError => e
|
||||
render_result(-6, e.message)
|
||||
rescue Exception => e
|
||||
Gitea::User::DeleteService.call(user.login) unless user.nil?
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(-1, e.message)
|
||||
end
|
||||
end
|
||||
|
||||
# 用户登录
|
||||
def login
|
||||
#Users::LoginForm.new(account_params).validate!
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
|
||||
return normal_status(-2, "错误的账号或密码") if @user.blank?
|
||||
# user is already in local database
|
||||
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
|
||||
|
||||
login_control = LimitForbidControl::UserLogin.new(@user)
|
||||
return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
|
||||
|
||||
password_ok = @user.check_password?(params[:password].to_s)
|
||||
unless password_ok
|
||||
if login_control.remain_times-1 == 0
|
||||
normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
|
||||
else
|
||||
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
|
||||
end
|
||||
login_control.increment!
|
||||
return
|
||||
end
|
||||
|
||||
successful_authentication(@user)
|
||||
sync_pwd_to_gitea!(@user, { password: @user.get_source_password(params[:password].to_s) }) # TODO用户密码未同步
|
||||
|
||||
# session[:user_id] = @user.id
|
||||
end
|
||||
|
||||
def change_password
|
||||
@user = User.find_by(login: params[:login])
|
||||
return render_error("未找到相关用户!") if @user.blank?
|
||||
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
|
||||
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: @user.mail,
|
||||
login_name: @user.login,
|
||||
source_id: 0
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
if interactor.success?
|
||||
@user.update_attribute(:password, params[:password])
|
||||
render_ok
|
||||
else
|
||||
render_error(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
# 忘记密码
|
||||
def reset_password
|
||||
begin
|
||||
code = params[:code]
|
||||
login_type = phone_mail_type(params[:login].strip)
|
||||
# 获取验证码
|
||||
if login_type == 1
|
||||
phone = params[:login]
|
||||
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last
|
||||
user = User.find_by_phone(phone)
|
||||
else
|
||||
email = params[:login]
|
||||
verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last
|
||||
user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs
|
||||
end
|
||||
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
|
||||
return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
|
||||
return normal_status(-1, "8~20位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
|
||||
|
||||
sync_params = {
|
||||
password: params[:new_password].to_s,
|
||||
email: user.mail,
|
||||
login_name: user.login,
|
||||
source_id: 0
|
||||
}
|
||||
user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
|
||||
ActiveRecord::Base.transaction do
|
||||
user.save!
|
||||
Gitea::User::UpdateInteractor.call(user.login, sync_params)
|
||||
LimitForbidControl::UserLogin.new(user).clear
|
||||
end
|
||||
sucess_status
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def successful_authentication(user)
|
||||
uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}")
|
||||
# Valid user
|
||||
self.logged_user = user
|
||||
# generate a key and set cookie if autologin
|
||||
|
||||
set_autologin_cookie(user)
|
||||
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
|
||||
user.update_column(:last_login_on, Time.now)
|
||||
session[:"#{default_yun_session}"] = user.id
|
||||
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
|
||||
# 注册完成后有一天的试用申请(先去掉)
|
||||
# UserDayCertification.create(user_id: user.id, status: 1)
|
||||
end
|
||||
|
||||
def set_autologin_cookie(user)
|
||||
token = Token.get_or_create_permanent_login_token(user, autologin_action)
|
||||
cookie_options = {
|
||||
:value => token.value,
|
||||
:expires => 1.month.from_now,
|
||||
:path => '/',
|
||||
:secure => false,
|
||||
:httponly => true
|
||||
}
|
||||
if edu_setting('cookie_domain').present?
|
||||
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
|
||||
end
|
||||
cookies[autologin_cookie_name] = cookie_options
|
||||
cookies.signed[:user_id] ||= user.id
|
||||
|
||||
logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}")
|
||||
end
|
||||
|
||||
def logout
|
||||
Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}")
|
||||
UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
|
||||
logout_user
|
||||
render :json => {status: 1, message: "退出成功!"}
|
||||
end
|
||||
|
||||
# 检验邮箱是否已被注册及邮箱或者手机号是否合法
|
||||
# 参数type为事件类型 1:注册;2:忘记密码;3:绑定
|
||||
def valid_email_and_phone
|
||||
check_mail_and_phone_valid(params[:login], params[:type])
|
||||
end
|
||||
|
||||
# 发送验证码
|
||||
# params[:login] 手机号或者邮箱号
|
||||
# params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
|
||||
# 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱
|
||||
# 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效
|
||||
def get_verification_code
|
||||
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||
value = params[:login]
|
||||
type = params[:type].strip.to_i
|
||||
login_type = phone_mail_type(value)
|
||||
send_type = verify_type(login_type, type)
|
||||
verification_code = code.sample(6).join
|
||||
|
||||
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
|
||||
tip_exception(501, "请求不合理") if sign != params[:smscode]
|
||||
|
||||
logger.info "########### 验证码:#{verification_code}"
|
||||
logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ")
|
||||
|
||||
# 记录验证码
|
||||
check_verification_code(verification_code, send_type, value)
|
||||
render_ok
|
||||
end
|
||||
|
||||
# check user's login or email or phone is used
|
||||
# params[:value] 手机号或者邮箱号或者登录名
|
||||
# params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号)
|
||||
def check
|
||||
Register::CheckColumnsForm.new(check_params).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
def login_check
|
||||
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_phone_code(phone, code)
|
||||
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
|
||||
code = strip(code)
|
||||
return if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试
|
||||
|
||||
raise VerifiCodeError, "验证码不正确" if verifi_code&.code != code
|
||||
raise VerifiCodeError, "验证码已失效" if !verifi_code&.effective?
|
||||
end
|
||||
|
||||
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
||||
# login_type 1:手机类型 2:邮箱类型
|
||||
def verify_type login_type, type
|
||||
case type
|
||||
when 1
|
||||
login_type == 1 ? 1 : 8
|
||||
when 2
|
||||
login_type == 1 ? 2 : 3
|
||||
when 3
|
||||
login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
|
||||
when 4
|
||||
login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
|
||||
when 5
|
||||
login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
|
||||
end
|
||||
end
|
||||
|
||||
def generate_login(login)
|
||||
type = phone_mail_type(login.strip)
|
||||
|
||||
if type == 1
|
||||
uid_logger("start register by phone: type is #{type}")
|
||||
pre = 'p'
|
||||
email = nil
|
||||
phone = login
|
||||
else
|
||||
uid_logger("start register by email: type is #{type}")
|
||||
pre = 'm'
|
||||
email = login
|
||||
phone = nil
|
||||
end
|
||||
code = generate_identifier User, 8, pre
|
||||
|
||||
{ login: pre + code, email: email, phone: phone }
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:login, :email, :phone)
|
||||
end
|
||||
|
||||
def account_params
|
||||
params.require(:account).permit(:login, :password)
|
||||
end
|
||||
|
||||
def check_params
|
||||
params.permit(:type, :value)
|
||||
end
|
||||
|
||||
def register_params
|
||||
params.permit(:login, :namespace, :password, :code)
|
||||
end
|
||||
|
||||
def remote_register_params
|
||||
params.permit(:username, :email, :password, :platform)
|
||||
end
|
||||
|
||||
def simple_update_params
|
||||
params.permit(:username, :email, :password, :platform)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
class Admins::ApplySignaturesController < Admins::BaseController
|
||||
|
||||
def index
|
||||
sort_by = params[:sort_by] ||= 'created_on'
|
||||
sort_direction = params[:sort_direction] ||= 'desc'
|
||||
|
||||
@apply_signatures = paginate ApplySignature.waiting.includes(:attachments)
|
||||
end
|
||||
|
||||
def update
|
||||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
apply_signature = ApplySignature.find_by!(id: params[:id])
|
||||
apply_signature.update_attributes!(apply_signatures_params)
|
||||
if apply_signature.status == "passed"
|
||||
Projects::AddMemberInteractor.call(apply_signature.project.owner, apply_signature.project, apply_signature.user, "read", true)
|
||||
end
|
||||
redirect_to admins_apply_signatures_path
|
||||
flash[:success] = "更新成功"
|
||||
rescue => e
|
||||
raise ActiveRecord::Rollback
|
||||
redirect_to admins_apply_signatures_path
|
||||
flash[:danger] = "更新失败"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def apply_signatures_params
|
||||
params.permit(:status)
|
||||
end
|
||||
end
|
|
@ -1,10 +1,33 @@
|
|||
class Admins::DashboardsController < Admins::BaseController
|
||||
def index
|
||||
@active_user_count = User.where(last_login_on: today).count
|
||||
@weekly_active_user_count = User.where(last_login_on: current_week).count
|
||||
@month_active_user_count = User.where(last_login_on: current_month).count
|
||||
# 用户活跃数
|
||||
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
|
||||
month_user_ids = CommitLog.where(created_at: current_month).pluck(:user_id).uniq
|
||||
@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
|
||||
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
||||
user_ids = User.where(created_on: pre_week).pluck(:id).uniq
|
||||
weekly_keep_user_count = User.where(id: user_ids).where(last_login_on: current_week).count
|
||||
@weekly_keep_rate = format("%.2f", user_ids.size > 0 ? weekly_keep_user_count.to_f / user_ids.size : 0)
|
||||
|
||||
@new_user_count = User.where(created_on: current_month).count
|
||||
# 新用户注册数
|
||||
@day_new_user_count = User.where(created_on: today).count
|
||||
@weekly_new_user_count = User.where(created_on: current_week).count
|
||||
@month_new_user_count = User.where(created_on: current_month).count
|
||||
|
||||
# 活跃项目数
|
||||
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
|
||||
month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + 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
|
||||
@weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
|
||||
@month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count
|
||||
|
||||
# 新增项目数
|
||||
@day_new_project_count = Project.where(created_on: today).count
|
||||
@weekly_new_project_count = Project.where(created_on: current_week).count
|
||||
@month_new_project_count = Project.where(created_on: current_month).count
|
||||
end
|
||||
|
||||
def month_active_user
|
||||
|
@ -42,10 +65,14 @@ class Admins::DashboardsController < Admins::BaseController
|
|||
end
|
||||
|
||||
def current_week
|
||||
7.days.ago.beginning_of_day..Time.now.end_of_day
|
||||
7.days.ago.end_of_day..Time.now.end_of_day
|
||||
end
|
||||
|
||||
def current_month
|
||||
30.days.ago.beginning_of_day..Time.now.end_of_day
|
||||
30.days.ago.end_of_day..Time.now.end_of_day
|
||||
end
|
||||
|
||||
def pre_week
|
||||
14.days.ago.end_of_day..7.days.ago.end_of_day
|
||||
end
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
class Admins::FeedbacksController < Admins::BaseController
|
||||
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
||||
|
||||
def index
|
||||
sort_by = Feedback.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
feedbacks = Feedback.order("#{sort_by} #{sort_direction}")
|
||||
@feedbacks = paginate(feedbacks)
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @feedback.destroy
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:success] = "反馈意见删除成功"
|
||||
else
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:danger] = "反馈意见删除失败"
|
||||
end
|
||||
end
|
||||
|
||||
def new_history
|
||||
@feedback_message_history = FeedbackMessageHistory.new
|
||||
end
|
||||
|
||||
def create_history
|
||||
@feedback_message_history = @feedback.feedback_message_histories.new(feedback_message_history_params)
|
||||
@feedback_message_history.user = current_user
|
||||
if @feedback_message_history.save
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:success] = "发送通知成功"
|
||||
else
|
||||
redirect_to admins_feedbacks_path
|
||||
flash[:danger] = @feedback_message_history.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def feedback_params
|
||||
params.require(:feedback).permit!
|
||||
end
|
||||
|
||||
def feedback_message_history_params
|
||||
params.require(:feedback_message_history).permit(:title, :content)
|
||||
end
|
||||
|
||||
def get_feedback
|
||||
@feedback = Feedback.find_by_id(params[:id])
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
|
|||
def create
|
||||
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
result = Admins::ImportUserService.call(params[:file].to_io)
|
||||
result = Admins::ImportUserFromExcelService.call(params[:file].to_io)
|
||||
render_ok(result)
|
||||
rescue Admins::ImportUserService::Error => ex
|
||||
render_error(ex)
|
||||
|
|
|
@ -2,8 +2,24 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
before_action :get_template, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
message_templates = MessageTemplate.group(:type).count.keys
|
||||
@message_templates = kaminari_array_paginate(message_templates)
|
||||
message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result
|
||||
@message_templates = kaminari_paginate(message_templates)
|
||||
end
|
||||
|
||||
def new
|
||||
@message_template = MessageTemplate.new
|
||||
end
|
||||
|
||||
def create
|
||||
@message_template = MessageTemplate::CustomTip.new(message_template_params)
|
||||
@message_template.type = "MessageTemplate::CustomTip"
|
||||
if @message_template.save!
|
||||
redirect_to admins_message_templates_path
|
||||
flash[:success] = "创建消息模板成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建消息模板失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -31,7 +47,9 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
|
||||
private
|
||||
def message_template_params
|
||||
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
|
||||
# type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
|
||||
# params.require(type.split("::").join("_").underscore.to_sym).permit!
|
||||
params.require(:message_template).permit!
|
||||
end
|
||||
|
||||
def get_template
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
class Admins::NpsController < Admins::BaseController
|
||||
def index
|
||||
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
||||
@user_nps = UserNp.joins(:user).order(created_at: :desc)
|
||||
keyword = params[:keyword].to_s.strip.presence
|
||||
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'
|
||||
@user_nps = @user_nps.where(sql, keyword: "%#{keyword}%")
|
||||
end
|
||||
@user_nps = @user_nps.where("action_type != 'close'") if params[:done_score].present?
|
||||
@min_score = @user_nps.where("action_type != 'close'").minimum("score")
|
||||
@max_score = @user_nps.where("action_type != 'close'").maximum("score")
|
||||
@score_total_count = UserNp.where("action_type !='close'").count
|
||||
@user_nps = paginate @user_nps.includes(:user)
|
||||
end
|
||||
|
||||
def switch_change
|
||||
edu_setting = EduSetting.find_by(name: "nps-on-off-switch")
|
||||
if edu_setting.blank?
|
||||
edu_setting = EduSetting.new(name: "nps-on-off-switch")
|
||||
end
|
||||
edu_setting.value = params[:switch].to_s
|
||||
edu_setting.save
|
||||
render_ok
|
||||
end
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
class Admins::PhengleiUsersController < Admins::BaseController
|
||||
before_action :phenglei_project, only: [:index]
|
||||
|
||||
def index
|
||||
if params[:keyword].present?
|
||||
@phenglei_users = PhengleiUser.ransack(phone_cont: params[:keyword]).result
|
||||
else
|
||||
@phenglei_users = PhengleiUser
|
||||
end
|
||||
@phenglei_users = @phenglei_users.page(page).per(per_page)
|
||||
end
|
||||
|
||||
def new
|
||||
@phenglei_user = PhengleiUser.new
|
||||
end
|
||||
|
||||
def create
|
||||
@phenglei_user = PhengleiUser.new(phenglei_user_params)
|
||||
if @phenglei_user.save
|
||||
redirect_to admins_phenglei_users_path
|
||||
flash[:success] = "创建成功"
|
||||
else
|
||||
redirect_to admins_phenglei_users_path
|
||||
flash[:error] = "创建失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def phenglei_project
|
||||
@phenglei_project = Project.find_by_id(EduSetting.get("sync_phenglei_user_project"))
|
||||
end
|
||||
|
||||
def phenglei_user_params
|
||||
params.require(:phenglei_user).permit(:phone)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,97 @@
|
|||
class Admins::PlatformCommunicatesController < Admins::BaseController
|
||||
before_action :get_communicate, only: [:edit, :update, :destroy, :show, :online_switch]
|
||||
|
||||
def index
|
||||
params[:location] = "pc"
|
||||
sort_by = PlatformCommunicate.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'order_index'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
q = PlatformCommunicate.where(location: params[:location]).ransack(title_cont: params[:search])
|
||||
communicates = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
||||
@communicates = kaminari_paginate(communicates)
|
||||
end
|
||||
|
||||
def applet
|
||||
params[:location] = "applet"
|
||||
sort_by = PlatformCommunicate.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'order_index'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
q = PlatformCommunicate.where(location: params[:location]).ransack(title_cont: params[:search])
|
||||
communicates = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
||||
@communicates = kaminari_paginate(communicates)
|
||||
end
|
||||
|
||||
def show
|
||||
watchers = @communicate.watchers
|
||||
if params[:search].present?
|
||||
like_sql = 'users.lastname LIKE :keyword OR users.nickname LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword OR users.login LIKE :keyword OR users.company_name LIKE :keyword'
|
||||
watchers = watchers.left_joins(:user).where(like_sql, keyword: "%#{params[:search]}%")
|
||||
end
|
||||
if params[:user_type].present?
|
||||
watchers = watchers.left_joins(:user).where("users.user_type = ?", params[:user_type])
|
||||
end
|
||||
if params[:professional_field].present?
|
||||
watchers = watchers.left_joins(:user).where("users.professional_field = ?", params[:professional_field])
|
||||
end
|
||||
@watchers = kaminari_paginate watchers
|
||||
end
|
||||
|
||||
def new
|
||||
location = params[:location] || "pc"
|
||||
@communicate = PlatformCommunicate.new(location: location)
|
||||
end
|
||||
|
||||
def create
|
||||
@communicate = PlatformCommunicate.new(communicate_params)
|
||||
if @communicate.save
|
||||
redirect_to @communicate.location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:success] = '创建成功'
|
||||
else
|
||||
redirect_to @communicate.location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:danger] = "创建失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
|
||||
end
|
||||
|
||||
def update
|
||||
@communicate.attributes = communicate_params
|
||||
if @communicate.save
|
||||
redirect_to @communicate.location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:success] = '更新成功'
|
||||
else
|
||||
redirect_to @communicate.location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:danger] = '更新失败'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
location = @communicate.location
|
||||
if @communicate.destroy
|
||||
redirect_to location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:success] = '删除成功'
|
||||
else
|
||||
redirect_to location == 'pc' ? "/admins/platform_communicates?location=pc" : "/admins/platform_communicates/applet?location=applet"
|
||||
flash[:danger] = '删除失败'
|
||||
end
|
||||
end
|
||||
|
||||
def online_switch
|
||||
if @communicate.status
|
||||
@communicate.update_attributes!(status: false)
|
||||
else
|
||||
@communicate.update_attributes!(status: true)
|
||||
end
|
||||
# render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_communicate
|
||||
@communicate = PlatformCommunicate.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def communicate_params
|
||||
params.require(:platform_communicate).permit!
|
||||
end
|
||||
end
|
|
@ -0,0 +1,69 @@
|
|||
class Admins::PlatformPeopleController < Admins::BaseController
|
||||
before_action :get_person, only: [:edit, :update, :destroy]
|
||||
def index
|
||||
sort_by = PlatformPerson.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
q = PlatformPerson.ransack(name_cont: params[:search])
|
||||
people = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
||||
@people = kaminari_paginate(people)
|
||||
end
|
||||
|
||||
def new
|
||||
@person = PlatformPerson.new
|
||||
end
|
||||
|
||||
def create
|
||||
@person = PlatformPerson.new(person_params)
|
||||
if @person.save
|
||||
save_image_file(params[:image], @person)
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:success] = '创建论坛交流人物成功'
|
||||
else
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:danger] = "创建论坛交流人物失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
|
||||
end
|
||||
|
||||
def update
|
||||
@person.attributes = person_params
|
||||
if @person.save
|
||||
save_image_file(params[:image], @person)
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:success] = '更新论坛交流人物成功'
|
||||
else
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:danger] = '更新论坛交流人物失败'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @person.destroy
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:success] = '删除论坛交流人物成功'
|
||||
else
|
||||
redirect_to admins_platform_people_path
|
||||
flash[:danger] = '删除论坛交流人物失败'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def get_person
|
||||
@person = PlatformPerson.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def person_params
|
||||
params.require(:platform_person).permit!
|
||||
end
|
||||
|
||||
def save_image_file(file, topic)
|
||||
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
file_path = Util::FileManage.source_disk_filename(topic, 'image')
|
||||
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
|
||||
Util.write_file(file, file_path)
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
def index
|
||||
sort_by = ProjectCategory.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
q = ProjectCategory.ransack(name_cont: params[:name])
|
||||
q = ProjectCategory.ransack(name_cont: params[:search])
|
||||
project_categories = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
||||
@project_categories = paginate(project_categories)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
||||
before_action :validate_params, only: [:create, :update]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
def index
|
||||
sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
|
@ -31,12 +31,12 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
# }
|
||||
@project_ignore = Ignore.new(ignore_params)
|
||||
|
||||
if @project_ignore.save!
|
||||
if @project_ignore.save
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:success] = "创建成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建失败"
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -58,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
redirect_to admins_project_ignores_path
|
||||
flash[:success] = "更新成功"
|
||||
else
|
||||
render :edit
|
||||
flash[:danger] = "更新失败"
|
||||
redirect_to admins_project_ignores_path
|
||||
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
|||
params.require(:ignore).permit(:name,:content)
|
||||
end
|
||||
|
||||
def validate_params
|
||||
name = params[:ignore][:name]
|
||||
if name.blank?
|
||||
flash[:danger] = "名称不允许为空"
|
||||
redirect_to admins_project_ignores_path
|
||||
elsif check_ignore_present?(name) && @project_ignore.blank?
|
||||
flash[:danger] = "创建失败:名称已存在"
|
||||
redirect_to admins_project_ignores_path
|
||||
end
|
||||
end
|
||||
# def validate_params
|
||||
# name = params[:ignore][:name]
|
||||
# if name.blank?
|
||||
# flash[:danger] = "名称不允许为空"
|
||||
# redirect_to admins_project_ignores_path
|
||||
# elsif check_ignore_present?(name) && @project_ignore.blank?
|
||||
# flash[:danger] = "创建失败:名称已存在"
|
||||
# redirect_to admins_project_ignores_path
|
||||
# end
|
||||
# end
|
||||
|
||||
def check_ignore_present?(name)
|
||||
return true if name.blank?
|
||||
name_downcase = name.downcase
|
||||
name_upcase = name.upcase
|
||||
name_first_big = name.capitalize
|
||||
Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
||||
end
|
||||
# def check_ignore_present?(name)
|
||||
# return true if name.blank?
|
||||
# name_downcase = name.downcase
|
||||
# name_upcase = name.upcase
|
||||
# name_first_big = name.capitalize
|
||||
# Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
||||
# end
|
||||
|
||||
end
|
||||
|
|
|
@ -27,17 +27,18 @@ class Admins::ProjectLanguagesController < Admins::BaseController
|
|||
flash[:success] = '创建成功'
|
||||
else
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:danger] = '创建失败'
|
||||
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @project_language.update_attribute(:name, @name)
|
||||
@project_language.attributes = {name: @name}
|
||||
if @project_language.save
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:success] = '更新成功'
|
||||
else
|
||||
redirect_to admins_project_languages_path
|
||||
flash[:success] = '更新失败'
|
||||
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Admins::ProjectLicensesController < Admins::BaseController
|
||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
||||
before_action :validate_params, only: [:create, :update]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
def index
|
||||
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
|
@ -30,13 +30,12 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
# position: max_position
|
||||
# }
|
||||
@project_license = License.new(license_params)
|
||||
|
||||
if @project_license.save!
|
||||
if @project_license.save
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:success] = "创建成功"
|
||||
else
|
||||
render :new
|
||||
flash[:danger] = "创建失败"
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -54,12 +53,13 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
# permissions: permissions.to_s,
|
||||
# limitations: limitations.to_s
|
||||
# }
|
||||
if @project_license.update_attributes(license_params)
|
||||
@project_license.attributes = license_params
|
||||
if @project_license.save
|
||||
redirect_to admins_project_licenses_path
|
||||
flash[:success] = "更新成功"
|
||||
else
|
||||
render :edit
|
||||
flash[:danger] = "更新失败"
|
||||
render admins_project_licenses_path
|
||||
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,23 +98,23 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
|||
params.require(:license).permit(:name,:content)
|
||||
end
|
||||
|
||||
def validate_params
|
||||
name = params[:license][:name]
|
||||
if name.blank?
|
||||
flash[:danger] = "名称不允许为空"
|
||||
redirect_to admins_project_licenses_path
|
||||
elsif check_license_present?(name) && @project_license.blank?
|
||||
flash[:danger] = "创建失败:名称已存在"
|
||||
redirect_to admins_project_licenses_path
|
||||
end
|
||||
end
|
||||
# def validate_params
|
||||
# name = params[:license][:name]
|
||||
# if name.blank?
|
||||
# flash[:danger] = "名称不允许为空"
|
||||
# redirect_to admins_project_licenses_path
|
||||
# elsif check_license_present?(name) && @project_license.blank?
|
||||
# flash[:danger] = "创建失败:名称已存在"
|
||||
# redirect_to admins_project_licenses_path
|
||||
# end
|
||||
# end
|
||||
|
||||
def check_license_present?(name)
|
||||
return true if name.blank?
|
||||
name_downcase = name.downcase
|
||||
name_upcase = name.upcase
|
||||
name_first_big = name.capitalize
|
||||
License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
||||
end
|
||||
# def check_license_present?(name)
|
||||
# return true if name.blank?
|
||||
# name_downcase = name.downcase
|
||||
# name_upcase = name.upcase
|
||||
# name_first_big = name.capitalize
|
||||
# License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
||||
# end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
class Admins::ProjectsController < Admins::BaseController
|
||||
before_action :find_project, only: [:edit, :update]
|
||||
before_action :find_project, only: [:edit, :update, :sync_phenglei_user]
|
||||
|
||||
def index
|
||||
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'
|
||||
search = params[:search].to_s.strip
|
||||
projects = Project.where("name like ?", "%#{search}%").order("#{sort_by} #{sort_direction}")
|
||||
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
|
||||
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score, :license)
|
||||
end
|
||||
|
||||
def edit ;end
|
||||
|
@ -43,6 +43,28 @@ class Admins::ProjectsController < Admins::BaseController
|
|||
flash[:danger] = "删除失败"
|
||||
end
|
||||
|
||||
def export
|
||||
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'
|
||||
search = params[:search].to_s.strip
|
||||
projects = Project.where("name like ?", "%#{search}%").order("#{sort_by} #{sort_direction}")
|
||||
@projects = projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score, :license)
|
||||
filename = ["项目列表", Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
|
||||
@domain_url = EduSetting.get('host_name')
|
||||
render xlsx: 'export', filename: filename
|
||||
end
|
||||
|
||||
def sync_phenglei_user
|
||||
if @project.is_secret
|
||||
SyncPhengleiUserJob.perform_later(@project.id)
|
||||
redirect_to admins_phenglei_users_path
|
||||
flash[:success] = "已开启后台同步任务"
|
||||
else
|
||||
redirect_to admins_phenglei_users_path
|
||||
flash[:danger] = "非风雷协议项目"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_project
|
||||
@project = Project.find_by_id(params[:id])
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::ActivityForumsController < Admins::Topic::BaseController
|
||||
before_action :find_activity_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::ActivityForum.ransack(title_cont: params[:search])
|
||||
activity_forums = q.result(distinct: true)
|
||||
@activity_forums = paginate(activity_forums)
|
||||
end
|
||||
|
||||
def new
|
||||
@activity_forum = ::Topic::ActivityForum.new
|
||||
end
|
||||
|
||||
def create
|
||||
@activity_forum = ::Topic::ActivityForum.new(activity_forum_params)
|
||||
if @activity_forum.save
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:success] = "新增平台动态成功"
|
||||
else
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:danger] = "新增平台动态失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@activity_forum.attributes = activity_forum_params
|
||||
if @activity_forum.save
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:success] = "更新平台动态成功"
|
||||
else
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:danger] = "更新平台动态失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @activity_forum.destroy
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:success] = "删除平台动态成功"
|
||||
else
|
||||
redirect_to admins_topic_activity_forums_path
|
||||
flash[:danger] = "删除平台动态失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_activity_forum
|
||||
@activity_forum = ::Topic::ActivityForum.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def activity_forum_params
|
||||
params.require(:topic_activity_forum).permit(:title, :uuid, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
class Admins::Topic::AppletBannersController < Admins::Topic::BaseController
|
||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@banners = ::Topic::AppletBanner
|
||||
@banners = @banners.where("title like ?", "%#{params[:search]}%") if params[:search].present?
|
||||
@banners = @banners.where(location: params[:location]) if params[:location].present?
|
||||
@banners = paginate(@banners)
|
||||
end
|
||||
|
||||
def new
|
||||
@banner = ::Topic::AppletBanner.new
|
||||
end
|
||||
|
||||
def create
|
||||
@banner = ::Topic::AppletBanner.new(banner_params)
|
||||
if @banner.save
|
||||
save_image_file(params[:image], @banner)
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:success] = "新增banner成功"
|
||||
else
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:danger] = "新增banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@banner.attributes = banner_params
|
||||
if @banner.save
|
||||
save_image_file(params[:image], @banner)
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:success] = "更新banner成功"
|
||||
else
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:danger] = "更新banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @banner.destroy
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:success] = "删除banner成功"
|
||||
else
|
||||
redirect_to admins_topic_applet_banners_path
|
||||
flash[:danger] = "删除banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_banner
|
||||
@banner = ::Topic::AppletBanner.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def banner_params
|
||||
params.require(:topic_applet_banner).permit(:title, :order_index, :url, :location)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@banners = paginate(::Topic::Banner)
|
||||
@banners = paginate(::Topic::Banner.where("title like ?", "%#{params[:search]}%")) if params[:search].present?
|
||||
end
|
||||
|
||||
def new
|
||||
@banner = ::Topic::Banner.new
|
||||
end
|
||||
|
||||
def create
|
||||
@banner = ::Topic::Banner.new(banner_params)
|
||||
if @banner.save
|
||||
save_image_file(params[:image], @banner)
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:success] = "新增banner成功"
|
||||
else
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:danger] = "新增banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@banner.attributes = banner_params
|
||||
if @banner.save
|
||||
save_image_file(params[:image], @banner)
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:success] = "更新banner成功"
|
||||
else
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:danger] = "更新banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @banner.destroy
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:success] = "删除banner成功"
|
||||
else
|
||||
redirect_to admins_topic_banners_path
|
||||
flash[:danger] = "删除banner失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_banner
|
||||
@banner = ::Topic::Banner.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def banner_params
|
||||
params.require(:topic_banner).permit(:title, :order_index, :url)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
class Admins::Topic::BaseController < Admins::BaseController
|
||||
|
||||
protected
|
||||
def save_image_file(file, topic)
|
||||
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
file_path = Util::FileManage.source_disk_filename(topic, 'image')
|
||||
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
|
||||
Util.write_file(file, file_path)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::CardsController < Admins::Topic::BaseController
|
||||
before_action :find_card, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::Card.ransack(title_cont: params[:search])
|
||||
cards = q.result(distinct: true)
|
||||
@cards = paginate(cards)
|
||||
end
|
||||
|
||||
def new
|
||||
@card = ::Topic::Card.new
|
||||
end
|
||||
|
||||
def create
|
||||
@card = ::Topic::Card.new(card_params)
|
||||
if @card.save
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:success] = "新增合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:danger] = "新增合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@card.attributes = card_params
|
||||
if @card.save
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:success] = "更新合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:danger] = "更新合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @card.destroy
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:success] = "删除合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cards_path
|
||||
flash[:danger] = "删除合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_card
|
||||
@card = ::Topic::Card.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def card_params
|
||||
params.require(:topic_card).permit(:title, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::CooperatorsController < Admins::Topic::BaseController
|
||||
before_action :find_cooperator, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@cooperators = paginate(::Topic::Cooperator)
|
||||
end
|
||||
|
||||
def new
|
||||
@cooperator = ::Topic::Cooperator.new
|
||||
end
|
||||
|
||||
def create
|
||||
@cooperator = ::Topic::Cooperator.new(cooperator_params)
|
||||
if @cooperator.save
|
||||
save_image_file(params[:image], @cooperator)
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:success] = "新增合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:danger] = "新增合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@cooperator.attributes = cooperator_params
|
||||
if @cooperator.save
|
||||
save_image_file(params[:image], @cooperator)
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:success] = "更新合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:danger] = "更新合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @cooperator.destroy
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:success] = "删除合作单位成功"
|
||||
else
|
||||
redirect_to admins_topic_cooperators_path
|
||||
flash[:danger] = "删除合作单位失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_cooperator
|
||||
@cooperator = ::Topic::Cooperator.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def cooperator_params
|
||||
params.require(:topic_cooperator).permit(:title, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::ExcellentProjectsController < Admins::Topic::BaseController
|
||||
before_action :find_excellent_project, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::ExcellentProject.ransack(title_cont: params[:search])
|
||||
excellent_projects = q.result(distinct: true)
|
||||
@excellent_projects = paginate(excellent_projects)
|
||||
end
|
||||
|
||||
def new
|
||||
@excellent_project = ::Topic::ExcellentProject.new
|
||||
end
|
||||
|
||||
def create
|
||||
@excellent_project = ::Topic::ExcellentProject.new(excellent_project_params)
|
||||
if @excellent_project.save
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:success] = "新增优秀仓库成功"
|
||||
else
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:danger] = "新增优秀仓库失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@excellent_project.attributes = excellent_project_params
|
||||
if @excellent_project.save
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:success] = "更新优秀仓库成功"
|
||||
else
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:danger] = "更新优秀仓库失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @excellent_project.destroy
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:success] = "删除优秀仓库成功"
|
||||
else
|
||||
redirect_to admins_topic_excellent_projects_path
|
||||
flash[:danger] = "删除优秀仓库失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_excellent_project
|
||||
@excellent_project = ::Topic::ExcellentProject.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def excellent_project_params
|
||||
params.require(:topic_excellent_project).permit(:title, :uuid, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::ExperienceForumsController < Admins::Topic::BaseController
|
||||
before_action :find_experience_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::ExperienceForum.ransack(title_cont: params[:search])
|
||||
experience_forums = q.result(distinct: true)
|
||||
@experience_forums = paginate(experience_forums)
|
||||
end
|
||||
|
||||
def new
|
||||
@experience_forum = ::Topic::ExperienceForum.new
|
||||
end
|
||||
|
||||
def create
|
||||
@experience_forum = ::Topic::ExperienceForum.new(experience_forum_params)
|
||||
if @experience_forum.save
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:success] = "新增经验分享成功"
|
||||
else
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:danger] = "新增经验分享失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@experience_forum.attributes = experience_forum_params
|
||||
if @experience_forum.save
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:success] = "更新经验分享成功"
|
||||
else
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:danger] = "更新经验分享失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @experience_forum.destroy
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:success] = "删除经验分享成功"
|
||||
else
|
||||
redirect_to admins_topic_experience_forums_path
|
||||
flash[:danger] = "删除经验分享失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_experience_forum
|
||||
@experience_forum = ::Topic::ExperienceForum.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def experience_forum_params
|
||||
params.require(:topic_experience_forum).permit(:title, :uuid, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
|
||||
before_action :find_glcc, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::GlccNews.ransack(title_cont: params[:search])
|
||||
glcc_news = q.result(distinct: true)
|
||||
@glcc_news = paginate(glcc_news)
|
||||
end
|
||||
|
||||
def new
|
||||
@glcc = ::Topic::GlccNews.new
|
||||
end
|
||||
|
||||
def create
|
||||
@glcc = ::Topic::GlccNews.new(glcc_params)
|
||||
if @glcc.save
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:success] = "新增新闻稿成功"
|
||||
else
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:danger] = "新增新闻稿失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@glcc.attributes = glcc_params
|
||||
if @glcc.save
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:success] = "更新新闻稿成功"
|
||||
else
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:danger] = "更新新闻稿失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @glcc.destroy
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:success] = "删除新闻稿成功"
|
||||
else
|
||||
redirect_to admins_topic_glcc_news_index_path
|
||||
flash[:danger] = "删除新闻稿失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_glcc
|
||||
@glcc = ::Topic::GlccNews.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def glcc_params
|
||||
params.require(:topic_glcc_news).permit(:title, :uuid, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::OrganizationsController < Admins::Topic::BaseController
|
||||
before_action :find_organization, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@organizations = paginate(::Topic::Organization)
|
||||
end
|
||||
|
||||
def new
|
||||
@organization = ::Topic::Organization.new
|
||||
end
|
||||
|
||||
def create
|
||||
@organization = ::Topic::Organization.new(organization_params)
|
||||
if @organization.save
|
||||
save_image_file(params[:image], @organization)
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:success] = "新增组织logo成功"
|
||||
else
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:danger] = "新增组织logo失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@organization.attributes = organization_params
|
||||
if @organization.save
|
||||
save_image_file(params[:image], @organization)
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:success] = "更新组织logo成功"
|
||||
else
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:danger] = "更新组织logo失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @organization.destroy
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:success] = "删除组织logo成功"
|
||||
else
|
||||
redirect_to admins_topic_organizations_path
|
||||
flash[:danger] = "删除组织logo失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_organization
|
||||
@organization = ::Topic::Organization.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def organization_params
|
||||
params.require(:topic_organization).permit(:title, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Admins::Topic::PinnedForumsController < Admins::Topic::BaseController
|
||||
before_action :find_pinned_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
q = ::Topic::PinnedForum.ransack(title_cont: params[:search])
|
||||
pinned_forums = q.result(distinct: true)
|
||||
@pinned_forums = paginate(pinned_forums)
|
||||
end
|
||||
|
||||
def new
|
||||
@pinned_forum = ::Topic::PinnedForum.new
|
||||
end
|
||||
|
||||
def create
|
||||
@pinned_forum = ::Topic::PinnedForum.new(pinned_forum_params)
|
||||
if @pinned_forum.save
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:success] = "新增精选文章成功"
|
||||
else
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:danger] = "新增精选文章失败"
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@pinned_forum.attributes = pinned_forum_params
|
||||
if @pinned_forum.save
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:success] = "更新精选文章成功"
|
||||
else
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:danger] = "更新精选文章失败"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @pinned_forum.destroy
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:success] = "删除精选文章成功"
|
||||
else
|
||||
redirect_to admins_topic_pinned_forums_path
|
||||
flash[:danger] = "删除精选文章失败"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_pinned_forum
|
||||
@pinned_forum = ::Topic::PinnedForum.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def pinned_forum_params
|
||||
params.require(:topic_pinned_forum).permit(:title, :uuid, :url, :order_index)
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::UsersController < Admins::BaseController
|
||||
before_action :finder_user, except: [:index]
|
||||
before_action :finder_user, except: [:index, :export]
|
||||
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
|
@ -24,6 +24,16 @@ class Admins::UsersController < Admins::BaseController
|
|||
render 'edit'
|
||||
end
|
||||
|
||||
def export
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||
|
||||
users = Admins::UserQuery.call(params)
|
||||
@users = users.includes(:user_extension, projects: :members)
|
||||
filename = ["用户列表", Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
|
||||
render xlsx: 'export', filename: filename
|
||||
end
|
||||
|
||||
def destroy
|
||||
@user.destroy!
|
||||
Gitea::User::DeleteService.call(@user.login)
|
||||
|
@ -57,7 +67,50 @@ class Admins::UsersController < Admins::BaseController
|
|||
render_ok
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create
|
||||
Users::AdminCreateUserForm.new(validate_create_params).validate!
|
||||
|
||||
user = User.new(create_params)
|
||||
login = User.generate_login("p")
|
||||
|
||||
user.type = 'User'
|
||||
user.login = login
|
||||
user.mail = "#{login}@example.org"
|
||||
ActiveRecord::Base.transaction do
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: create_params[:password]})
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(user.login, create_params[:password])
|
||||
user.gitea_token = result['sha1']
|
||||
user.gitea_uid = gitea_user[:body]['id']
|
||||
user.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
flash[:success] = '保存成功'
|
||||
redirect_to admins_users_path
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
logger.info "------------ #{e.message}"
|
||||
puts e.message
|
||||
flash.now[:danger] = e.message
|
||||
render 'new'
|
||||
rescue Exception => ex
|
||||
flash.now[:danger] = ex.message
|
||||
render 'new'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def finder_user
|
||||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
def finder_user
|
||||
@user = User.find(params[:id])
|
||||
|
@ -66,6 +119,14 @@ class Admins::UsersController < Admins::BaseController
|
|||
def update_params
|
||||
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
|
||||
mail phone location location_city school_id department_id admin business is_test
|
||||
password professional_certification authentication login])
|
||||
password professional_certification authentication login bank_certification enterprise_certification])
|
||||
end
|
||||
|
||||
def create_params
|
||||
params.require(:user).permit(%i[nickname gender mail phone location location_city password professional_certification])
|
||||
end
|
||||
|
||||
def validate_create_params
|
||||
create_params.slice(:phone, :password)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
class Api::V1::BaseController < ApplicationController
|
||||
|
||||
include Api::ProjectHelper
|
||||
include Api::UserHelper
|
||||
include Api::PullHelper
|
||||
|
||||
# before_action :doorkeeper_authorize!
|
||||
# skip_before_action :user_setup
|
||||
|
||||
protected
|
||||
# def current_user
|
||||
# #client方法对接,需要一直带着用户标识uid
|
||||
# Rails.logger.info doorkeeper_token
|
||||
# if doorkeeper_token && doorkeeper_token.resource_owner_id.blank?
|
||||
# # return User.anonymous if params[:uid].nil?
|
||||
# # tip_exception("2222")
|
||||
# # return render_error('缺少用户标识!') if params[:uid].nil?
|
||||
# User.current = User.find(params[:uid])
|
||||
# else
|
||||
# User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
||||
# end
|
||||
# end
|
||||
|
||||
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 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
|
||||
puts !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
|
||||
|
||||
# 具有对仓库的访问权限
|
||||
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,46 @@
|
|||
class Api::V1::ProjectTopicsController < Api::V1::BaseController
|
||||
|
||||
def index
|
||||
@project_topics = ProjectTopic
|
||||
@project_topics = @project_topics.ransack(name_cont: params[:keyword]) if params[:keyword].present?
|
||||
@project_topics = @project_topics.includes(:projects)
|
||||
@project_topics = kaminary_select_paginate(@project_topics)
|
||||
end
|
||||
|
||||
def create
|
||||
ActiveRecord::Base.transaction do
|
||||
@project = Project.find_by_id(create_params[:project_id])
|
||||
return render_not_found unless @project.present?
|
||||
return render_error("请输入项目搜索标签名称.") unless create_params[:name].present?
|
||||
|
||||
@project_topic = ProjectTopic.find_or_create_by!(name: create_params[:name].downcase)
|
||||
@project_topic_ralate = @project_topic.project_topic_ralates.find_or_create_by!(project_id: create_params[:project_id])
|
||||
|
||||
if @project_topic.present? && @project_topic_ralate.present?
|
||||
render_ok
|
||||
else
|
||||
render_error("项目关联搜索标签失败.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
ActiveRecord::Base.transaction do
|
||||
@project = Project.find_by_id(create_params[:project_id])
|
||||
return render_not_found unless @project.present?
|
||||
|
||||
@project_topic = ProjectTopic.find_by_id(params[:id])
|
||||
@project_topic_ralate = @project_topic.project_topic_ralates.find_by(project_id: @project.id)
|
||||
if @project_topic_ralate.destroy!
|
||||
render_ok
|
||||
else
|
||||
render_error("项目取消关联搜索标签失败.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def create_params
|
||||
params.permit(:project_id, :name)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
class Api::V1::Projects::BranchesController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:all]
|
||||
|
||||
def all
|
||||
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
before_action :require_operate_above, only: [:create]
|
||||
|
||||
def create
|
||||
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
private
|
||||
def branch_params
|
||||
params.require(:branch).permit(:new_branch_name, :old_branch_name)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
class Api::V1::Projects::CodeStatsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:index]
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::CodeStats::ListService.call(@project, {ref: params[:ref]}, current_user&.gitea_token)
|
||||
puts @result_object
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class Api::V1::Projects::CommitsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:index, :diff]
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
|
||||
puts @result_object
|
||||
end
|
||||
|
||||
def diff
|
||||
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class Api::V1::Projects::ContentsController < Api::V1::BaseController
|
||||
before_action :require_operate_above_or_fork_project, only: [:batch]
|
||||
|
||||
def batch
|
||||
@batch_content_params = batch_content_params
|
||||
# 处理下author和committer信息,如果没传则默认为当前用户信息
|
||||
@batch_content_params.merge!(author_email: current_user.mail, author_name: current_user.login) if batch_content_params[:author_email].blank? && batch_content_params[:author_name].blank?
|
||||
@batch_content_params.merge!(committer_email: current_user.mail, committer_name: current_user.login) if batch_content_params[:committer_email].blank? && batch_content_params[:committer_name].blank?
|
||||
|
||||
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, @batch_content_params, @project.owner.gitea_token)
|
||||
end
|
||||
|
||||
private
|
||||
def batch_content_params
|
||||
params.require(:content).permit(:author_email, :author_name, :author_timeunix, :branch, :committer_email, :committer_name, :committer_timeunix, :message, :new_branch, files: [ :action_type, :content, :encoding, :file_path])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class Api::V1::Projects::GitController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:trees, :blobs]
|
||||
|
||||
def trees
|
||||
@result_object = Api::V1::Projects::Git::TreesService.call(@project, params[:sha], {recursive: params[:recursive], page: page, limit: limit}, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def blobs
|
||||
@result_object = Api::V1::Projects::Git::BlobsService.call(@project, params[:sha], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class Api::V1::Projects::Pulls::BaseController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above
|
||||
before_action :load_pull_request
|
||||
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
class Api::V1::Projects::Pulls::JournalsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@journals = Api::V1::Projects::Pulls::Journals::ListService.call(@project, @pull_request, params, current_user)
|
||||
@journals = @journals.limit(200)
|
||||
end
|
||||
|
||||
def create
|
||||
@journal = Api::V1::Projects::Pulls::Journals::CreateService.call(@project, @pull_request, create_params, current_user)
|
||||
end
|
||||
|
||||
before_action :find_journal, only: [:update, :destroy]
|
||||
|
||||
def update
|
||||
@journal = Api::V1::Projects::Pulls::Journals::UpdateService.call(@project, @pull_request, @journal, update_params, current_user)
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @journal.destroy
|
||||
render_ok
|
||||
else
|
||||
render_error("删除评论失败!")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def create_params
|
||||
params.permit(:parent_id, :line_code, :note, :commit_id, :path, :type, :review_id, :diff => {})
|
||||
end
|
||||
|
||||
def update_params
|
||||
params.permit(:note, :commit_id, :state)
|
||||
end
|
||||
|
||||
def find_journal
|
||||
@journal = @pull_request.journals.find_by_id(params[:id])
|
||||
return render_not_found unless @journal.present?
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above
|
||||
|
||||
def index
|
||||
@pulls = Api::V1::Projects::Pulls::ListService.call(@project, query_params)
|
||||
@pulls = kaminari_paginate(@pulls)
|
||||
end
|
||||
|
||||
before_action :load_pull_request, only: [:show]
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token)
|
||||
@last_review = @pull_request.reviews.order(created_at: :desc).take
|
||||
end
|
||||
|
||||
private
|
||||
def query_params
|
||||
params.permit(:status, :keyword, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
class Api::V1::Projects::Pulls::ReviewsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@reviews = @pull_request.reviews
|
||||
@reviews = @reviews.where(status: params[:status]) if params[:status].present?
|
||||
# @reviews = kaminari_paginate(@reviews)
|
||||
end
|
||||
|
||||
before_action :require_reviewer, only: [:create]
|
||||
|
||||
def create
|
||||
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
||||
end
|
||||
|
||||
private
|
||||
def require_reviewer
|
||||
return render_forbidden('您没有审查权限,请联系项目管理员') if !current_user.admin? && !@pull_request.reviewers.exists?(current_user.id) && !@project.manager?(current_user)
|
||||
end
|
||||
|
||||
def review_params
|
||||
params.require(:review).permit(:content, :commit_id, :status)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
class Api::V1::Projects::Pulls::VersionsController < Api::V1::Projects::Pulls::BaseController
|
||||
|
||||
def index
|
||||
@result_object = Api::V1::Projects::Pulls::Versions::ListService.call(@project, @pull_request, {page: page, limit: limit}, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def diff
|
||||
@result_object = Api::V1::Projects::Pulls::Versions::GetDiffService.call(@project, @pull_request, params[:id], {filepath: params[:filepath]}, current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
class Api::V1::Projects::WebhooksController < Api::V1::BaseController
|
||||
before_action :require_manager_above
|
||||
before_action :find_webhook, only: [:show, :update, :destroy, :tests, :hooktasks]
|
||||
|
||||
def index
|
||||
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
|
||||
@webhooks = @project.webhooks
|
||||
@webhooks = @webhooks.where(type: params[:type]) if params[:type].present?
|
||||
@webhooks = kaminari_paginate(@webhooks)
|
||||
end
|
||||
|
||||
def create
|
||||
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
|
||||
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, create_webhook_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::Webhooks::GetService.call(@project, params[:id], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def update
|
||||
@result_object = Api::V1::Projects::Webhooks::UpdateService.call(@project, params[:id], webhook_params, current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@result_object = Api::V1::Projects::Webhooks::DeleteService.call(@project, params[:id], current_user&.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('删除失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def tests
|
||||
@result_object = Api::V1::Projects::Webhooks::TestsService.call(@project, params[:id], current_user&.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('推送失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def hooktasks
|
||||
@hooktasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
|
||||
@hooktasks = kaminari_paginate(@hooktasks)
|
||||
end
|
||||
|
||||
private
|
||||
def create_webhook_params
|
||||
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, :type, events: [])
|
||||
end
|
||||
|
||||
def webhook_params
|
||||
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
|
||||
end
|
||||
|
||||
def find_webhook
|
||||
@webhook = Gitea::Webhook.find_by_id(params[:id])
|
||||
return render_not_found unless @webhook.present?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
class Api::V1::ProjectsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:show, :compare, :blame]
|
||||
|
||||
def index
|
||||
render_ok
|
||||
end
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
|
||||
end
|
||||
|
||||
def compare
|
||||
@result_object = Api::V1::Projects::CompareService.call(@project, params[:from], params[:to], current_user&.gitea_token)
|
||||
end
|
||||
|
||||
def blame
|
||||
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
class Api::V1::Users::FeedbacksController < Api::V1::BaseController
|
||||
|
||||
before_action :load_observe_user
|
||||
before_action :check_auth_for_observe_user
|
||||
|
||||
def create
|
||||
@result = Api::V1::Users::Feedbacks::CreateService.call(@observe_user, feedback_params)
|
||||
return render_error("反馈意见创建失败.") if @result.nil?
|
||||
return render_ok
|
||||
end
|
||||
|
||||
private
|
||||
def feedback_params
|
||||
params.permit(:content)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
class Api::V1::Users::ProjectsController < Api::V1::BaseController
|
||||
before_action :load_observe_user
|
||||
|
||||
def index
|
||||
@object_results = Api::V1::Users::Projects::ListService.call(@observe_user, query_params, current_user)
|
||||
@projects = kaminari_paginate(@object_results)
|
||||
end
|
||||
|
||||
private
|
||||
def query_params
|
||||
params.permit(:category, :is_public, :project_type, :sort_by, :sort_direction, :search)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,81 @@
|
|||
class Api::V1::UsersController < Api::V1::BaseController
|
||||
|
||||
before_action :load_observe_user
|
||||
before_action :check_auth_for_observe_user
|
||||
|
||||
def send_email_vefify_code
|
||||
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||
verification_code = code.sample(6).join
|
||||
mail = params[:email]
|
||||
code_type = params[:code_type]
|
||||
|
||||
sign = Digest::MD5.hexdigest("#{OPENKEY}#{mail}")
|
||||
Rails.logger.info sign
|
||||
|
||||
tip_exception(501, "请求不合理") if sign != params[:smscode]
|
||||
|
||||
# 60s内不能重复发送
|
||||
send_email_limit_cache_key = "send_email_60_second_limit:#{mail}"
|
||||
tip_exception(-2, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key)
|
||||
send_email_control = LimitForbidControl::SendEmailCode.new(mail)
|
||||
tip_exception(-2, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
|
||||
begin
|
||||
UserMailer.update_email(mail, verification_code).deliver_now
|
||||
|
||||
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
|
||||
send_email_control.increment!
|
||||
rescue Exception => e
|
||||
logger_error(e)
|
||||
tip_exception(-2,"邮件发送失败,请稍后重试")
|
||||
end
|
||||
ver_params = {code_type: code_type, code: verification_code, email: mail}
|
||||
last_code = VerificationCode.where(code_type: code_type, email: mail).last
|
||||
last_code.update_attributes!({created_at: Time.current - 10.minute}) if last_code.present?
|
||||
data = VerificationCode.new(ver_params)
|
||||
if data.save!
|
||||
render_ok
|
||||
else
|
||||
tip_exception(-1, "创建数据失败")
|
||||
end
|
||||
end
|
||||
|
||||
def check_password
|
||||
password = params[:password]
|
||||
return tip_exception(-5, "8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD
|
||||
return tip_exception(-5, "密码错误") unless @observe_user.check_password?(password)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def check_email
|
||||
mail = strip(params[:email])
|
||||
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
|
||||
|
||||
exist_owner = Owner.find_by(mail: mail)
|
||||
return tip_exception(-2, '邮箱已被使用') if exist_owner
|
||||
render_ok
|
||||
end
|
||||
|
||||
def check_email_verify_code
|
||||
code = strip(params[:code])
|
||||
mail = strip(params[:email])
|
||||
code_type = params[:code_type]
|
||||
|
||||
return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
|
||||
|
||||
verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last
|
||||
return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试
|
||||
|
||||
return tip_exception(-6, "验证码不正确") if verifi_code&.code != code
|
||||
return tip_exception(-6, "验证码已失效") if !verifi_code&.effective?
|
||||
render_ok
|
||||
end
|
||||
|
||||
def update_email
|
||||
@result_object = Api::V1::Users::UpdateEmailService.call(@observe_user, params, current_user.gitea_token)
|
||||
if @result_object
|
||||
return render_ok
|
||||
else
|
||||
return render_error('更改邮箱失败!')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -82,7 +82,7 @@ class ApplicationController < ActionController::Base
|
|||
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
|
||||
tip_exception(-2, "请输入正确的手机号或邮箱")
|
||||
end
|
||||
|
||||
|
||||
user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
|
||||
if user_exist && type.to_i == 1
|
||||
tip_exception(-2, "该手机号码或邮箱已被注册")
|
||||
|
@ -125,7 +125,7 @@ class ApplicationController < ActionController::Base
|
|||
tip_exception(-2,"邮件发送失败,请稍后重试")
|
||||
end
|
||||
end
|
||||
ver_params = {code_type: send_type, code: code}.merge(sigle_para)
|
||||
ver_params = { code_type: send_type, code: code, status: 1 }.merge(sigle_para)
|
||||
VerificationCode.create!(ver_params)
|
||||
end
|
||||
|
||||
|
@ -174,11 +174,11 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def require_profile_completed
|
||||
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
|
||||
# tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
|
||||
end
|
||||
|
||||
def require_user_profile_completed(user)
|
||||
tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
|
||||
# tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
|
||||
end
|
||||
|
||||
# 异常提醒
|
||||
|
@ -248,42 +248,55 @@ class ApplicationController < ActionController::Base
|
|||
#return if params[:controller] == "main"
|
||||
# Find the current user
|
||||
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
|
||||
User.current = find_current_user
|
||||
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
|
||||
|
||||
# 开放课程通过链接访问的用户
|
||||
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
|
||||
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
|
||||
|
||||
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
|
||||
user = open_class_user
|
||||
if user
|
||||
start_user_session(user)
|
||||
set_autologin_cookie(user)
|
||||
if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer')
|
||||
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
|
||||
if @doorkeeper_token.present?
|
||||
# client方法对接,需要一直带着用户标识uid
|
||||
if @doorkeeper_token.resource_owner_id.blank?
|
||||
tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
|
||||
User.current = User.find(params[:uid])
|
||||
else
|
||||
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
|
||||
end
|
||||
end
|
||||
else
|
||||
User.current = find_current_user
|
||||
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
|
||||
|
||||
# 开放课程通过链接访问的用户
|
||||
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
|
||||
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
|
||||
|
||||
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
|
||||
user = open_class_user
|
||||
if user
|
||||
start_user_session(user)
|
||||
set_autologin_cookie(user)
|
||||
end
|
||||
User.current = user
|
||||
end
|
||||
User.current = user
|
||||
end
|
||||
end
|
||||
|
||||
# if !User.current.logged? && Rails.env.development?
|
||||
# User.current = User.find 1
|
||||
# end
|
||||
if !User.current.logged? && Rails.env.development?
|
||||
User.current = User.find 1
|
||||
end
|
||||
|
||||
|
||||
# 测试版前端需求
|
||||
logger.info("subdomain:#{request.subdomain}")
|
||||
# if request.subdomain != "www"
|
||||
# if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
|
||||
# User.current = User.find 81403
|
||||
# elsif params[:debug] == 'student'
|
||||
# User.current = User.find 8686
|
||||
# elsif params[:debug] == 'admin'
|
||||
# logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
|
||||
# user = User.find 36480
|
||||
# User.current = user
|
||||
# cookies.signed[:user_id] = user.id
|
||||
# end
|
||||
# end
|
||||
if request.subdomain != "www"
|
||||
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
|
||||
User.current = User.find 6
|
||||
elsif params[:debug] == 'student'
|
||||
User.current = User.find 7
|
||||
elsif params[:debug] == 'admin'
|
||||
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
|
||||
user = User.find 1
|
||||
User.current = user
|
||||
cookies.signed[:user_id] = user.id
|
||||
end
|
||||
end
|
||||
# User.current = User.find 81403
|
||||
end
|
||||
|
||||
|
@ -309,9 +322,11 @@ class ApplicationController < ActionController::Base
|
|||
# auto-login feature starts a new session
|
||||
user = nil
|
||||
Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ")
|
||||
user = User.try_to_autologin(cookies[autologin_cookie_name])
|
||||
user = User.try_to_autologin(cookies[autologin_cookie_name], autologin_action)
|
||||
# start_user_session(user) if user # TODO 解决sso退出不同步的问题
|
||||
user
|
||||
elsif params[:token].present?
|
||||
User.try_to_autologin(params[:token], autologin_action)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -686,7 +701,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
@project, @owner = Project.find_with_namespace(namespace, id)
|
||||
|
||||
if @project and current_user.can_read_project?(@project)
|
||||
if @project and (current_user.can_read_project?(@project) || controller_path == "projects/project_invite_links")
|
||||
logger.info "###########: has project and can read project"
|
||||
@project
|
||||
# elsif @project && current_user.is_a?(AnonymousUser)
|
||||
|
@ -694,9 +709,15 @@ class ApplicationController < ActionController::Base
|
|||
# @project = nil if !@project.is_public?
|
||||
# render_forbidden and return
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
if @project.present?
|
||||
logger.info "###########: has project and but can't read project"
|
||||
@project = nil
|
||||
render_forbidden and return
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
end
|
||||
end
|
||||
@project
|
||||
end
|
||||
|
@ -709,14 +730,20 @@ class ApplicationController < ActionController::Base
|
|||
Rails.application.config_for(:configuration)['platform_url'] || request.base_url
|
||||
end
|
||||
|
||||
def image_type?(str)
|
||||
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
|
||||
default_type.include?(str&.downcase)
|
||||
end
|
||||
|
||||
def convert_image!
|
||||
@image = params[:image]
|
||||
@image = params[:image]
|
||||
@image = @image.nil? && params[:user].present? ? params[:user][:image] : @image
|
||||
return unless @image.present?
|
||||
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
|
||||
if @image.class == ActionDispatch::Http::UploadedFile
|
||||
render_error('请上传文件') if @image.size.zero?
|
||||
render_error('文件大小超过限制') if @image.size > max_size.to_i
|
||||
return render_error('请上传文件') if @image.size.zero?
|
||||
return render_error('文件大小超过限制') if @image.size > max_size.to_i
|
||||
return render_error('头像格式不正确!') unless image_type?(File.extname(@image.original_filename.to_s)[1..-1])
|
||||
else
|
||||
image = @image.to_s.strip
|
||||
return render_error('请上传正确的图片') if image.blank?
|
||||
|
@ -725,7 +752,7 @@ class ApplicationController < ActionController::Base
|
|||
rescue Base64ImageConverter::Error => ex
|
||||
render_error(ex.message)
|
||||
end
|
||||
|
||||
|
||||
def avatar_path(object)
|
||||
ApplicationController.helpers.disk_filename(object.class, object.id)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
class ApplySignaturesController < ApplicationController
|
||||
include ApplicationHelper
|
||||
before_action :require_login
|
||||
before_action :find_project, only: [:index, :show_pro_info, :create, :create_simple_info, :update]
|
||||
before_action :require_owner, only: [:update]
|
||||
before_action :find_apply_signature, only: [:update, :create_detail]
|
||||
|
||||
def index
|
||||
search = params[:search].to_s.downcase
|
||||
@apply_signatures = @project.apply_signatures.with_status(status).includes(user: :user_extension)
|
||||
@apply_signatures = @apply_signatures.joins(:user).where("apply_signatures.name like ?" ,"%#{search}%").or(@apply_signatures.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%")) if search.present?
|
||||
@apply_signatures = kaminari_paginate(@apply_signatures)
|
||||
end
|
||||
|
||||
def show_pro_info
|
||||
@user_apply_signature = @project.apply_signatures.with_user_id(current_user.id).take
|
||||
end
|
||||
|
||||
def template_file
|
||||
license_name = params[:license_name] || "PHengLEI"
|
||||
license = License.find_by_name(license_name)
|
||||
file = license.attachments.take
|
||||
# normal_status(-1, "文件不存在") if file.blank?
|
||||
if file.blank?
|
||||
send_file("#{Rails.root.to_s}/public/#{license_name}-License.docx", filename: "#{license_name}软件开源协议.docx",stream:false, type: 'application/octet-stream')
|
||||
else
|
||||
send_file(absolute_path(local_path(file)), filename: file.title,stream:false, type: file.content_type.presence || 'application/octet-stream')
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
tip_exception "您已上传开源许可协议" if current_user.apply_signatures.where(project_id: params[:project_id]).where(status: ['waiting', 'passed']).present?
|
||||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
@signature = current_user.apply_signatures.find_or_create_by!(project_id: params[:project_id])
|
||||
@signature.status = 0
|
||||
@signature.attachments = Attachment.none
|
||||
@attachment = Attachment.find_by_id(params[:attachment_id])
|
||||
@attachment.container = @signature
|
||||
@signature.save!
|
||||
@attachment.save!
|
||||
rescue Exception => e
|
||||
tip_exception("#{e}")
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
render_json
|
||||
end
|
||||
end
|
||||
|
||||
def create_simple_info
|
||||
current_user.apply_signatures.where(project_id: params[:project_id]).where(status: ['unpassed']).destroy_all
|
||||
tip_exception "您已提交基本信息" if current_user.apply_signatures.where(project_id: params[:project_id]).where(status: ['waiting', 'passed']).present?
|
||||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
ApplySignatures::CreateSimpleInfoForm.new(simple_info_params).validate!
|
||||
@signature = current_user.apply_signatures.find_or_create_by!(project_id: params[:project_id])
|
||||
@signature.name = params[:name]
|
||||
@signature.phone = params[:phone]
|
||||
@signature.company_name = params[:company_name]
|
||||
@signature.position = params[:position]
|
||||
@signature.email = params[:email]
|
||||
@signature.remark = params[:remark]
|
||||
@signature.save!
|
||||
rescue Exception => e
|
||||
tip_exception("#{e}")
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def create_detail
|
||||
if ApplySignatureReadDetail.create!(apply_signature: @apply_signature, user: @apply_signature.user)
|
||||
render_ok
|
||||
else
|
||||
render_error("阅读审核记录失败")
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
return normal_status(-1, "已经是该状态了") if @apply_signature.status == params[:status]
|
||||
@apply_signature.update_attributes!(apply_signature_params)
|
||||
if @apply_signature.status == "passed"
|
||||
SendTemplateMessageJob.perform_later('ApplySignaturePassed', @apply_signature.user_id, @apply_signature.id)
|
||||
Projects::AddMemberInteractor.call(@apply_signature.project.owner, @apply_signature.project, @apply_signature.user, "read", true)
|
||||
else
|
||||
Projects::DeleteMemberInteractor.call(@apply_signature.project.owner, @apply_signature.project, @apply_signature.user)
|
||||
end
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
private
|
||||
def find_project
|
||||
@project = Project.find_by_id(params[:project_id])
|
||||
normal_status(-1, "项目不存在") unless @project.present?
|
||||
end
|
||||
|
||||
def find_apply_signature
|
||||
@apply_signature = ApplySignature.find_by_id(params[:id])
|
||||
normal_status(-1, "申请不存在") unless @apply_signature.present?
|
||||
end
|
||||
|
||||
def apply_signature_params
|
||||
params.permit(:status, :cdkey)
|
||||
end
|
||||
|
||||
def simple_info_params
|
||||
params.permit(:name, :phone, :remark, :company_name, :position, :email)
|
||||
end
|
||||
|
||||
def status
|
||||
params.fetch(:status, "all")
|
||||
end
|
||||
|
||||
def require_owner
|
||||
normal_status(403, "") unless @project.owner?(current_user) || current_user.admin?
|
||||
end
|
||||
end
|
|
@ -1,261 +1,258 @@
|
|||
#coding=utf-8
|
||||
#
|
||||
# 文件上传
|
||||
class AttachmentsController < ApplicationController
|
||||
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
||||
before_action :find_file, only: %i[show destroy]
|
||||
before_action :attachment_candown, only: [:show]
|
||||
skip_before_action :check_sign, only: [:show, :create]
|
||||
|
||||
include ApplicationHelper
|
||||
|
||||
def show
|
||||
# 1. 优先跳到cdn
|
||||
# 2. 如果没有cdn,send_file
|
||||
if @file.cloud_url.present?
|
||||
update_downloads(@file)
|
||||
redirect_to @file.cloud_url and return
|
||||
end
|
||||
|
||||
type_attachment = params[:disposition] || "attachment"
|
||||
if type_attachment == "inline"
|
||||
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
||||
elsif type_attachment == "MP4"
|
||||
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
||||
else
|
||||
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
||||
end
|
||||
update_downloads(@file)
|
||||
end
|
||||
|
||||
|
||||
def get_file
|
||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
||||
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
|
||||
if url.starts_with?(base_url)
|
||||
domain = Gitea.gitea_config[:domain]
|
||||
api_url = Gitea.gitea_config[:base_url]
|
||||
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
|
||||
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
|
||||
response = Faraday.get(request_url)
|
||||
filename = url.to_s.split("/").pop()
|
||||
else
|
||||
response = Faraday.get(url)
|
||||
filename = params[:download_url].to_s.split("/").pop()
|
||||
end
|
||||
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
||||
end
|
||||
|
||||
def create
|
||||
# 1. 本地存储
|
||||
# 2. 上传到云
|
||||
begin
|
||||
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
||||
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
||||
raise "未上传文件" unless upload_file
|
||||
|
||||
folder = file_storage_directory
|
||||
raise "存储目录未定义" unless folder.present?
|
||||
|
||||
month_folder = current_month_folder
|
||||
save_path = File.join(folder, month_folder)
|
||||
|
||||
ext = file_ext(upload_file.original_filename)
|
||||
|
||||
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
||||
|
||||
content_type = upload_file.content_type.presence || 'application/octet-stream'
|
||||
|
||||
# remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type)
|
||||
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
||||
|
||||
logger.info "local_path: #{local_path}"
|
||||
logger.info "remote_path: #{remote_path}"
|
||||
|
||||
|
||||
disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
#存数据库
|
||||
#
|
||||
@attachment = Attachment.where(disk_filename: disk_filename,
|
||||
author_id: current_user.id,
|
||||
cloud_url: remote_path).first
|
||||
if @attachment.blank?
|
||||
@attachment = Attachment.new
|
||||
@attachment.filename = upload_file.original_filename
|
||||
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
@attachment.filesize = upload_file.tempfile.size
|
||||
@attachment.content_type = content_type
|
||||
@attachment.digest = digest
|
||||
@attachment.author_id = current_user.id
|
||||
@attachment.disk_directory = month_folder
|
||||
@attachment.cloud_url = remote_path
|
||||
@attachment.save!
|
||||
else
|
||||
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
||||
end
|
||||
|
||||
render_json
|
||||
rescue => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@file_path = absolute_path(local_path(@file))
|
||||
#return normal_status(403, "") unless @file.author == current_user
|
||||
@file.destroy!
|
||||
|
||||
delete_file(@file_path)
|
||||
normal_status("删除成功")
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
# 附件为视频时,点击播放
|
||||
def preview_attachment
|
||||
attachment = Attachment.find_by(id: params[:id])
|
||||
dir_path = "#{Rails.root}/public/preview"
|
||||
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
||||
if params[:status] == "preview"
|
||||
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
||||
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
else
|
||||
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
||||
normal_status(1, "操作成功")
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_file
|
||||
@file =
|
||||
if params[:type] == 'history'
|
||||
AttachmentHistory.find params[:id]
|
||||
else
|
||||
Attachment.find params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file(file_path)
|
||||
File.delete(file_path) if File.exist?(file_path)
|
||||
end
|
||||
|
||||
def current_month_folder
|
||||
date = Time.now
|
||||
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
||||
end
|
||||
|
||||
def file_ext(file_name)
|
||||
ext = ''
|
||||
exts = file_name.split(".")
|
||||
if exts.size > 1
|
||||
ext = ".#{exts.last}"
|
||||
end
|
||||
ext
|
||||
end
|
||||
|
||||
def file_save_to_local(save_path, temp_file, ext)
|
||||
unless Dir.exists?(save_path)
|
||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||
end
|
||||
|
||||
digest = md5_file(temp_file)
|
||||
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
||||
local_file_path = File.join(save_path, digest) + ext
|
||||
save_temp_file(temp_file, local_file_path)
|
||||
|
||||
[local_file_path, digest]
|
||||
end
|
||||
|
||||
def save_temp_file(temp_file, save_file_path)
|
||||
File.open(save_file_path, 'wb') do |f|
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
f.write(buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def md5_file(temp_file)
|
||||
md5 = Digest::MD5.new
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
md5.update(buffer)
|
||||
end
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
def file_save_to_ucloud(path, file, content_type)
|
||||
ufile = Gitlink::Ufile.new(
|
||||
ucloud_public_key: edu_setting('public_key'),
|
||||
ucloud_private_key: edu_setting('private_key'),
|
||||
ucloud_public_read: true,
|
||||
ucloud_public_bucket: edu_setting('public_bucket'),
|
||||
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
||||
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
||||
)
|
||||
File.open(file) do |f|
|
||||
ufile.put(path, f, 'Content-Type' => content_type)
|
||||
end
|
||||
edu_setting('public_cdn_host') + "/" + path
|
||||
end
|
||||
|
||||
def attachment_candown
|
||||
unless current_user.admin? || current_user.business?
|
||||
candown = true
|
||||
unless params[:type] == 'history'
|
||||
if @file.container && current_user.logged?
|
||||
if @file.container.is_a?(Issue)
|
||||
course = @file.container.project
|
||||
candown = course.member?(current_user)
|
||||
elsif @file.container.is_a?(Journal)
|
||||
course = @file.container.issue.project
|
||||
candown = course.member?(current_user)
|
||||
else
|
||||
course = nil
|
||||
end
|
||||
tip_exception(403, "您没有权限进入") if course.present? && !candown
|
||||
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def send_file_with_range(path, options = {})
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
logger.info("########request.headers: #{File.exist?(path)}")
|
||||
|
||||
if File.exist?(path)
|
||||
size = File.size(path)
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
if !request.headers["Range"]
|
||||
status_code = 200 # 200 OK
|
||||
offset = 0
|
||||
length = File.size(path)
|
||||
else
|
||||
status_code = 206 # 206 Partial Content
|
||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||
offset = bytes.begin
|
||||
length = bytes.end - bytes.begin
|
||||
end
|
||||
response.header["Accept-Ranges"] = "bytes"
|
||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||
response.header["status"] = status_code
|
||||
|
||||
send_data IO.binread(path, length, offset), options
|
||||
else
|
||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
#coding=utf-8
|
||||
#
|
||||
# 文件上传
|
||||
class AttachmentsController < ApplicationController
|
||||
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
||||
before_action :find_file, only: %i[show destroy]
|
||||
before_action :attachment_candown, only: [:show]
|
||||
skip_before_action :check_sign, only: [:show, :create]
|
||||
|
||||
include ApplicationHelper
|
||||
|
||||
def show
|
||||
# 1. 优先跳到cdn
|
||||
# 2. 如果没有cdn,send_file
|
||||
if @file.cloud_url.present?
|
||||
update_downloads(@file)
|
||||
redirect_to @file.cloud_url and return
|
||||
end
|
||||
|
||||
type_attachment = params[:disposition] || "attachment"
|
||||
if type_attachment == "inline"
|
||||
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
||||
elsif type_attachment == "MP4"
|
||||
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
||||
else
|
||||
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
||||
end
|
||||
update_downloads(@file)
|
||||
end
|
||||
|
||||
|
||||
def get_file
|
||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
||||
url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s)
|
||||
if url.starts_with?(base_url) && !url.starts_with?("#{base_url}/repo")
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
api_url = GiteaService.gitea_config[:base_url]
|
||||
url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?')
|
||||
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
|
||||
response = Faraday.get(request_url)
|
||||
filename = url.to_s.split("/").pop()
|
||||
else
|
||||
response = Faraday.get(url)
|
||||
filename = params[:download_url].to_s.split("/").pop()
|
||||
end
|
||||
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
||||
end
|
||||
|
||||
def create
|
||||
# 1. 本地存储
|
||||
# 2. 上传到云
|
||||
begin
|
||||
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
||||
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
||||
raise "未上传文件" unless upload_file
|
||||
|
||||
folder = file_storage_directory
|
||||
raise "存储目录未定义" unless folder.present?
|
||||
|
||||
month_folder = current_month_folder
|
||||
save_path = File.join(folder, month_folder)
|
||||
|
||||
ext = file_ext(upload_file.original_filename)
|
||||
|
||||
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
||||
|
||||
content_type = upload_file.content_type.presence || 'application/octet-stream'
|
||||
|
||||
# remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type)
|
||||
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
||||
|
||||
logger.info "local_path: #{local_path}"
|
||||
logger.info "remote_path: #{remote_path}"
|
||||
|
||||
|
||||
disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
#存数据库
|
||||
#
|
||||
@attachment = Attachment.where(disk_filename: disk_filename,
|
||||
author_id: current_user.id,
|
||||
cloud_url: remote_path).first
|
||||
if @attachment.blank?
|
||||
@attachment = Attachment.new
|
||||
@attachment.filename = upload_file.original_filename
|
||||
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||
@attachment.filesize = upload_file.tempfile.size
|
||||
@attachment.content_type = content_type
|
||||
@attachment.digest = digest
|
||||
@attachment.author_id = current_user.id
|
||||
@attachment.disk_directory = month_folder
|
||||
@attachment.cloud_url = remote_path
|
||||
@attachment.save!
|
||||
else
|
||||
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
||||
end
|
||||
|
||||
render_json
|
||||
rescue => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@file_path = absolute_path(local_path(@file))
|
||||
#return normal_status(403, "") unless @file.author == current_user
|
||||
@file.destroy!
|
||||
|
||||
delete_file(@file_path)
|
||||
normal_status("删除成功")
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
# 附件为视频时,点击播放
|
||||
def preview_attachment
|
||||
attachment = Attachment.find_by(id: params[:id])
|
||||
dir_path = "#{Rails.root}/public/preview"
|
||||
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
||||
if params[:status] == "preview"
|
||||
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
||||
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
else
|
||||
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
||||
normal_status(1, "操作成功")
|
||||
else
|
||||
normal_status(-1, "出现错误,请稍后重试")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_file
|
||||
@file =
|
||||
if params[:type] == 'history'
|
||||
AttachmentHistory.find params[:id]
|
||||
else
|
||||
Attachment.find params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_file(file_path)
|
||||
File.delete(file_path) if File.exist?(file_path)
|
||||
end
|
||||
|
||||
def current_month_folder
|
||||
date = Time.now
|
||||
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
||||
end
|
||||
|
||||
def file_ext(file_name)
|
||||
ext = ''
|
||||
exts = file_name.split(".")
|
||||
if exts.size > 1
|
||||
ext = ".#{exts.last}"
|
||||
end
|
||||
ext
|
||||
end
|
||||
|
||||
def file_save_to_local(save_path, temp_file, ext)
|
||||
unless Dir.exists?(save_path)
|
||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||
end
|
||||
|
||||
digest = md5_file(temp_file)
|
||||
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
||||
local_file_path = File.join(save_path, digest) + ext
|
||||
save_temp_file(temp_file, local_file_path)
|
||||
|
||||
[local_file_path, digest]
|
||||
end
|
||||
|
||||
def save_temp_file(temp_file, save_file_path)
|
||||
File.open(save_file_path, 'wb') do |f|
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
f.write(buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def md5_file(temp_file)
|
||||
md5 = Digest::MD5.new
|
||||
temp_file.rewind
|
||||
while (buffer = temp_file.read(8192))
|
||||
md5.update(buffer)
|
||||
end
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
def file_save_to_ucloud(path, file, content_type)
|
||||
ufile = Gitlink::Ufile.new(
|
||||
ucloud_public_key: edu_setting('public_key'),
|
||||
ucloud_private_key: edu_setting('private_key'),
|
||||
ucloud_public_read: true,
|
||||
ucloud_public_bucket: edu_setting('public_bucket'),
|
||||
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
||||
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
||||
)
|
||||
File.open(file) do |f|
|
||||
ufile.put(path, f, 'Content-Type' => content_type)
|
||||
end
|
||||
edu_setting('public_cdn_host') + "/" + path
|
||||
end
|
||||
|
||||
def attachment_candown
|
||||
unless current_user.admin? || current_user.business?
|
||||
candown = true
|
||||
if @file.container
|
||||
if @file.container.is_a?(Issue)
|
||||
project = @file.container.project
|
||||
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||
elsif @file.container.is_a?(Journal)
|
||||
project = @file.container.issue.project
|
||||
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||
else
|
||||
project = nil
|
||||
end
|
||||
tip_exception(403, "您没有权限进入") if project.present? && !candown
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def send_file_with_range(path, options = {})
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
logger.info("########request.headers: #{File.exist?(path)}")
|
||||
|
||||
if File.exist?(path)
|
||||
size = File.size(path)
|
||||
logger.info("########request.headers: #{request.headers}")
|
||||
if !request.headers["Range"]
|
||||
status_code = 200 # 200 OK
|
||||
offset = 0
|
||||
length = File.size(path)
|
||||
else
|
||||
status_code = 206 # 206 Partial Content
|
||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||
offset = bytes.begin
|
||||
length = bytes.end - bytes.begin
|
||||
end
|
||||
response.header["Accept-Ranges"] = "bytes"
|
||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||
response.header["status"] = status_code
|
||||
|
||||
send_data IO.binread(path, length, offset), options
|
||||
else
|
||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ class Ci::BaseController < ApplicationController
|
|||
namespace = params[:owner]
|
||||
id = params[:repo] || params[:id]
|
||||
|
||||
@ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id)
|
||||
@ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id, current_user.login)
|
||||
end
|
||||
|
||||
def load_all_repo
|
||||
|
|
|
@ -14,12 +14,12 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
|
||||
def create
|
||||
flag, msg = check_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
|
@ -27,17 +27,17 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def activate
|
||||
return render_error('请先认证') unless current_user.ci_certification?
|
||||
return tip_exception('请先认证') unless current_user.ci_certification?
|
||||
|
||||
begin
|
||||
@cloud_account = Ci::CloudAccount.find params[:id]
|
||||
ActiveRecord::Base.transaction do
|
||||
if @repo
|
||||
return render_error('该项目已经激活') if @repo.repo_active?
|
||||
return tip_exception('该项目已经激活') if @repo.repo_active?
|
||||
@repo.activate!(@project)
|
||||
else
|
||||
@repo = Ci::Repo.auto_create!(@ci_user, @project)
|
||||
|
@ -50,7 +50,7 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,39 +59,39 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
|
||||
def bind
|
||||
flag, msg = check_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def trustie_bind
|
||||
account = params[:account].to_s
|
||||
return render_error("account不能为空.") if account.blank?
|
||||
return tip_exception("account不能为空.") if account.blank?
|
||||
|
||||
flag, msg = check_trustie_bind_cloud_account!
|
||||
return render_error(msg) if flag === true
|
||||
return tip_exception(msg) if flag === true
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@cloud_account = trustie_bind_account!
|
||||
if @cloud_account.blank?
|
||||
render_error('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
tip_exception('激活失败, 请检查你的云服务器信息是否正确.')
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
|
||||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def unbind
|
||||
|
@ -107,18 +107,18 @@ class Ci::CloudAccountsController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def oauth_grant
|
||||
password = params[:password].to_s
|
||||
return render_error('你输入的密码不正确.') unless current_user.check_password?(password)
|
||||
return tip_exception('你输入的密码不正确.') unless current_user.check_password?(password)
|
||||
|
||||
oauth = current_user.oauths.last
|
||||
return render_error("服务器出小差了.") if oauth.blank?
|
||||
return tip_exception("服务器出小差了.") if oauth.blank?
|
||||
|
||||
result = gitea_oauth_grant!(password, oauth)
|
||||
return render_error('授权失败.') unless result === true
|
||||
return tip_exception('授权失败.') unless result === true
|
||||
current_user.set_drone_step!(User::DEVOPS_CERTIFICATION)
|
||||
end
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
ActiveRecord::Base.transaction do
|
||||
size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size
|
||||
if size > 0
|
||||
render_error("#{params[:branch]}分支已经存在流水线!")
|
||||
tip_exception("#{params[:branch]}分支已经存在流水线!")
|
||||
return
|
||||
end
|
||||
pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner],
|
||||
|
@ -53,7 +53,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok({id: pipeline.id})
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
# 在代码库创建文件
|
||||
|
@ -81,6 +81,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
repo_branch: pipeline.branch,
|
||||
repo_config: pipeline.file_name
|
||||
}
|
||||
Rails.logger.info("########create_params===#{create_params.to_json}")
|
||||
repo = Ci::Repo.create_repo(create_params)
|
||||
repo
|
||||
end
|
||||
|
@ -118,7 +119,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -132,7 +133,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def content
|
||||
|
@ -182,7 +183,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage
|
||||
|
@ -192,7 +193,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def delete_stage
|
||||
|
@ -205,7 +206,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage_index(pipeline_id, show_index, diff)
|
||||
|
@ -229,7 +230,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
unless steps.empty?
|
||||
steps.each do |step|
|
||||
unless step[:template_id]
|
||||
render_error('请选择模板!')
|
||||
tip_exception('请选择模板!')
|
||||
return
|
||||
end
|
||||
if !step[:id]
|
||||
|
@ -246,7 +247,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def create_stage_step
|
||||
|
@ -262,7 +263,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update_stage_step
|
||||
|
@ -279,7 +280,7 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
render_ok
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def delete_stage_step
|
||||
|
@ -289,6 +290,6 @@ class Ci::PipelinesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,19 +30,19 @@ class Ci::ProjectsController < Ci::BaseController
|
|||
@file = interactor.result
|
||||
render_result(1, "更新成功")
|
||||
else
|
||||
render_error(interactor.error)
|
||||
tip_exception(interactor.error)
|
||||
end
|
||||
end
|
||||
|
||||
def activate
|
||||
return render_error('你还未认证') unless current_user.ci_certification?
|
||||
return tip_exception('你还未认证') unless current_user.ci_certification?
|
||||
|
||||
begin
|
||||
ActiveRecord::Base.transaction do
|
||||
if @repo
|
||||
return render_error('该项目已经激活') if @repo.repo_active?
|
||||
@repo.destroy! if @repo&.repo_user_id == 0
|
||||
return tip_exception('该项目已经激活') if @repo.repo_active?
|
||||
@repo.activate!(@project)
|
||||
return render_ok
|
||||
else
|
||||
@repo = Ci::Repo.auto_create!(@ci_user, @project)
|
||||
@ci_user.update_column(:user_syncing, false)
|
||||
|
@ -55,12 +55,12 @@ class Ci::ProjectsController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
end
|
||||
|
||||
def deactivate
|
||||
return render_error('该项目已经取消激活') if !@repo.repo_active?
|
||||
return tip_exception('该项目已经取消激活') if !@repo.repo_active?
|
||||
|
||||
@project.update_column(:open_devops, false)
|
||||
@repo.deactivate_repos!
|
||||
|
|
|
@ -20,14 +20,14 @@ class Ci::SecretsController < Ci::BaseController
|
|||
if result["id"]
|
||||
render_ok
|
||||
else
|
||||
render_error(result["message"])
|
||||
tip_exception(result["message"])
|
||||
end
|
||||
else
|
||||
result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret
|
||||
if result["id"]
|
||||
render_ok
|
||||
else
|
||||
render_error(result["message"])
|
||||
tip_exception(result["message"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -39,14 +39,14 @@ class Ci::SecretsController < Ci::BaseController
|
|||
Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret
|
||||
render_ok
|
||||
else
|
||||
render_error("参数名不能为空")
|
||||
tip_exception("参数名不能为空")
|
||||
end
|
||||
rescue Exception => ex
|
||||
render_ok
|
||||
end
|
||||
|
||||
def ci_drone_url
|
||||
user = User.find_by(login: params[:owner])
|
||||
user = User.find_by(login: params[:owner]) || User.find_by(login: current_user.login)
|
||||
user&.ci_cloud_account.drone_url
|
||||
end
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -63,7 +63,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
)
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -73,7 +73,7 @@ class Ci::TemplatesController < Ci::BaseController
|
|||
end
|
||||
render_ok
|
||||
rescue Exception => ex
|
||||
render_error(ex.message)
|
||||
tip_exception(ex.message)
|
||||
end
|
||||
|
||||
#======流水线模板查询=====#
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#coding=utf-8
|
||||
class ClaimsController < ApplicationController
|
||||
# skip_before_action :verify_authenticity_token
|
||||
protect_from_forgery with: :null_session
|
||||
before_action :require_login, except: [:index]
|
||||
before_action :set_issue
|
||||
|
||||
def index
|
||||
@user_claimed = 0
|
||||
@claims = @issue.claims.claim_includes.order("created_at desc")
|
||||
|
||||
@claims.each do |claim|
|
||||
if claim.user_id == current_user.id
|
||||
@user_claimed = 1
|
||||
break
|
||||
end
|
||||
end
|
||||
render file: 'app/views/claims/list.json.jbuilder'
|
||||
end
|
||||
|
||||
def create
|
||||
@claim = Claim.find_by_sql(["select id from claims where issue_id=? and user_id=?",params[:issue_id], current_user.id])
|
||||
if @claim.present?
|
||||
return normal_status(-1,"您已经声明过该易修")
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@claim = Claim.new(parse_issue_params(params))
|
||||
if @claim.save
|
||||
@claims = @issue.claims.claim_includes.order("created_at desc")
|
||||
@user_claimed = 1
|
||||
|
||||
journal_params = {
|
||||
journalized_id: params[:issue_id],
|
||||
journalized_type: "Issue",
|
||||
user_id: current_user.id ,
|
||||
notes: "新建声明: #{params[:claim_note]}",
|
||||
}
|
||||
|
||||
journal = Journal.new(journal_params)
|
||||
if journal.save
|
||||
SendTemplateMessageJob.perform_later('IssueClaim', current_user.id, @issue&.id)
|
||||
render file: 'app/views/claims/list.json.jbuilder'
|
||||
else
|
||||
normal_status(-1,"新建声明关联评论操作失败")
|
||||
end
|
||||
|
||||
else
|
||||
normal_status(-1,"新建声明操作失败")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@claim = Claim.find_by_id(params[:claim_id])
|
||||
if @claim.blank?
|
||||
return normal_status(-1,"易修不存在")
|
||||
end
|
||||
|
||||
if @claim.user_id != current_user.id
|
||||
return normal_status(-1,"你不能更新别人的声明")
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
if @claim.update_attribute(:note,params[:claim_note])
|
||||
@claims = @issue.claims.claim_includes.order("created_at desc")
|
||||
@user_claimed = 1
|
||||
|
||||
journal_params = {
|
||||
journalized_id: params[:issue_id],
|
||||
journalized_type: "Issue",
|
||||
user_id: current_user.id ,
|
||||
notes: "更新声明: #{params[:claim_note]}",
|
||||
}
|
||||
|
||||
journal = Journal.new(journal_params)
|
||||
if journal.save
|
||||
render file: 'app/views/claims/list.json.jbuilder'
|
||||
else
|
||||
normal_status(-1,"新建声明关联评论操作失败")
|
||||
end
|
||||
|
||||
else
|
||||
normal_status(-1,"声明更新操作失败")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@claim = Claim.find_by_sql(["select id from claims where issue_id=? and user_id=?",params[:issue_id], current_user.id])
|
||||
if @claim.blank?
|
||||
normal_status(-1,"您未曾声明过该易修")
|
||||
else
|
||||
@claim = @claim[0]
|
||||
# 判断current user是否是claimer
|
||||
ActiveRecord::Base.transaction do
|
||||
if @claim.destroy
|
||||
|
||||
@claims = @issue.claims.claim_includes.order("created_at desc")
|
||||
@user_claimed = 0
|
||||
|
||||
journal_params = {
|
||||
journalized_id: params[:issue_id],
|
||||
journalized_type: "Issue",
|
||||
user_id: current_user.id ,
|
||||
notes: "取消声明",
|
||||
}
|
||||
|
||||
journal = Journal.new(journal_params)
|
||||
if journal.save
|
||||
render file: 'app/views/claims/list.json.jbuilder'
|
||||
else
|
||||
normal_status(-1,"新建声明关联评论操作失败")
|
||||
end
|
||||
|
||||
else
|
||||
normal_status(-1,"取消声明操作失败")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def parse_issue_params(params)
|
||||
{
|
||||
issue_id: params[:issue_id],
|
||||
user_id: current_user.id,
|
||||
note: params[:claim_note],
|
||||
}
|
||||
end
|
||||
|
||||
def set_issue
|
||||
@issue = Issue.find_by_id(params[:issue_id])
|
||||
unless @issue.present?
|
||||
normal_status(-1, "易修不存在")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
class CommitLogsController < ApplicationController
|
||||
|
||||
def create
|
||||
tip_exception "未认证" unless params[:token].to_s == "7917908927b6f1b792f2027a08a8b24a2de42c1692c2fd45da0dee5cf90a5af5"
|
||||
ref = params[:ref]
|
||||
user_name = params[:pusher][:login]
|
||||
user_mail = params[:pusher][:email]
|
||||
user = User.find_by(mail: user_mail)
|
||||
user = User.find_by(login: user_name) if user.blank?
|
||||
|
||||
repository_id = params[:repository][:id]
|
||||
repository_name = params[:repository][:name]
|
||||
repository_full_name = params[:repository][:full_name]
|
||||
owner_name = repository_full_name.split("/")[0]
|
||||
owner = User.find_by(login: owner_name)
|
||||
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
|
||||
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
|
||||
# project.update_column(:updated_on, Time.now) if project.present?
|
||||
params[:commits].each do |commit|
|
||||
commit_id = commit[:id]
|
||||
message = commit[:message]
|
||||
CommitLog.create(user: user, project: project, repository_id: repository_id,
|
||||
name: repository_name, full_name: repository_full_name,
|
||||
ref: ref, commit_id: commit_id, message: message)
|
||||
end
|
||||
# c
|
||||
if project.present?
|
||||
if repository_full_name.to_s.include?("openkylin")
|
||||
project.update_column(:updated_on, Time.now - rand(1..100).minutes)
|
||||
else
|
||||
project.update_column(:updated_on, Time.now)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,9 +6,18 @@ class CompareController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
load_compare_params
|
||||
compare
|
||||
@merge_status, @merge_message = get_merge_message
|
||||
if params[:type] == "sha"
|
||||
load_compare_params
|
||||
@compare_result ||= gitea_compare(@base, @head)
|
||||
else
|
||||
load_compare_params
|
||||
compare
|
||||
@merge_status, @merge_message = get_merge_message
|
||||
end
|
||||
@page_size = page_size <= 0 ? 1 : page_size
|
||||
@page_limit = page_limit <=0 ? 15 : page_limit
|
||||
@page_offset = (@page_size -1) * @page_limit
|
||||
Rails.logger.info("+========#{@page_size}-#{@page_limit}-#{@page_offset}")
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -16,6 +25,7 @@ class CompareController < ApplicationController
|
|||
if @base.blank? || @head.blank?
|
||||
return -2, "请选择分支"
|
||||
else
|
||||
return -2, "目标仓库未开启合并请求(PR)功能" unless @project.has_menu_permission("pulls")
|
||||
if @head.include?(":")
|
||||
fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take
|
||||
return -2, "请选择正确的仓库" unless fork_project.present?
|
||||
|
@ -42,12 +52,22 @@ class CompareController < ApplicationController
|
|||
end
|
||||
|
||||
def load_compare_params
|
||||
@base = Addressable::URI.unescape(params[:base])
|
||||
@head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head]
|
||||
|
||||
# @base = Addressable::URI.unescape(params[:base])
|
||||
@base = params[:base].include?(":") ? Addressable::URI.unescape(params[:base].split(":")[0]) + ':' + Base64.decode64(params[:base].split(":")[1]) : Base64.decode64(params[:base])
|
||||
@head = params[:head].include?('.json') ? params[:head][0..-6] : params[:head]
|
||||
# @head = Addressable::URI.unescape(@head)
|
||||
@head = @head.include?(":") ? Addressable::URI.unescape(@head.split(":")[0]) + ':' + Base64.decode64(@head.split(":")[1]) : Base64.decode64(@head)
|
||||
end
|
||||
|
||||
def gitea_compare(base, head)
|
||||
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token)
|
||||
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
|
||||
end
|
||||
|
||||
def page_size
|
||||
params.fetch(:page, 1).to_i
|
||||
end
|
||||
|
||||
def page_limit
|
||||
params.fetch(:limit, 15).to_i
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,506 @@
|
|||
class CompetitionInfosController < ApplicationController
|
||||
include ApplicationHelper
|
||||
before_action :find_competition, only: [:show, :edit, :update, :update_zone_or_sub, :enroll, :upload, :enroll_status,
|
||||
:statistics, :enroll_list, :ranking_list, :enroll_update, :enroll_status_update, :apply_status_update,
|
||||
:upload_enroll_template, :upload_apply_template, :enroll_template, :apply_template, :online_switch, :destroy]
|
||||
before_action :require_admin, only: [:new, :edit, :create, :destroy]
|
||||
before_action :check_competition_manager, only: [:update, :enroll_status_update, :online_switch, :enroll_list]
|
||||
before_action :require_login, only: [:enroll, :enroll_update, :enroll_status_update, :upload, :upload_enroll_template]
|
||||
|
||||
def index
|
||||
competition_infos = CompetitionInfo.order(sort_no: :desc)
|
||||
competition_infos = competition_infos.where("competition_infos.title like ?", "%#{params[:name]}%") if params[:name].present?
|
||||
competition_infos = competition_infos.joins(:watchers).where(watchers: { user_id: current_user.id }) if params[:category].to_s == "watched"
|
||||
@competition_infos = paginate(competition_infos)
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { render_ok(data: @competition_infos.as_json, count: competition_infos.count) }
|
||||
end
|
||||
end
|
||||
|
||||
def list
|
||||
@competition_infos = CompetitionInfo.order(sort_no: :desc)
|
||||
@competition_infos = @competition_infos.where(id: params[:ids].to_s.split(",")) if params[:ids].present?
|
||||
end
|
||||
|
||||
def recommend
|
||||
sort_direction = ["asc", "desc"].include?(params[:sort_direction].to_s) ? params[:sort_direction] : "desc"
|
||||
sort_by = params[:sort_by] || "created_at"
|
||||
competition_infos = CompetitionInfo.where(status: true)
|
||||
competition_infos = competition_infos.where("title like ?", "%#{params[:name]}%") if params[:name].present?
|
||||
@total_count = competition_infos.count
|
||||
if sort_by.to_s == "hot"
|
||||
competition_infos = competition_infos.select("competition_infos.*, (SELECT count(1) from competition_users where competition_users.competition_info_id = competition_infos.id ) as count").order("count #{sort_direction}")
|
||||
elsif sort_by.to_s == "new"
|
||||
sort_by = "created_at"
|
||||
competition_infos = competition_infos.order("#{sort_by} #{params[:sort_direction]}")
|
||||
else
|
||||
competition_infos = competition_infos.order("#{sort_by} #{params[:sort_direction]}")
|
||||
end
|
||||
@competition_infos = paginate(competition_infos)
|
||||
render_ok(data: @competition_infos.as_json, count: @total_count)
|
||||
end
|
||||
|
||||
# GET /competition_infos/new
|
||||
def new
|
||||
@competition_info = CompetitionInfo.new
|
||||
end
|
||||
|
||||
# GET /competition_infos/1/edit
|
||||
def edit
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { render_ok(data: @competition_info.as_json) }
|
||||
end
|
||||
end
|
||||
|
||||
# POST /competition_infos.json
|
||||
def create
|
||||
@competition_info = CompetitionInfo.new(competition_info_params)
|
||||
@competition_info.admin_data = params[:admin_data] if params[:admin_data].present?
|
||||
|
||||
respond_to do |format|
|
||||
if @competition_info.save
|
||||
format.html { redirect_to competition_infos_path, notice: '创建成功.' }
|
||||
format.json { render_ok(data: @competition_info.as_json) }
|
||||
else
|
||||
format.html { render :new }
|
||||
format.json { render json: @competition_info.errors, status: -1 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /competition_infos/1.json
|
||||
def update
|
||||
# @competition_info = CompetitionInfo.find params[:id]
|
||||
respond_to do |format|
|
||||
@competition_info.admin_data = params[:admin_data] if params[:admin_data].present?
|
||||
if @competition_info.update!(competition_info_params)
|
||||
format.html { redirect_to competition_infos_path, notice: '更新成功.' }
|
||||
format.json { render_ok(data: @competition_info.as_json) }
|
||||
else
|
||||
format.html { render :edit }
|
||||
format.json { render json: @competition_info.errors, status: -1 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def online_switch
|
||||
if @competition_info.status
|
||||
@competition_info.update_attributes!(status: false)
|
||||
else
|
||||
@competition_info.update_attributes!(status: true)
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def update_zone_or_sub
|
||||
tip_exception "参数错误" if params[:new].blank? || params[:old].blank? || params[:type].blank?
|
||||
if params[:type].to_s == "zone"
|
||||
competition_users = CompetitionUser.where(competition_info: @competition_info.id).where(zone: params[:old].to_s)
|
||||
competition_users.update_all(zone: params[:new].to_s)
|
||||
elsif params[:type].to_s == "sub"
|
||||
competition_users = CompetitionUser.where(competition_info: @competition_info.id).where(sub_competition: params[:old].to_s)
|
||||
competition_users.update_all(sub_competition: params[:new].to_s)
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def enroll_list
|
||||
competition_users = CompetitionUser.where(competition_info: @competition_info.id).order("updated_at desc")
|
||||
zones = @competition_info.manager_zones(current_user)
|
||||
if @competition_info.identifier == "qz2022"
|
||||
if params[:zone].present?
|
||||
competition_users = zones.include?(params[:zone].to_s) ? competition_users.where(zone: params[:zone].to_s) : competition_users.where(zone: [])
|
||||
else
|
||||
competition_users = current_user.admin? ? competition_users : competition_users.where(zone: zones)
|
||||
end
|
||||
if params[:sub_competition].present?
|
||||
competition_users = competition_users.where(sub_competition: params[:sub_competition].to_s)
|
||||
end
|
||||
end
|
||||
if params[:keyword].present?
|
||||
competition_users = competition_users.where("competition_users.org_name LIKE :keyword OR competition_users.leader LIKE :keyword OR competition_users.phone LIKE :keyword", keyword: "%#{params[:keyword].to_s}%")
|
||||
end
|
||||
if params[:status].present?
|
||||
competition_users = competition_users.where(status: params[:status].to_s.split(","))
|
||||
end
|
||||
if params[:apply_status].present?
|
||||
competition_users = competition_users.where(ext3: params[:apply_status].to_s.split(","))
|
||||
end
|
||||
if params[:upload].to_s == "true"
|
||||
# competition_users = competition_users.joins("join attachments on attachments.container_type='CompetitionUser' and attachments.container_id = competition_users.id")
|
||||
competition_users = competition_users.where(status: 3)
|
||||
end
|
||||
if params[:sub_item].present?
|
||||
competition_users = competition_users.where(sub_item: params[:sub_item])
|
||||
end
|
||||
@competition_users_count = competition_users.count
|
||||
competition_users = competition_users.select("DISTINCT competition_users.*")
|
||||
@competition_users = paginate(competition_users)
|
||||
respond_to do |format|
|
||||
format.json
|
||||
# 导出功能
|
||||
format.xlsx {
|
||||
set_export_cookies
|
||||
competition_users = params[:upload].to_s == "true" ? competition_users.where(status: [2, 3]) : competition_users.where(status: [1, 2, 3])
|
||||
enroll_fields = @competition_info.enroll_fields
|
||||
enroll_fields = enroll_fields.delete_if { |key, value| ["sub_item", "works_name", "works_url"].include?(value) } if params[:upload].to_s != "true"
|
||||
@table_columns = enroll_fields.keys
|
||||
@table_columns = @table_columns + %w(参赛报名表下载链接)
|
||||
@table_columns = @table_columns + %w(作品下载链接) if params[:upload].to_s == "true" && !enroll_fields.values.include?("works_url")
|
||||
@table_columns = @table_columns + %w(申请表下载链接) if params[:apply_status].present?
|
||||
@table_columns = @table_columns + %w(bm审查下载链接) if @competition_info.identifier == "KXSYSJ-2024" && params[:upload].to_s == "true"
|
||||
# 重排成员放最后
|
||||
enroll_fields_values = enroll_fields.values - ["members_to_string"] + ["members_to_string"]
|
||||
@export_infos = []
|
||||
@export_infos_new = []
|
||||
max_members = []
|
||||
competition_users.each do |u|
|
||||
info_array = []
|
||||
file_array = []
|
||||
file = Attachment.where_id_or_uuid(u.enroll_template_id).first
|
||||
file_array = file_array + [file.blank? ? "" : "#{EduSetting.get('host_name')}/#{download_url(file)}"]
|
||||
if params[:upload].to_s == "true" && !enroll_fields.values.include?("works_url")
|
||||
file_array = file_array + [u.attachments.blank? ? "" : "#{EduSetting.get('host_name')}/#{download_url(u.attachments.first)}"]
|
||||
end
|
||||
if params[:apply_status].present?
|
||||
file = Attachment.where_id_or_uuid(u.ext2).first
|
||||
file_array = file_array + [file.blank? ? "" : "#{EduSetting.get('host_name')}/#{download_url(file)}"]
|
||||
end
|
||||
if @competition_info.identifier == "KXSYSJ-2024" && params[:upload].to_s == "true"
|
||||
file = Attachment.where_id_or_uuid(u.bm_file_id).first
|
||||
file_array = file_array + [file.blank? ? "" : "#{EduSetting.get('host_name')}/#{download_url(file)}"]
|
||||
end
|
||||
enroll_fields_values.each do |val|
|
||||
if "members_to_string" == val.to_s
|
||||
members = u.send("#{val}")
|
||||
max_members.push(members.size)
|
||||
info_array = info_array + file_array + members
|
||||
else
|
||||
info_array.push("#{u.send("#{val}")}")
|
||||
end
|
||||
end
|
||||
@export_infos.push(info_array)
|
||||
end
|
||||
Rails.logger.info("######_______________1111########@export_infos: #{@export_infos}")
|
||||
if max_members.present? && max_members.max > 1
|
||||
max_members.max.times do |n|
|
||||
@table_columns = @table_columns - ["成员"]
|
||||
@table_columns.push("成员#{n + 1}")
|
||||
end
|
||||
total_col = enroll_fields.values.size + max_members.max.to_i
|
||||
@export_infos.each do |info|
|
||||
blank_str = []
|
||||
(total_col - 1 - info.size).times do
|
||||
blank_str.push("")
|
||||
end
|
||||
@export_infos_new.push(info + blank_str)
|
||||
end
|
||||
else
|
||||
@table_columns = @table_columns - ["成员"] + ["成员"]
|
||||
@export_infos_new = @export_infos
|
||||
end
|
||||
export_name = "竞赛报名列表_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
|
||||
export_name = "竞赛作品列表_#{Time.now.strftime('%Y%m%d_%H%M%S')}" if params[:upload].to_s == "true"
|
||||
Rails.logger.info("######_______________########export_infos_new: #{@export_infos_new}")
|
||||
render xlsx: "#{export_name.strip}", template: "competition_infos/enroll_list.xlsx.axlsx", locals: { table_columns: @table_columns, export_infos: @export_infos_new }
|
||||
}
|
||||
format.zip {
|
||||
competition_users = params[:upload].to_s == "true" ? competition_users.where(status: [2, 3]) : competition_users.where(status: [1, 2, 3])
|
||||
Rails.logger.info("######_______________########competition_users.size: #{competition_users.size}")
|
||||
service = Competition::ZipWorkFileService.new(competition_users, "files")
|
||||
send_file service.zip, filename: service.filename, type: 'application/zip'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def enroll_template
|
||||
file_attr_name = params[:file].to_s == "bm_file_id" ? params[:file].to_s : "enroll_template_id"
|
||||
competition_users = CompetitionUser.where(competition_info: @competition_info.id).order("updated_at desc")
|
||||
competition_users = competition_users.where(status: [1, 2, 3])
|
||||
competition_users = competition_users.where("competition_users.enroll_template_id is not null") if file_attr_name.to_s == "enroll_template_id"
|
||||
competition_users = competition_users.where("competition_users.bm_file_id is not null") if file_attr_name.to_s == "bm_file_id"
|
||||
zones = @competition_info.manager_zones(current_user)
|
||||
if params[:zone].present?
|
||||
competition_users = zones.include?(params[:zone].to_s) ? competition_users.where(zone: params[:zone].to_s) : competition_users.where(zone: [])
|
||||
else
|
||||
competition_users = current_user.admin? ? competition_users : competition_users.where(zone: zones)
|
||||
end
|
||||
if params[:sub_competition].present?
|
||||
competition_users = competition_users.where(sub_competition: params[:sub_competition].to_s)
|
||||
end
|
||||
if params[:keyword].present?
|
||||
competition_users = competition_users.where("competition_users.org_name LIKE :keyword OR competition_users.leader LIKE :keyword OR competition_users.phone LIKE :keyword", keyword: "%#{params[:keyword].to_s}%")
|
||||
end
|
||||
respond_to do |format|
|
||||
format.json
|
||||
format.zip {
|
||||
Rails.logger.info("######_______________########competition_users.size: #{competition_users.size}")
|
||||
service = Competition::ZipEnrollTemplateService.new(competition_users, "files", file_attr_name)
|
||||
send_file service.zip, filename: service.filename, type: 'application/zip'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def apply_template
|
||||
competition_users = CompetitionUser.where(competition_info: @competition_info.id).order("updated_at desc")
|
||||
competition_users = competition_users.where(status: [1, 2, 3]).where("competition_users.ext2 is not null")
|
||||
zones = @competition_info.manager_zones(current_user)
|
||||
if params[:zone].present?
|
||||
competition_users = zones.include?(params[:zone].to_s) ? competition_users.where(zone: params[:zone].to_s) : competition_users.where(zone: [])
|
||||
else
|
||||
competition_users = current_user.admin? ? competition_users : competition_users.where(zone: zones)
|
||||
end
|
||||
if params[:sub_competition].present?
|
||||
competition_users = competition_users.where(sub_competition: params[:sub_competition].to_s)
|
||||
end
|
||||
if params[:keyword].present?
|
||||
competition_users = competition_users.where("competition_users.org_name LIKE :keyword OR competition_users.leader LIKE :keyword OR competition_users.phone LIKE :keyword", keyword: "%#{params[:keyword].to_s}%")
|
||||
end
|
||||
respond_to do |format|
|
||||
format.json
|
||||
format.zip {
|
||||
Rails.logger.info("######_______________########competition_users.size: #{competition_users.size}")
|
||||
service = Competition::ZipApplyTemplateService.new(competition_users, "files")
|
||||
send_file service.zip, filename: service.filename, type: 'application/zip'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@competition_info.increment!(:visits)
|
||||
end
|
||||
|
||||
def enroll_status_update
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: params[:user_id])
|
||||
tip_exception "未找到该报名用户" if competition_user.blank?
|
||||
tip_exception "状态参数错误" unless ['0', '1', '2'].include?(params[:status].to_s)
|
||||
old_status = competition_user.status
|
||||
stage = competition_user.ext5
|
||||
# 作品驳回时得分清0
|
||||
if old_status.to_i == 3 && params[:status].to_i ==2
|
||||
stage_score = competition_user.competition_user_scores.find_by(stage: stage.to_i)
|
||||
stage_score.update_attributes!(score: 0, last_score: 0) if stage_score.present?
|
||||
competition_user.update_attributes!(score: 0)
|
||||
cache_key = "limit_forbid_control:#{@competition_info.identifier}:competition_api_score:#{competition_user.id}-#{stage}"
|
||||
Rails.cache.delete(cache_key)
|
||||
api_score_control = LimitForbidControl::CompetitionApiScore.new(@competition_user&.id)
|
||||
api_score_control.clear
|
||||
end
|
||||
competition_user.update_attributes!(status: params[:status].to_i)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def apply_status_update
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: params[:user_id])
|
||||
tip_exception "未找到该报名用户" if competition_user.blank?
|
||||
tip_exception "状态参数错误" unless ['0', '1', '2'].include?(params[:status].to_s)
|
||||
competition_user.update_attributes!(ext3: params[:status].to_i)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def enroll
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: current_user.id)
|
||||
tip_exception "您已经报名!" if competition_user.present?
|
||||
competition_user = CompetitionUser.new(enroll_params)
|
||||
competition_user.competition_info = @competition_info
|
||||
competition_user.user = current_user
|
||||
competition_user.members = params[:members]
|
||||
competition_user.status = 1
|
||||
competition_user.save
|
||||
render_ok
|
||||
end
|
||||
|
||||
def enroll_update
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: current_user.id)
|
||||
tip_exception "未报名,请先报名" if competition_user.blank?
|
||||
competition_user.update_attributes!(enroll_params)
|
||||
competition_user.members = params[:members]
|
||||
competition_user.status = 1
|
||||
competition_user.save
|
||||
render_ok
|
||||
end
|
||||
|
||||
def upload_enroll_template
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: current_user.id)
|
||||
tip_exception "未报名,请先报名" if competition_user.blank?
|
||||
tip_exception "附件参数enroll_template_id不能为空" if params[:enroll_template_id].blank?
|
||||
competition_user.update_attributes!(enroll_template_id: params[:enroll_template_id])
|
||||
render_ok
|
||||
end
|
||||
|
||||
def enroll_status
|
||||
@competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: current_user.id)
|
||||
# first_round_ids = CompetitionUser.where(competition_info_id: @competition_info.id).where("score > 26").pluck(:id)
|
||||
# 第一轮赛合格人员
|
||||
first_round_ids = [541, 543, 544, 545, 546, 548, 550, 551, 552, 554, 555, 556, 558, 560, 563, 565, 567, 576, 579, 581]
|
||||
@second_round = first_round_ids.include?(@competition_user&.id)
|
||||
if @competition_info.identifier.to_s == "dmsc" || @competition_info.identifier.to_s == "zswd"
|
||||
cache_key = "limit_forbid_control:#{@competition_info.identifier}:competition_api_score:#{@competition_user&.id}-#{@stage}"
|
||||
@count_control = Rails.cache.read(cache_key)
|
||||
else
|
||||
api_score_control = LimitForbidControl::CompetitionApiScore.new(@competition_user&.id)
|
||||
@count_control = api_score_control.forbid?
|
||||
end
|
||||
end
|
||||
|
||||
def upload
|
||||
@stage = params[:stage] || params[:ext5]
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_info.id, user_id: current_user.id)
|
||||
tip_exception "未报名,请先报名" if competition_user.blank?
|
||||
# tip_exception "附件参数attachment_ids不能为空" if params[:attachment_ids].blank?
|
||||
# 第一轮赛合格人员
|
||||
# first_round_ids = CompetitionUser.where(competition_info_id: @competition_info.id).where("score > 26").pluck(:id)
|
||||
first_round_ids = [541, 543, 544, 545, 546, 548, 550, 551, 552, 554, 555, 556, 558, 560, 563, 565, 567, 576, 579, 581]
|
||||
tip_exception "您不在复赛名单中,不能参加复赛!" if @competition_info.identifier == "zstp2022" && !first_round_ids.include?(competition_user&.id)
|
||||
if @competition_info.identifier.to_s == "dmsc" || @competition_info.identifier.to_s == "zswd"
|
||||
cache_key = "limit_forbid_control:#{@competition_info.identifier}:competition_api_score:#{competition_user.id}-#{@stage}"
|
||||
allow_count = 1
|
||||
count_control = Rails.cache.read(cache_key)
|
||||
if count_control.present? && count_control.to_i >= allow_count
|
||||
return normal_status(-1, "打分受限,当前竞赛仅支持3天打一次榜")
|
||||
else
|
||||
Rails.cache.write(cache_key, count_control.to_i + 1, expires_in: 5.minutes)
|
||||
end
|
||||
else
|
||||
api_score_control = LimitForbidControl::CompetitionApiScore.new(competition_user.id)
|
||||
return normal_status(-1, "今日打分已达上限,请明日再试") if api_score_control.forbid?
|
||||
api_score_control.increment!
|
||||
end
|
||||
competition_user.bm_file_id = params[:bm_file_id] if params[:bm_file_id].present?
|
||||
# tip_exception "您已经提交作品!" if competition_user.present? && competition_user.attachments.present?
|
||||
if params[:attachment_ids].present?
|
||||
competition_user.attachments.update_all(container_id: nil, container_type: nil)
|
||||
params[:attachment_ids].each do |id|
|
||||
attachment = Attachment.where_id_or_uuid(id).first
|
||||
unless attachment.blank?
|
||||
attachment.container = competition_user
|
||||
attachment.author_id = current_user.id
|
||||
attachment.description = ""
|
||||
attachment.save
|
||||
end
|
||||
forge_url = Rails.application.config_for(:configuration)['platform_url'] || EduSetting.get("main_site")
|
||||
filePath = "#{forge_url}/api/attachments/#{attachment.id}"
|
||||
if EduSetting.get("competition_ccks_ids").to_s.split(",").include?(@competition_info.identifier.to_s)
|
||||
api_url = "/script/ccks"
|
||||
CompetitionAutoScoreNewJob.perform_later(competition_user.id, api_url, filePath)
|
||||
elsif EduSetting.get("competition_zstp2023_ids").to_s.split(",").include?(@competition_info.identifier.to_s)
|
||||
api_url = "/script/ccks2023"
|
||||
CompetitionAutoScoreNewJob.perform_later(competition_user.id, api_url, filePath)
|
||||
elsif @competition_info.identifier.to_s == "dmsc"
|
||||
api_url = "/script/qyCode"
|
||||
CompetitionAutoScoreNewJob.perform_later(competition_user.id, api_url, filePath, @stage)
|
||||
elsif @competition_info.identifier.to_s == "zswd"
|
||||
api_url = "/script/qyMilitary"
|
||||
CompetitionAutoScoreNewJob.perform_later(competition_user.id, api_url, filePath, @stage)
|
||||
elsif @competition_info.identifier.to_s == "mmlss"
|
||||
api_url = "/script/mmlssEval"
|
||||
CompetitionAutoScoreNewJob.perform_later(competition_user.id, api_url, filePath, @stage)
|
||||
end
|
||||
end
|
||||
end
|
||||
competition_user.sub_item = params[:sub_item] if params[:sub_item].present?
|
||||
competition_user.works_name = params[:works_name] if params[:works_name].present?
|
||||
competition_user.works_url = params[:works_url] if params[:works_url].present?
|
||||
if @stage.present?
|
||||
competition_user.update_attributes!(api_status: 1, status: 3, ext5: @stage)
|
||||
else
|
||||
competition_user.update_attributes!(api_status: 1, status: 3)
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
# 自动打分接口
|
||||
def auto_score
|
||||
filePath = params[:filePath].to_s
|
||||
team_id = params[:team_id].to_s
|
||||
api_url = params[:api_url].to_s
|
||||
tip_exception("参数错误") if filePath.blank? || team_id.blank? || api_url.blank?
|
||||
competition_team = CompetitionTeam.find team_id
|
||||
competition_team.update_attributes!(api_status: 1)
|
||||
api_score_control = LimitForbidControl::CompetitionApiScore.new(team_id)
|
||||
return normal_status(-1, "今日打分已达上限,请明日再试") if api_score_control.forbid?
|
||||
api_score_control.increment!
|
||||
CompetitionAutoScoreJob.perform_later(team_id, api_url, filePath)
|
||||
render_ok
|
||||
end
|
||||
|
||||
# 赛事风采
|
||||
def statistics
|
||||
@competition_users = @competition_info.competition_users.where(status: [1, 2, 3])
|
||||
@upload_count = @competition_users.joins("join attachments on attachments.container_type='CompetitionUser' and attachments.container_id = competition_users.id").count
|
||||
end
|
||||
|
||||
# 排名
|
||||
def ranking_list
|
||||
@stage = params[:stage] || params[:ext5]
|
||||
if @stage.present?
|
||||
competition_users = @competition_info.competition_users.joins(:competition_user_scores)
|
||||
.where("competition_users.status = 3")
|
||||
.where("competition_user_scores.stage = ? ", @stage.to_i)
|
||||
.where("competition_user_scores.score > 0")
|
||||
.order("competition_user_scores.score desc, competition_user_scores.created_at asc")
|
||||
@rank_num = competition_users.pluck(:id)
|
||||
if params[:keyword].present?
|
||||
competition_users = competition_users.where("competition_users.org_name LIKE :keyword OR competition_users.leader LIKE :keyword OR competition_users.ext4 LIKE :keyword ", keyword: "%#{params[:keyword].to_s}%")
|
||||
end
|
||||
@competition_users_count = competition_users.count
|
||||
@competition_users = paginate(competition_users)
|
||||
else
|
||||
competition_users = @competition_info.competition_users.where("competition_users.status = 3").where("score > 0").order("score desc, created_at asc")
|
||||
@rank_num = competition_users.pluck(:id)
|
||||
if params[:keyword].present?
|
||||
competition_users = competition_users.where("competition_users.org_name LIKE :keyword OR competition_users.leader LIKE :keyword OR competition_users.ext4 LIKE :keyword ", keyword: "%#{params[:keyword].to_s}%")
|
||||
end
|
||||
@competition_users_count = competition_users.count
|
||||
@competition_users = paginate(competition_users)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @competition_info.destroy!
|
||||
flash[:success] = '删除成功'
|
||||
else
|
||||
flash[:danger] = '删除失败'
|
||||
end
|
||||
redirect_to "api/competition_infos"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enroll_params
|
||||
params.permit(:org_name, :org_job, :org_rank, :leader, :zone, :sub_competition, :phone,
|
||||
:subject_source_type, :subject_source_name, :enroll_template_id, :mail, :ext1, :ext2, :ext3, :ext4, :ext5,
|
||||
:bm_file_id, :teacher_name, :teacher_dept, :teacher_email, :teacher_phone, :teacher_professional)
|
||||
end
|
||||
|
||||
def competition_info_params
|
||||
params.require(:competition_info).permit(:title, :zones, :zones_local, :sub_competitions, :identifier, :content,
|
||||
:video_url, :is_local, :manager_ids, :upload_date, :enroll_date, :guide, :about_us,
|
||||
:banner_url, :enroll_template, :enroll_columns, :applet_banner_url, :start_at,:start_upload_date, :sort_no,
|
||||
:ext1, :ext2, :ext3, :ext4, :ext5)
|
||||
end
|
||||
|
||||
def find_competition
|
||||
if CompetitionInfo.where(:identifier => params[:id]).exists?
|
||||
@competition_info = CompetitionInfo.where(:identifier => params[:id]).first
|
||||
else
|
||||
@competition_info = CompetitionInfo.find(params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
def manager_competition_zones
|
||||
if current_user.admin?
|
||||
@competition_info.competition_zones
|
||||
else
|
||||
@competition_info.manager_zones(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def check_competition_manager
|
||||
unless @competition_info.is_manager?(current_user)
|
||||
tip_exception(403, "你没有权限操作!")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
class CompetitionNoticesController < ApplicationController
|
||||
include ApplicationHelper
|
||||
before_action :find_competition, only: [:show, :index, :update, :destroy, :create]
|
||||
# before_action :require_admin, only: [:show, :index, :update, :destroy, :create]
|
||||
before_action :manager_competition_zones, only: [:enroll_list]
|
||||
|
||||
def index
|
||||
competition_notices = CompetitionNotice.where(competition_info_id: @competition_info.id).order("created_at desc")
|
||||
if current_user.logged?
|
||||
competition_notices.each do |notice|
|
||||
CompetitionNoticeUser.find_or_create_by!(user_id: current_user.id, competition_notice_id: notice.id)
|
||||
end
|
||||
end
|
||||
@competition_notices_count = competition_notices.size
|
||||
@competition_notices = paginate(competition_notices)
|
||||
end
|
||||
|
||||
def create
|
||||
@competition_notice = CompetitionNotice.new(competition_notice_params)
|
||||
@competition_notice.user = current_user
|
||||
@competition_notice.competition_info = @competition_info
|
||||
@competition_notice.save
|
||||
if params[:attachment_ids].present?
|
||||
params[:attachment_ids].each do |id|
|
||||
attachment = Attachment.find_by_id(id)
|
||||
unless attachment.blank?
|
||||
attachment.container = @competition_notice
|
||||
attachment.author_id = current_user.id
|
||||
attachment.description = ""
|
||||
attachment.save
|
||||
end
|
||||
end
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
# PATCH/PUT /competition_infos/1.json
|
||||
def update
|
||||
@competition_notice = CompetitionNotice.find params[:id]
|
||||
@competition_notice.update(competition_notice_params)
|
||||
@competition_notice.attachments.update_all(container_id: nil, container_type: nil)
|
||||
if params[:attachment_ids].present?
|
||||
params[:attachment_ids].each do |id|
|
||||
attachment = Attachment.find_by_id(id)
|
||||
unless attachment.blank?
|
||||
attachment.container = @competition_notice
|
||||
attachment.author_id = current_user.id
|
||||
attachment.description = ""
|
||||
attachment.save
|
||||
end
|
||||
end
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def show
|
||||
@competition_notice = CompetitionNotice.find params[:id]
|
||||
end
|
||||
|
||||
def upload
|
||||
competition_user = CompetitionUser.find_by(competition_info: @competition_notice.id, user_id: current_user.id)
|
||||
tip_exception "未报名,请先报名" if competition_user.blank?
|
||||
tip_exception "附件参数attachment_ids不能为空" if params[:attachment_ids].blank?
|
||||
# tip_exception "您已经提交作品!" if competition_user.present? && competition_user.attachments.present?
|
||||
competition_user.attachments.update_all(container_id: nil, container_type: nil)
|
||||
|
||||
render_ok
|
||||
end
|
||||
|
||||
def destroy
|
||||
@competition_notice = CompetitionNotice.find params[:id]
|
||||
@competition_notice.destroy
|
||||
render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def competition_notice_params
|
||||
params.permit(:title, :content)
|
||||
end
|
||||
|
||||
def find_competition
|
||||
if CompetitionInfo.where(:identifier => params[:competition_info_id]).exists?
|
||||
@competition_info = CompetitionInfo.where(:identifier => params[:competition_info_id]).first
|
||||
else
|
||||
@competition_info = CompetitionInfo.find(params[:competition_info_id])
|
||||
end
|
||||
end
|
||||
|
||||
def manager_competition_zones
|
||||
if current_user.admin?
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,15 +18,15 @@ module Acceleratorable
|
|||
end
|
||||
|
||||
def accelerator_domain
|
||||
Gitea.gitea_config[:accelerator]["domain"]
|
||||
GiteaService.gitea_config[:accelerator]["domain"]
|
||||
end
|
||||
|
||||
def accelerator_username
|
||||
Gitea.gitea_config[:accelerator]["access_key_id"]
|
||||
GiteaService.gitea_config[:accelerator]["access_key_id"]
|
||||
end
|
||||
|
||||
def config_accelerator?
|
||||
Gitea.gitea_config[:accelerator].present?
|
||||
GiteaService.gitea_config[:accelerator].present?
|
||||
end
|
||||
|
||||
def is_foreign_url?(clone_addr)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
module Api::ProjectHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_project
|
||||
namespace = params[:owner]
|
||||
repo = params[:repo]
|
||||
|
||||
@project, @owner = Project.find_with_namespace(namespace, repo)
|
||||
|
||||
if @project
|
||||
logger.info "###########:project founded"
|
||||
@project
|
||||
else
|
||||
logger.info "###########:project not found"
|
||||
@project = nil
|
||||
render_not_found and return
|
||||
end
|
||||
@project
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module Api::PullHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_pull_request
|
||||
pull_request_id = params[:pull_id] || params[:id]
|
||||
@pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id)
|
||||
@issue = @pull_request&.issue
|
||||
if @pull_request
|
||||
logger.info "###########pull_request founded"
|
||||
@pull_request
|
||||
else
|
||||
logger.info "###########pull_request not found"
|
||||
@pull_request = nil
|
||||
render_not_found and return
|
||||
end
|
||||
|
||||
@pull_request
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
module Api::UserHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def load_observe_user
|
||||
username = params[:owner]
|
||||
|
||||
@observe_user = User.find_by(login: username)
|
||||
|
||||
if @observe_user
|
||||
logger.info "###########observe_user not founded"
|
||||
@observe_user
|
||||
else
|
||||
logger.info "###########observe_user not found"
|
||||
@observe_user = nil
|
||||
render_not_found and return
|
||||
end
|
||||
@observe_user
|
||||
end
|
||||
|
||||
# 是否具有查看用户或编辑用户的权限
|
||||
def check_auth_for_observe_user
|
||||
return render_forbidden unless current_user.admin? || @observe_user.id == current_user.id
|
||||
end
|
||||
|
||||
def strip(str)
|
||||
str.to_s.strip.presence
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@ module Base::PaginateHelper
|
|||
end
|
||||
|
||||
def per_page
|
||||
params[:per_page].to_i <= 0 || params[:per_page].to_i > 100 ? 20 : params[:per_page].to_i
|
||||
params[:per_page].to_i <= 0 || params[:per_page].to_i > 200 ? 10 : params[:per_page].to_i
|
||||
end
|
||||
alias_method :limit, :per_page
|
||||
|
||||
|
|
|
@ -160,9 +160,9 @@ module Ci::CloudAccountManageable
|
|||
state = SecureRandom.hex(8)
|
||||
# redirect_uri eg:
|
||||
# https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805
|
||||
redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
|
||||
clientId = client_id(oauth)
|
||||
grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{clientId}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}"
|
||||
# redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
|
||||
# clientId = client_id(oauth)
|
||||
grant_url = "#{@cloud_account.drone_url}/login"
|
||||
logger.info "[gitea] grant_url: #{grant_url}"
|
||||
|
||||
conn = Faraday.new(url: grant_url) do |req|
|
||||
|
@ -188,6 +188,7 @@ module Ci::CloudAccountManageable
|
|||
response = conn.get
|
||||
logger.info "[drone] response headers: #{response.headers}"
|
||||
|
||||
# true
|
||||
response.headers['location'].include?('error') ? false : true
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ module LaboratoryHelper
|
|||
helper_method :default_setting
|
||||
helper_method :default_yun_session
|
||||
helper_method :default_course_links
|
||||
helper_method :manager_main_site_url
|
||||
helper_method :main_web_site_url
|
||||
helper_method :current_main_site_url
|
||||
end
|
||||
|
||||
def current_laboratory
|
||||
|
@ -32,18 +35,30 @@ module LaboratoryHelper
|
|||
end
|
||||
|
||||
def default_course_links
|
||||
# my_projects: "/users/#{current_user.try(:login)}/projects",
|
||||
# my_projects: "https://www.trustie.net/users/#{current_user.try(:login)}/user_projectlist",
|
||||
|
||||
{
|
||||
new_syllabuses: "https://www.trustie.net/syllabuses/new",
|
||||
new_course: "https://www.trustie.net/courses/new",
|
||||
edit_account: "https://www.trustie.net/my/account",
|
||||
my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
|
||||
my_projects: "/users/#{current_user.try(:login)}/projects",
|
||||
my_organ: "https://www.trustie.net/users/#{current_user.try(:login)}/user_organizations",
|
||||
default_url: Rails.application.config_for(:configuration)['platform_url'],
|
||||
tiding_url: "https://www.trustie.net/users/#{current_user.try(:login)}/user_messages",
|
||||
register_url: "https://www.trustie.net/login?login=false"
|
||||
# new_syllabuses: "https://www.trustie.net/syllabuses/new",
|
||||
# new_course: "https://www.trustie.net/courses/new",
|
||||
# edit_account: "https://www.trustie.net/my/account",
|
||||
# my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist",
|
||||
# my_projects: "/users/#{current_user.try(:login)}/projects",
|
||||
# my_organ: "https://www.trustie.net/users/#{current_user.try(:login)}/user_organizations",
|
||||
# default_url: "https://www.trustie.net/",
|
||||
tiding_url: "#{main_web_site_url}/users/#{current_user.try(:login)}/user_tidings",
|
||||
register_url: "#{current_main_site_url}/register"
|
||||
}
|
||||
end
|
||||
|
||||
def manager_main_site_url
|
||||
url = EduSetting.get('managements_url') || "#{current_main_site_url}/managements"
|
||||
{name: '管理', link: "#{url}"}
|
||||
end
|
||||
|
||||
def main_web_site_url
|
||||
EduSetting.get('host_main_site')
|
||||
end
|
||||
|
||||
def current_main_site_url
|
||||
EduSetting.get('host_name')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,14 +6,16 @@ module LoginHelper
|
|||
end
|
||||
|
||||
def autologin_cookie_name
|
||||
edu_setting('autologin_cookie_name').presence || 'autologin'
|
||||
edu_setting('autologin_cookie_name').presence || 'autologin_forge_military'
|
||||
end
|
||||
|
||||
def autologin_action
|
||||
EduSetting.get('autologin_action').presence || 'autologin'
|
||||
end
|
||||
|
||||
def set_autologin_cookie(user)
|
||||
token = Token.get_or_create_permanent_login_token(user, "autologin")
|
||||
sync_user_token_to_trustie(user.login, token.value)
|
||||
|
||||
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
|
||||
Rails.logger.info("set_cookie_user_id is=======> #{user.id}")
|
||||
token = Token.get_or_create_permanent_login_token(user, autologin_action)
|
||||
cookie_options = {
|
||||
:value => token.value,
|
||||
:expires => 1.month.from_now,
|
||||
|
@ -108,10 +110,15 @@ module LoginHelper
|
|||
def sync_pwd_to_gitea!(user, hash={})
|
||||
return true if user.is_sync_pwd?
|
||||
|
||||
sync_params = { email: user.mail }
|
||||
sync_params = {
|
||||
login_name: user.name,
|
||||
source_id: 0,
|
||||
email: user.mail
|
||||
}
|
||||
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
|
||||
if interactor.success?
|
||||
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
|
||||
user.update_column(:is_sync_pwd, true)
|
||||
true
|
||||
else
|
||||
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"
|
||||
|
|
|
@ -1,30 +1,66 @@
|
|||
module RegisterHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def autologin_register(username, email, password, platform= 'forge')
|
||||
def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false)
|
||||
result = {message: nil, user: nil}
|
||||
email = email.blank? ? "#{username}@example.org" : email
|
||||
|
||||
user = User.new(admin: false, login: username, mail: email, type: "User")
|
||||
user.password = password
|
||||
user.platform = platform
|
||||
user.activate
|
||||
|
||||
user.phone = phone if phone.present?
|
||||
user.nickname = nickname if nickname.present?
|
||||
if need_edit_info
|
||||
user.need_edit_info
|
||||
else
|
||||
user.activate
|
||||
end
|
||||
|
||||
return unless user.valid?
|
||||
|
||||
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
|
||||
result ={}
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(username, password)
|
||||
user.gitea_token = result['sha1']
|
||||
user.gitea_uid = gitea_user[:body]['id']
|
||||
user.gitea_uid = gitea_user[:body]['id'] if gitea_user[:body].present?
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
UserExtension.create!(user_id: user.id) if user.user_extension.blank?
|
||||
result[:user] = {id: user.id, token: user.gitea_token}
|
||||
end
|
||||
else
|
||||
result[:message] = interactor.error
|
||||
result[:message] = interactor.result[:message]
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def auto_update(user, params={})
|
||||
return if params.blank?
|
||||
result = {message: nil, user: nil}
|
||||
before_login = user.login
|
||||
user.login = params[:username]
|
||||
user.password = params[:password]
|
||||
user.mail = params[:email]
|
||||
|
||||
if user.save!
|
||||
sync_params = {
|
||||
password: params[:password].to_s,
|
||||
email: params[:email],
|
||||
login_name: params[:username],
|
||||
new_name: params[:username],
|
||||
source_id: 0
|
||||
}
|
||||
|
||||
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
|
||||
if interactor.success?
|
||||
result[:user] = user
|
||||
else
|
||||
result[:message] = '用户同步Gitea失败!'
|
||||
end
|
||||
else
|
||||
result[:message] = user.errors.full_messages.join(",")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
module RenderHelper
|
||||
def render_ok(data = {})
|
||||
render json: { status: 0, message: 'success' }.merge(data)
|
||||
end
|
||||
|
||||
def render_error(status = -1, message = '')
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
|
||||
def render_not_acceptable(message = '请求已拒绝')
|
||||
render json: { status: 406, message: message }
|
||||
end
|
||||
|
||||
def render_not_found(message = I18n.t('error.record_not_found'))
|
||||
render json: { status: 404, message: message }
|
||||
# render status: 404, json: { errors: errors }
|
||||
end
|
||||
|
||||
def render_forbidden(message = I18n.t('error.forbidden'))
|
||||
render json: { status: 403, message: message }
|
||||
# render status: 403, json: { errors: errors }
|
||||
end
|
||||
|
||||
def render_unauthorized(message = I18n.t('error.unauthorized'))
|
||||
render json: { status: 401, message: message }
|
||||
end
|
||||
|
||||
def render_result(status=1, message='success')
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
end
|
||||
module RenderHelper
|
||||
def render_ok(data = {})
|
||||
render json: { status: 0, message: 'success' }.merge(data)
|
||||
end
|
||||
|
||||
def render_error(message = '', status = -1)
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
|
||||
def render_not_acceptable(message = '请求已拒绝')
|
||||
render json: { status: 406, message: message }
|
||||
end
|
||||
|
||||
def render_not_found(message = I18n.t('error.record_not_found'))
|
||||
render json: { status: 404, message: message }
|
||||
# render status: 404, json: { errors: errors }
|
||||
end
|
||||
|
||||
def render_forbidden(message = I18n.t('error.forbidden'))
|
||||
render json: { status: 403, message: message }
|
||||
# render status: 403, json: { errors: errors }
|
||||
end
|
||||
|
||||
def render_unauthorized(message = I18n.t('error.unauthorized'))
|
||||
render json: { status: 401, message: message }
|
||||
end
|
||||
|
||||
def render_result(status=1, message='success')
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,17 @@ module Repository::LanguagesPercentagable
|
|||
result = Gitea::Repository::Languages::ListService.call(@owner.login,
|
||||
@repository.identifier, current_user&.gitea_token)
|
||||
|
||||
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
|
||||
@transform_language = result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
|
||||
update_project_language(@transform_language) unless @transform_language.nil?
|
||||
@transform_language
|
||||
end
|
||||
|
||||
def update_project_language(language)
|
||||
return if @project.project_language.present?
|
||||
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
|
||||
@project.update_column(:project_language_id, db_language.id)
|
||||
rescue
|
||||
return
|
||||
end
|
||||
|
||||
# hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781}
|
||||
|
|
|
@ -13,7 +13,7 @@ class ForksController < ApplicationController
|
|||
if current_user&.id == @project.user_id
|
||||
render_result(-1, "自己不能fork自己的项目")
|
||||
elsif Project.exists?(user_id: current_user.id, identifier: @project.identifier)
|
||||
render_result(-1, "fork失败,你已拥有了这个项目")
|
||||
render_result(0, "fork失败,你已拥有了这个项目")
|
||||
end
|
||||
# return if current_user != @project.owner
|
||||
# render_result(-1, "自己不能fork自己的项目")
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class Home::CompetitionsController < ApplicationController
|
||||
|
||||
def index
|
||||
@competitions = Competition.active.where(show_index: true).order(sort_no: :desc).limit(3)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
class Home::PlatformCommunicatesController < ApplicationController
|
||||
|
||||
def index
|
||||
location = params[:location] || "pc"
|
||||
scope = PlatformCommunicate.where(status:true).where(location: location).order(order_index: :desc)
|
||||
@communicates = kaminari_paginate(scope)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class Home::PlatformPeopleController < ApplicationController
|
||||
|
||||
def index
|
||||
scope = PlatformPerson.order(created_at: :desc)
|
||||
@people = kaminari_paginate(scope)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
class Home::PlatformStatisticsController < ApplicationController
|
||||
|
||||
def index
|
||||
@platform_statistic = PlatformStatistic.data
|
||||
@project_statistic = ProjectStatistic.data
|
||||
@platform_statistic.increment!(:visits)
|
||||
@tasks_count = ActiveRecord::Base.connection.exec_query("SELECT COUNT(1) FROM tasks b LEFT JOIN task_details a ON a.task_id = b.id WHERE b.is_delete = 0 AND b.published = 1 AND status IN (3, 4, 5, 6, 7, 8)").rows[0][0]
|
||||
@memos_count = ActiveRecord::Base.connection.exec_query("SELECT COUNT(*) FROM memos").rows[0][0]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class HomeController < ApplicationController
|
||||
|
||||
def to_competitions
|
||||
competition_url = Rails.application.config_for(:configuration)['web_site'] || EduSetting.get('host_main_site')
|
||||
redirect_to "#{competition_url}/competitions/#{params[:identifier].to_s}/home"
|
||||
end
|
||||
end
|
|
@ -2,12 +2,12 @@ class IssueTagsController < ApplicationController
|
|||
before_action :require_login, except: [:index]
|
||||
before_action :load_repository
|
||||
before_action :set_user
|
||||
before_action :check_issue_permission, except: :index
|
||||
before_action :check_issue_tags_permission
|
||||
before_action :set_issue_tag, only: [:edit, :update, :destroy]
|
||||
|
||||
|
||||
def index
|
||||
issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}")
|
||||
issue_tags = @project.issue_tags.includes(:issues).reorder("issue_tags.#{order_name} #{order_type}")
|
||||
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
|
||||
@page = params[:page] || 1
|
||||
@limit = params[:limit] || 15
|
||||
|
@ -17,7 +17,7 @@ class IssueTagsController < ApplicationController
|
|||
|
||||
|
||||
def create
|
||||
title = params[:name].to_s.strip.first(10)
|
||||
title = params[:name].to_s.strip.first(15)
|
||||
desc = params[:description].to_s.first(30)
|
||||
color = params[:color] || "#ccc"
|
||||
|
||||
|
@ -29,7 +29,7 @@ class IssueTagsController < ApplicationController
|
|||
|
||||
if title.present?
|
||||
if IssueTag.exists?(name: title, project_id: @project.id)
|
||||
normal_status(-1, "标签已存在")
|
||||
normal_status(-1, "项目标记已存在")
|
||||
else
|
||||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
|
@ -37,12 +37,12 @@ class IssueTagsController < ApplicationController
|
|||
if issue_tag.save
|
||||
# gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call
|
||||
# if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"])
|
||||
# normal_status(0, "标签创建成功")
|
||||
normal_status(0, "项目标记创建成功!")
|
||||
# else
|
||||
# normal_status(-1, "标签创建失败")
|
||||
# normal_status(-1, "项目标记创建失败")
|
||||
# end
|
||||
else
|
||||
normal_status(-1, "标签创建失败")
|
||||
normal_status(-1, "项目标记创建失败")
|
||||
end
|
||||
rescue => e
|
||||
puts "create version release error: #{e.message}"
|
||||
|
@ -51,7 +51,7 @@ class IssueTagsController < ApplicationController
|
|||
end
|
||||
end
|
||||
else
|
||||
normal_status(-1, "标签名称不能为空")
|
||||
normal_status(-1, "项目标记名称不能为空")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -60,8 +60,8 @@ class IssueTagsController < ApplicationController
|
|||
end
|
||||
|
||||
def update
|
||||
title = params[:name]
|
||||
desc = params[:description]
|
||||
title = params[:name].to_s.strip.first(15)
|
||||
desc = params[:description].to_s.first(30)
|
||||
color = params[:color] || "#ccc"
|
||||
|
||||
tag_params = {
|
||||
|
@ -71,19 +71,19 @@ class IssueTagsController < ApplicationController
|
|||
}
|
||||
if title.present?
|
||||
if IssueTag.exists?(name: title, project_id: @project.id) && (@issue_tag.name != title)
|
||||
normal_status(-1, "标签已存在")
|
||||
normal_status(-1, "项目标记已存在")
|
||||
else
|
||||
ActiveRecord::Base.transaction do
|
||||
begin
|
||||
if @issue_tag.update_attributes(tag_params)
|
||||
# gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call
|
||||
# if gitea_tag
|
||||
# normal_status(0, "标签更新成功")
|
||||
# normal_status(0, "项目标记更新成功")
|
||||
# else
|
||||
# normal_status(-1, "标签更新失败")
|
||||
# normal_status(-1, "项目标记更新失败")
|
||||
# end
|
||||
else
|
||||
normal_status(-1, "标签更新失败")
|
||||
normal_status(-1, "项目标记更新失败")
|
||||
end
|
||||
rescue => e
|
||||
puts "create version release error: #{e.message}"
|
||||
|
@ -92,7 +92,7 @@ class IssueTagsController < ApplicationController
|
|||
end
|
||||
end
|
||||
else
|
||||
normal_status(-1, "标签名称不能为空")
|
||||
normal_status(-1, "项目标记名称不能为空")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -102,12 +102,12 @@ class IssueTagsController < ApplicationController
|
|||
if @issue_tag.destroy
|
||||
# issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call
|
||||
# if issue_tag
|
||||
# normal_status(0, "标签删除成功")
|
||||
# normal_status(0, "项目标记删除成功")
|
||||
# else
|
||||
# normal_status(-1, "标签删除失败")
|
||||
# normal_status(-1, "项目标记删除失败")
|
||||
# end
|
||||
else
|
||||
normal_status(-1, "标签删除失败")
|
||||
normal_status(-1, "项目标记删除失败")
|
||||
end
|
||||
rescue => e
|
||||
puts "create version release error: #{e.message}"
|
||||
|
@ -122,16 +122,16 @@ class IssueTagsController < ApplicationController
|
|||
@user = @project.owner
|
||||
end
|
||||
|
||||
def check_issue_permission
|
||||
unless @project.member?(current_user) || current_user.admin?
|
||||
normal_status(-1, "您没有权限")
|
||||
def check_issue_tags_permission
|
||||
unless @project.manager?(current_user) || current_user.admin?
|
||||
return render_forbidden('你不是管理员,没有权限操作')
|
||||
end
|
||||
end
|
||||
|
||||
def set_issue_tag
|
||||
@issue_tag = IssueTag.find_by_id(params[:id])
|
||||
unless @issue_tag.present?
|
||||
normal_status(-1, "标签不存在")
|
||||
normal_status(-1, "项目标记不存在")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ class IssuesController < ApplicationController
|
|||
include TagChosenHelper
|
||||
|
||||
def index
|
||||
@user_operate_issue = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user))
|
||||
@user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user) || @project.is_public?)
|
||||
issues = @project.issues.issue_issue.issue_index_includes
|
||||
issues = issues.where(is_private: false) unless @user_admin_or_member
|
||||
|
@ -23,13 +24,13 @@ class IssuesController < ApplicationController
|
|||
@filter_issues = @all_issues
|
||||
@filter_issues = @filter_issues.where.not(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::ADD
|
||||
@filter_issues = @filter_issues.where(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::SOLVING
|
||||
@filter_issues = @filter_issues.where("subject LIKE ? OR description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
|
||||
@filter_issues = @filter_issues.where("issues.subject LIKE ? OR issues.description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
|
||||
@open_issues = @all_issues.where.not(status_id: IssueStatus::CLOSED)
|
||||
@close_issues = @all_issues.where(status_id: IssueStatus::CLOSED)
|
||||
@assign_to_me = @filter_issues.where(assigned_to_id: current_user&.id)
|
||||
@my_published = @filter_issues.where(author_id: current_user&.id)
|
||||
scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "Issue")
|
||||
@issues_size = scopes.size
|
||||
@assign_to_me = scopes.where(assigned_to_id: current_user&.id)
|
||||
@my_published = scopes.where(author_id: current_user&.id)
|
||||
@issues = paginate(scopes)
|
||||
|
||||
respond_to do |format|
|
||||
|
@ -108,7 +109,7 @@ class IssuesController < ApplicationController
|
|||
|
||||
def create
|
||||
issue_params = issue_send_params(params)
|
||||
Issues::CreateForm.new({subject:issue_params[:subject]}).validate!
|
||||
Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
|
||||
@issue = Issue.new(issue_params)
|
||||
if @issue.save!
|
||||
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
|
||||
|
@ -125,10 +126,17 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
end
|
||||
if params[:issue_tag_ids].present?
|
||||
params[:issue_tag_ids].each do |tag|
|
||||
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
|
||||
end
|
||||
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
|
||||
return normal_status(-1, "最多只能创建一个标记。")
|
||||
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
|
||||
params[:issue_tag_ids].each do |tag|
|
||||
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
|
||||
end
|
||||
else
|
||||
return normal_status(-1, "请输入正确的标记。")
|
||||
end
|
||||
end
|
||||
|
||||
if params[:assigned_to_id].present?
|
||||
Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id,
|
||||
container_id: @issue.id, container_type: 'Issue',
|
||||
|
@ -142,11 +150,13 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
|
||||
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
|
||||
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE) if params[:status_id].to_i == 5
|
||||
|
||||
|
||||
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
|
||||
AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
|
||||
|
||||
render json: {status: 0, message: "创建成", id: @issue.id}
|
||||
render json: {status: 0, message: "创建成功", id: @issue.id}
|
||||
else
|
||||
normal_status(-1, "创建失败")
|
||||
end
|
||||
|
@ -157,19 +167,27 @@ class IssuesController < ApplicationController
|
|||
|
||||
def edit
|
||||
# @issue_chosen = issue_left_chosen(@project, @issue.id)
|
||||
@cannot_edit_tags = @issue.issue_type=="2" && @issue.status_id == 5 #悬赏任务已解决且关闭的状态下,不能修改
|
||||
@issue_attachments = @issue.attachments
|
||||
end
|
||||
|
||||
def update
|
||||
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
|
||||
return normal_status(-1, "您没有权限修改token") if @issue.will_save_change_to_token? && @issue.user_id != current_user&.id
|
||||
last_token = @issue.token
|
||||
last_status_id = @issue.status_id
|
||||
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
|
||||
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
|
||||
@issue&.issue_tags_relates&.destroy_all
|
||||
params[:issue_tag_ids].each do |tag|
|
||||
IssueTagsRelate.create(issue_id: @issue.id, issue_tag_id: tag)
|
||||
end
|
||||
if params[:issue_tag_ids].present?
|
||||
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
|
||||
return normal_status(-1, "最多只能创建一个标记。")
|
||||
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
|
||||
@issue&.issue_tags_relates&.destroy_all
|
||||
params[:issue_tag_ids].each do |tag|
|
||||
next if tag == [""]
|
||||
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
|
||||
end
|
||||
else
|
||||
return normal_status(-1, "请输入正确的标记。")
|
||||
end
|
||||
end
|
||||
|
||||
issue_files = params[:attachment_ids]
|
||||
|
@ -188,6 +206,7 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# if params[:issue_tag_ids].present?
|
||||
# issue_current_tags = @issue&.issue_tags&.select(:id)&.pluck(:id)
|
||||
|
@ -207,7 +226,7 @@ class IssuesController < ApplicationController
|
|||
normal_status(-1, "不允许修改为关闭状态")
|
||||
else
|
||||
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
|
||||
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate!
|
||||
Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
|
||||
if @issue.update_attributes(issue_params)
|
||||
if @issue&.pull_request.present?
|
||||
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
|
||||
|
@ -231,7 +250,7 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
|
||||
@issue.issue_times.update_all(end_time: Time.now)
|
||||
@issue.update_closed_issues_count_in_project!
|
||||
# @issue.update_closed_issues_count_in_project!
|
||||
if @issue.issue_type.to_s == "2" && last_status_id != 5
|
||||
if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时,才给token
|
||||
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))
|
||||
|
@ -256,6 +275,8 @@ class IssuesController < ApplicationController
|
|||
else
|
||||
normal_status(-1, "更新失败")
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
rescue Exception => exception
|
||||
puts exception.message
|
||||
|
@ -289,20 +310,17 @@ class IssuesController < ApplicationController
|
|||
if issue_type == "2" && status_id != 5
|
||||
post_to_chain("add", token, login)
|
||||
end
|
||||
normal_status(0, "删除成功")
|
||||
return normal_status(0, "删除成功")
|
||||
else
|
||||
normal_status(-1, "删除失败")
|
||||
return normal_status(-1, "删除失败")
|
||||
end
|
||||
rescue => exception
|
||||
Rails.logger.info("#########_______exception.message_________##########{exception.message}")
|
||||
normal_status(-1, "删除失败")
|
||||
else
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def clean
|
||||
#批量删除,暂时只能删除未悬赏的
|
||||
issue_ids = params[:ids]
|
||||
issues = Issue.where(id: issue_ids, issue_type: "1")
|
||||
if issues.present?
|
||||
|
@ -473,7 +491,8 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
|
||||
def operate_issue_permission
|
||||
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || @project.is_public?)
|
||||
@issue = Issue.find_by_id(params[:id]) unless @issue.present?
|
||||
return render_forbidden("您没有权限进行此操作.") unless current_user.present? && current_user.logged? && (current_user.admin? || @project.member?(current_user) || (@project.is_public && @issue.nil?) || (@project.is_public && @issue.present? && @issue.author_id == current_user.id))
|
||||
end
|
||||
|
||||
def export_issues(issues)
|
||||
|
|
|
@ -23,6 +23,7 @@ class JournalsController < ApplicationController
|
|||
normal_status(-1, "评论内容不能为空")
|
||||
else
|
||||
ActiveRecord::Base.transaction do
|
||||
Journals::CreateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
|
||||
journal_params = {
|
||||
journalized_id: @issue.id ,
|
||||
journalized_type: "Issue",
|
||||
|
@ -53,6 +54,9 @@ class JournalsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
rescue Exception => exception
|
||||
puts exception.message
|
||||
normal_status(-1, exception.message)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -70,16 +74,19 @@ class JournalsController < ApplicationController
|
|||
|
||||
def update
|
||||
content = params[:content]
|
||||
if content.present?
|
||||
if content.present?
|
||||
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
|
||||
if @journal.update_attribute(:notes, content)
|
||||
normal_status(0, "更新成功")
|
||||
else
|
||||
normal_status(-1, "更新失败")
|
||||
normal_status(-1, @journal.errors.messages.values[0][0])
|
||||
end
|
||||
else
|
||||
normal_status(-1, "评论的内容不能为空")
|
||||
end
|
||||
|
||||
rescue Exception => exception
|
||||
puts exception.message
|
||||
normal_status(-1, exception.message)
|
||||
end
|
||||
|
||||
def get_children_journals
|
||||
|
|
|
@ -4,6 +4,8 @@ class MainController < ApplicationController
|
|||
skip_before_action :user_setup
|
||||
skip_before_action :setup_laboratory
|
||||
|
||||
#before_action :sso_login, only: [:index]
|
||||
|
||||
def first_stamp
|
||||
render :json => { status: 0, message: Time.now.to_i }
|
||||
end
|
||||
|
@ -29,4 +31,110 @@ class MainController < ApplicationController
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
def sso_login
|
||||
return if current_user.logged?
|
||||
return unless EduSetting.get("509_SSO_LOGIN_OPEN").to_s == "true"
|
||||
user_token = params['access_token']
|
||||
Rails.logger.info "=== params.access_token user_token ====#{user_token}"
|
||||
|
||||
app_domain = EduSetting.get("509_APP_DOMAIN")
|
||||
access_token = get_509_sso_token
|
||||
if access_token.present?
|
||||
api_user_url ="#{app_domain}/api/sso/user?access_token=#{user_token}"
|
||||
user_params = url_http_post(api_user_url, {})
|
||||
if user_params['rsltcode'].to_s == "0"
|
||||
login = user_params['account']
|
||||
login = login[0..20] if login.size > 29
|
||||
phone = user_params['mobile']
|
||||
mail = user_params['useremail']
|
||||
mail = "#{login}@example.org" if mail.blank?
|
||||
nickname = user_params['fullname']
|
||||
orgName = user_params['orgName']
|
||||
user = phone.present? ? User.find_by(phone: phone) : nil
|
||||
user = User.where("login = ? or phone = ? or mail = ? ", login.presence, phone.presence, mail.presence).first if user.nil?
|
||||
if user.blank?
|
||||
Rails.logger.info "=== 创建新用户 ===="
|
||||
user = User.new(type: "User")
|
||||
user.login = login
|
||||
user.phone = phone
|
||||
user.mail = mail
|
||||
user.nickname = nickname if nickname.present?
|
||||
user.company_name = orgName if orgName.present?
|
||||
user.user_type = "6"
|
||||
user.professional_field = "12"
|
||||
password = "a12345678"
|
||||
user.password = password
|
||||
|
||||
# gitea用户注册, email, username, password
|
||||
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
|
||||
if interactor.success?
|
||||
gitea_user = interactor.result
|
||||
result = Gitea::User::GenerateTokenService.call(user.login, password)
|
||||
user.gitea_token = result['sha1']
|
||||
user.gitea_uid = gitea_user[:body]['id']
|
||||
if user.save!
|
||||
UserExtension.create!(user_id: user.id)
|
||||
end
|
||||
else
|
||||
tip_exception(-1, interactor.result[:message])
|
||||
end
|
||||
else
|
||||
user.update!(phone: phone) if user.phone.blank? && phone.present? && User.find_by(phone: phone).blank?
|
||||
user.update!(nickname: nickname) if user.nickname.blank? && nickname.present?
|
||||
end
|
||||
successful_authentication(user)
|
||||
else
|
||||
Rails.logger.error("#############api_url:#{api_user_url},code: #{user_params['rsltcode']}, msg: #{user_params['rsltcode']}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_509_sso_token
|
||||
app_id = EduSetting.get("509_APP_ID")
|
||||
app_secret = EduSetting.get("509_APP_SECRET")
|
||||
app_domain = EduSetting.get("509_APP_DOMAIN")
|
||||
api_token_url ="#{app_domain}/api/uaa/oauth/token?client_id=#{app_id}&client_secret=#{app_secret}&grant_type=client_credentials"
|
||||
# api_token_url ="#{app_domain}/oauth/token?client_id=#{app_id}&client_secret=#{app_secret}&grant_type=client_credentials"
|
||||
access_token = Rails.cache.read("509_APP/access_token")
|
||||
if access_token.present?
|
||||
api_check_token_url = "#{app_domain}/api/sso/valtoken/#{access_token}"
|
||||
# api_check_token_url = "#{app_domain}/api/sso/user?access_token=#{access_token}"
|
||||
result = url_http_post(api_check_token_url, {})
|
||||
if result['rsltcode'].to_s != "0"
|
||||
data = url_http_post(api_token_url, {})
|
||||
access_token = data['access_token']
|
||||
Rails.cache.write("509_APP/access_token", access_token, expires_in: 5.days)
|
||||
end
|
||||
else
|
||||
data = url_http_post(api_token_url, {})
|
||||
access_token = data['access_token']
|
||||
Rails.cache.write("509_APP/access_token", access_token, expires_in: 5.days)
|
||||
end
|
||||
access_token
|
||||
end
|
||||
|
||||
def url_http_post(api_url,params)
|
||||
Rails.logger.info "api_url==#{api_url}"
|
||||
uri = URI.parse(api_url)
|
||||
http = Net::HTTP.new uri.host, uri.port
|
||||
http.open_timeout = 60
|
||||
http.read_timeout = 60
|
||||
if uri.scheme == 'https'
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
http.use_ssl = true
|
||||
end
|
||||
begin
|
||||
request = Net::HTTP::Post.new(uri)
|
||||
request.set_form_data(params) if params.present?
|
||||
request['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
|
||||
response = http.start { |http| http.request(request) }
|
||||
Rails.logger.info "api response.body==#{response.body}"
|
||||
JSON.parse response.body
|
||||
rescue =>err
|
||||
Rails.logger.error("#############api_url:#{api_url},error:#{err.message.size}")
|
||||
# Rails.logger.error("#############api_url:#{api_url},error:#{err.message}")
|
||||
return {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
class MarkFilesController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :load_project
|
||||
before_action :load_pull_request
|
||||
|
||||
def index
|
||||
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token, { "only-file-name": true })
|
||||
@mark_files = MarkFile.where(pull_request_id: @pull_request.id)
|
||||
end
|
||||
|
||||
def create
|
||||
# unless @pull_request.mark_files.present?
|
||||
# MarkFile.bulk_insert(*%i[pull_request_id, file_path_sha file_path created_at updated_at]) do |worker|
|
||||
# @files_result['Files'].each do |file|
|
||||
# worker.add(pull_request_id: @pull_request.id, file_path_sha: SecureRandom.uuid.gsub("-", ""), file_path: file['Name'])
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
def mark_file_as_unread
|
||||
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||
mark_file.file_path = file_path
|
||||
mark_file.user_id = current_user.id
|
||||
mark_file.mark_as_read = false
|
||||
mark_file.save
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
tip_exception "参数解析错误"
|
||||
end
|
||||
|
||||
def mark_file_as_read
|
||||
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||
mark_file.file_path = file_path
|
||||
mark_file.user_id = current_user.id
|
||||
mark_file.mark_as_read = true
|
||||
mark_file.save
|
||||
render_ok
|
||||
rescue Exception => e
|
||||
tip_exception "参数解析错误"
|
||||
end
|
||||
|
||||
private
|
||||
def review_params
|
||||
params.require(:review).permit(:content, :commit_id, :status)
|
||||
end
|
||||
|
||||
def load_pull_request
|
||||
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
end
|
|
@ -3,7 +3,7 @@ class MembersController < ApplicationController
|
|||
before_action :load_project
|
||||
before_action :find_user_with_id, only: %i[create remove change_role]
|
||||
before_action :check_user_profile_completed, only: [:create]
|
||||
before_action :operate!, except: %i[index]
|
||||
before_action :operate!
|
||||
before_action :check_member_exists!, only: %i[create]
|
||||
before_action :check_member_not_exists!, only: %i[remove change_role]
|
||||
|
||||
|
@ -26,6 +26,9 @@ class MembersController < ApplicationController
|
|||
|
||||
@total_count = scope.size
|
||||
@members = paginate(scope)
|
||||
if @project.owner.is_a?(Organization) && (params[:page].to_i == 1 || params[:page].blank?) && !@project.members.exists?(user_id: current_user.id)
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
end
|
||||
end
|
||||
|
||||
def remove
|
||||
|
@ -61,11 +64,14 @@ class MembersController < ApplicationController
|
|||
end
|
||||
|
||||
def check_member_exists!
|
||||
return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
return render_error("#{@user&.nickname}已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?)
|
||||
end
|
||||
|
||||
def check_member_not_exists!
|
||||
return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
|
||||
@current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take
|
||||
return render_error("用户为组织成员,请到组织下操作!") if (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) && !member_exists?
|
||||
return render_error("#{@user&.nickname}还不是项目成员") unless member_exists?
|
||||
end
|
||||
|
||||
def check_user_profile_completed
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
class NoticesController < ApplicationController
|
||||
|
||||
def create
|
||||
return tip_exception("参数有误") if params["source"].blank?
|
||||
user_id = params[:user_id]
|
||||
|
||||
if params["source"] == "CompetitionBegin"
|
||||
competition_id = params[:competition_id]
|
||||
SendTemplateMessageJob.perform_later('CompetitionBegin', user_id, competition_id)
|
||||
elsif params["source"] == "CompetitionResult"
|
||||
competition_id = params[:competition_id]
|
||||
SendTemplateMessageJob.perform_later('CompetitionResult', user_id, competition_id)
|
||||
elsif params["source"] == "CompetitionReview"
|
||||
competition_id = params[:competition_id]
|
||||
SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id)
|
||||
elsif params["source"] == "CustomTip"
|
||||
users_id = params[:users_id]
|
||||
props = params[:props].to_unsafe_hash
|
||||
return tip_exception("参数有误") unless props.is_a?(Hash) && users_id.is_a?(Array)
|
||||
template_id = params[:template_id]
|
||||
SendTemplateMessageJob.perform_later('CustomTip', users_id, template_id, props)
|
||||
else
|
||||
tip_exception("#{params["source"]}未配置")
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def params_props
|
||||
params.require(:notice).permit(:props)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class NpsController < ApplicationController
|
||||
|
||||
before_action :require_login
|
||||
|
||||
# close,关闭
|
||||
# createIssue,创建issue
|
||||
# createPullRequest,创建PR
|
||||
# auditPullRequest,审核PR
|
||||
# indexProject,项目主页
|
||||
# createProject,创建项目
|
||||
# createOrganization,创建组织
|
||||
def create
|
||||
tip_exception "缺少参数" if params[:action_id].blank? || params[:action_type].blank?
|
||||
UserNp.create(:action_id => params[:action_id].to_i, :action_type => params[:action_type], :user_id => User.current.id, :score => params[:score].to_f, memo: params[:memo])
|
||||
render_ok
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue