Compare commits
892 Commits
v7.0.0-alp
...
7.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
073e48c396 | ||
|
|
a335ed8e9b | ||
|
|
02973a0f22 | ||
|
|
bffa5ebde2 | ||
|
|
3ec64c989b | ||
|
|
c643833496 | ||
|
|
759979fc10 | ||
|
|
8859682366 | ||
|
|
f5183babf6 | ||
|
|
db087d0ccb | ||
|
|
70d43e6e53 | ||
|
|
a45770732a | ||
|
|
ec4f10d43a | ||
|
|
eff9f6fec6 | ||
|
|
96394228ea | ||
|
|
ae68550448 | ||
|
|
a2ea9b29ba | ||
|
|
1725ea5a9e | ||
|
|
12679e85a8 | ||
|
|
79d4928e18 | ||
|
|
7a34756188 | ||
|
|
97baf98d04 | ||
|
|
eb27c94637 | ||
|
|
5f9e7d5754 | ||
|
|
6e9dcf8a31 | ||
|
|
aedb1f22b6 | ||
|
|
41baefbf4a | ||
|
|
3c21047c15 | ||
|
|
52332c250b | ||
|
|
0c89d36a16 | ||
|
|
4ac781a20d | ||
|
|
d68d8791bd | ||
|
|
23eb9dcbda | ||
|
|
7a76ac4226 | ||
|
|
37fc761567 | ||
|
|
1b82ef6c88 | ||
|
|
7ace8bccd6 | ||
|
|
b213f2bb4c | ||
|
|
0d1f38cf85 | ||
|
|
e62e4a865d | ||
|
|
09f3e3cfdf | ||
|
|
fd2f4f2150 | ||
|
|
651174bda8 | ||
|
|
bbec276da8 | ||
|
|
25999d55a3 | ||
|
|
6018a6dcaa | ||
|
|
94ba5d8680 | ||
|
|
3d6a29795b | ||
|
|
dd2b297cc5 | ||
|
|
7fdaf62ef5 | ||
|
|
182aabf426 | ||
|
|
91a5eb535d | ||
|
|
b6189bab7e | ||
|
|
dc51897314 | ||
|
|
c1103afe8f | ||
|
|
39fbdcb787 | ||
|
|
47be7507f0 | ||
|
|
5cafebe4d6 | ||
|
|
becf6c95f0 | ||
|
|
380c9d13b6 | ||
|
|
a08c9db284 | ||
|
|
ff6ba4c29a | ||
|
|
f6465bea58 | ||
|
|
5cce1b3040 | ||
|
|
e12188b7d3 | ||
|
|
092b9fc9dc | ||
|
|
6292b05ad5 | ||
|
|
732a0c4088 | ||
|
|
753804b71b | ||
|
|
9f3ba05880 | ||
|
|
3a97071fcf | ||
|
|
d4c172e734 | ||
|
|
95147e31bf | ||
|
|
63485d5a0f | ||
|
|
aa57997ff5 | ||
|
|
f31d6a00ec | ||
|
|
e307da36b5 | ||
|
|
be5dd68c81 | ||
|
|
e9e2e12e4e | ||
|
|
981a5915e3 | ||
|
|
224cfaf603 | ||
|
|
71f5d33af7 | ||
|
|
70f470d64e | ||
|
|
fcc6295a77 | ||
|
|
c5007f2928 | ||
|
|
62a10224a0 | ||
|
|
ee1c8ee3fa | ||
|
|
823325d049 | ||
|
|
b2cf7acfb6 | ||
|
|
c6547ac7fc | ||
|
|
748601064c | ||
|
|
a9c5be1c70 | ||
|
|
a0a6ab027f | ||
|
|
e97ae78e47 | ||
|
|
89a01afc7c | ||
|
|
9475a737f0 | ||
|
|
0225a84a81 | ||
|
|
bb15119bf0 | ||
|
|
95ae3aacb3 | ||
|
|
482a9cb04f | ||
|
|
f5dcd06838 | ||
|
|
9c8c06ef28 | ||
|
|
567ff91de0 | ||
|
|
337fe5cfaa | ||
|
|
ec81a6d157 | ||
|
|
15e6226511 | ||
|
|
80560ec20c | ||
|
|
3e1d9080df | ||
|
|
454776ecd4 | ||
|
|
dd946d4cdd | ||
|
|
a720f12e0b | ||
|
|
31f16d693b | ||
|
|
ed91ddb5a8 | ||
|
|
08a2be165c | ||
|
|
c04bfb78c6 | ||
|
|
06d8f11ca3 | ||
|
|
466d04caf7 | ||
|
|
02674f6ecb | ||
|
|
d8795e66da | ||
|
|
8cdf47f7b3 | ||
|
|
331b9133a8 | ||
|
|
783c06d811 | ||
|
|
8a4516f1ba | ||
|
|
6543728478 | ||
|
|
54347c6706 | ||
|
|
b169337fb6 | ||
|
|
b28ace970c | ||
|
|
29ca9711f8 | ||
|
|
313c0b0c80 | ||
|
|
f9ecabdccc | ||
|
|
abb1eb332d | ||
|
|
faf51de9a9 | ||
|
|
ae464b7601 | ||
|
|
79c60d34c2 | ||
|
|
fb9c1c3681 | ||
|
|
4653eb20ad | ||
|
|
c7376a59f0 | ||
|
|
09307443f9 | ||
|
|
4259533958 | ||
|
|
da87a35a69 | ||
|
|
7a468b2c16 | ||
|
|
a39549d597 | ||
|
|
a176ed2dae | ||
|
|
4ae17f65c8 | ||
|
|
be441dacd9 | ||
|
|
5210c78d5e | ||
|
|
e1bdef98d6 | ||
|
|
defd78e5c2 | ||
|
|
27944b8235 | ||
|
|
f0ef723854 | ||
|
|
889ed06acc | ||
|
|
267a0e21ba | ||
|
|
7e461f401b | ||
|
|
2ca1f33e68 | ||
|
|
dbd7c5e90b | ||
|
|
d65b74d7a0 | ||
|
|
8d6621e2a8 | ||
|
|
88957f4071 | ||
|
|
75eaec2f11 | ||
|
|
a79f28caa4 | ||
|
|
25a9ca9b90 | ||
|
|
d5a3328130 | ||
|
|
18c5cf766d | ||
|
|
1c935998fb | ||
|
|
1b1cf2a891 | ||
|
|
047a72f3da | ||
|
|
87aa6ed1da | ||
|
|
7f0fb16dc3 | ||
|
|
82f6dfbece | ||
|
|
b8d4f4e5c4 | ||
|
|
df814edafe | ||
|
|
1ec866d4dc | ||
|
|
7fce5421b4 | ||
|
|
65bd6888e8 | ||
|
|
2ca4393c5a | ||
|
|
099600cf4c | ||
|
|
4dd3fc5244 | ||
|
|
a90d9aac39 | ||
|
|
81652cf70e | ||
|
|
5f0db96fc4 | ||
|
|
2b45b9fd70 | ||
|
|
5b061ba636 | ||
|
|
1dae81b707 | ||
|
|
3ceb5fbe5b | ||
|
|
5fac731a57 | ||
|
|
d00115fc1a | ||
|
|
d2c20f97fd | ||
|
|
400e4854e8 | ||
|
|
12c66e2681 | ||
|
|
56c2115144 | ||
|
|
de6420ad59 | ||
|
|
93b03bb5ab | ||
|
|
86b68fb515 | ||
|
|
52ed248f7d | ||
|
|
bc58a2b076 | ||
|
|
fd96bb49f6 | ||
|
|
30a53670fe | ||
|
|
204f3a7397 | ||
|
|
3a6e3e0e24 | ||
|
|
3bea54136b | ||
|
|
655dc39c63 | ||
|
|
e2637ce0a7 | ||
|
|
c8c3e2bb79 | ||
|
|
ec662243d8 | ||
|
|
93b738be79 | ||
|
|
54c4e017cc | ||
|
|
1d0e6cc10e | ||
|
|
29a578ea6a | ||
|
|
905be6ffc3 | ||
|
|
2d002e5cc5 | ||
|
|
2132b50ede | ||
|
|
8d8857e552 | ||
|
|
6816c77845 | ||
|
|
2f2eb2e5b2 | ||
|
|
d2257095da | ||
|
|
53d4380339 | ||
|
|
4e9ea9aa3c | ||
|
|
a6a52ef7bb | ||
|
|
239483dfc4 | ||
|
|
e4b8707e34 | ||
|
|
c0afb2ea8f | ||
|
|
e367bd9a2e | ||
|
|
62871c8a7d | ||
|
|
9bc6fd23b9 | ||
|
|
9d762df946 | ||
|
|
e48f25d0ba | ||
|
|
20a6e0ffb6 | ||
|
|
4b39b44dab | ||
|
|
8c358948e5 | ||
|
|
3cafe20736 | ||
|
|
0014a4254d | ||
|
|
9f226fe574 | ||
|
|
e23caec9f3 | ||
|
|
64bee1b238 | ||
|
|
1b1eb1539e | ||
|
|
4bc0a786ab | ||
|
|
6f7735afa7 | ||
|
|
3aef1a0aae | ||
|
|
cd327502d9 | ||
|
|
900e8ffe26 | ||
|
|
270556eb1c | ||
|
|
e319f8eba4 | ||
|
|
48b14091c4 | ||
|
|
88122c14d2 | ||
|
|
3911d95107 | ||
|
|
61c7a3d54d | ||
|
|
075d4b3069 | ||
|
|
c5498937dc | ||
|
|
f8b21c99e2 | ||
|
|
8b6c44de6f | ||
|
|
b852bdc411 | ||
|
|
2e0cc10ded | ||
|
|
7707d8816e | ||
|
|
a3239e78db | ||
|
|
bbce735e31 | ||
|
|
262aad2d7a | ||
|
|
99e472f99c | ||
|
|
d40c9ba91f | ||
|
|
ab5480fdc9 | ||
|
|
fbcaa382f4 | ||
|
|
aebb517791 | ||
|
|
2de900eaa8 | ||
|
|
e878168d4c | ||
|
|
d04565919b | ||
|
|
146fe05bdc | ||
|
|
daffd1017f | ||
|
|
b66f10510e | ||
|
|
9e55f8ecf0 | ||
|
|
bac6396b19 | ||
|
|
b73182f830 | ||
|
|
ec873f2b82 | ||
|
|
24fb55872f | ||
|
|
f7ae027156 | ||
|
|
f46e5090ae | ||
|
|
c95fe3c971 | ||
|
|
5992dad5a3 | ||
|
|
646987764f | ||
|
|
ebac18ebef | ||
|
|
f2f0873b2e | ||
|
|
f14f7c1a5e | ||
|
|
fbe3804658 | ||
|
|
1c1c0d55f4 | ||
|
|
20d8a2d0a7 | ||
|
|
e71f12311a | ||
|
|
19a206f4ac | ||
|
|
8171d681a6 | ||
|
|
aba23f99bd | ||
|
|
525e8ba8bb | ||
|
|
75ef658d8f | ||
|
|
e5935507c8 | ||
|
|
3c32f2d89d | ||
|
|
e95b3eb366 | ||
|
|
0f3424f41e | ||
|
|
046dac5db5 | ||
|
|
9596d88b48 | ||
|
|
20f46adbc4 | ||
|
|
7b8e20f348 | ||
|
|
996ebde501 | ||
|
|
36d91265d3 | ||
|
|
796053cfa5 | ||
|
|
1c32ef838d | ||
|
|
a62c938099 | ||
|
|
a9536064d3 | ||
|
|
543026da18 | ||
|
|
e77488c66a | ||
|
|
91a64113fb | ||
|
|
25cead3288 | ||
|
|
80556dcda3 | ||
|
|
ffccb01670 | ||
|
|
299f391455 | ||
|
|
666c5d50d4 | ||
|
|
56c1f5ce4d | ||
|
|
79806c3b42 | ||
|
|
66a9b361cb | ||
|
|
89baf34824 | ||
|
|
5ee053cace | ||
|
|
2dee3190ce | ||
|
|
1f50d2b7f7 | ||
|
|
c40a8c893d | ||
|
|
b2cc818b7a | ||
|
|
0ce86e9e44 | ||
|
|
e680f33326 | ||
|
|
69eebd9370 | ||
|
|
fb17159743 | ||
|
|
0f1a4bbf33 | ||
|
|
68b00f776a | ||
|
|
87206ed2b4 | ||
|
|
5b233da11b | ||
|
|
28f10eaf41 | ||
|
|
26061deced | ||
|
|
3f3f0dd81d | ||
|
|
4596ddae58 | ||
|
|
91b1fd5dca | ||
|
|
1b51bc8c04 | ||
|
|
0af85a3fff | ||
|
|
4ca58ed754 | ||
|
|
f640381978 | ||
|
|
761c845300 | ||
|
|
1b62cb7109 | ||
|
|
ad7aa7c8ce | ||
|
|
9cc640b866 | ||
|
|
85615300e0 | ||
|
|
5caecf9c5f | ||
|
|
a1868075ed | ||
|
|
81ecb5673f | ||
|
|
7c414e5419 | ||
|
|
8b368a3808 | ||
|
|
fef36f89f4 | ||
|
|
e9aaa85fc7 | ||
|
|
9125cc3d87 | ||
|
|
230d3bebd3 | ||
|
|
5b227c3a60 | ||
|
|
316bc14526 | ||
|
|
9bc3a67c9a | ||
|
|
a083f9c671 | ||
|
|
b7a6cb4fbc | ||
|
|
d76b264238 | ||
|
|
e02ae682a8 | ||
|
|
59b99497a7 | ||
|
|
42fb13294b | ||
|
|
a515921143 | ||
|
|
019cf9b4fb | ||
|
|
17cece598b | ||
|
|
8179611cac | ||
|
|
0a7f002217 | ||
|
|
36dcd61feb | ||
|
|
072a7ffe12 | ||
|
|
9173558a0b | ||
|
|
7cba92d420 | ||
|
|
3288467aa1 | ||
|
|
2b074ee894 | ||
|
|
33ef3dd252 | ||
|
|
bd84877f0e | ||
|
|
1258b87671 | ||
|
|
ba1bf4581d | ||
|
|
440a0c5425 | ||
|
|
74b53b4ba7 | ||
|
|
1a3065b1ca | ||
|
|
fb6fc118e3 | ||
|
|
b63c9a8cd4 | ||
|
|
203b6496fc | ||
|
|
a747657642 | ||
|
|
ba9c64f420 | ||
|
|
c2bcebdb29 | ||
|
|
f4ca576178 | ||
|
|
459f69f609 | ||
|
|
06f8322eeb | ||
|
|
84f64f45d9 | ||
|
|
6899ea1964 | ||
|
|
81c148fc4d | ||
|
|
89ebcbdb10 | ||
|
|
a38bad9648 | ||
|
|
7432ea5cc7 | ||
|
|
1c84dd1e44 | ||
|
|
078f361a39 | ||
|
|
0b1670aae5 | ||
|
|
10867b2641 | ||
|
|
a346b0df2e | ||
|
|
ba8a819c7d | ||
|
|
77a2fd70c3 | ||
|
|
1c0c7e0012 | ||
|
|
e026a8d333 | ||
|
|
650d9884b0 | ||
|
|
0d53c5487d | ||
|
|
993513c22b | ||
|
|
959db2e247 | ||
|
|
c64dec1080 | ||
|
|
da0a7cbe81 | ||
|
|
a63a784dec | ||
|
|
40c7fd8977 | ||
|
|
3e96b195a6 | ||
|
|
c8a9ebd26d | ||
|
|
63897a5666 | ||
|
|
9332f64284 | ||
|
|
3f1bb26ee5 | ||
|
|
9ca8825868 | ||
|
|
b8424f712d | ||
|
|
bc7fccfb95 | ||
|
|
605bf477ad | ||
|
|
df88cb141a | ||
|
|
5230fc9600 | ||
|
|
62aa825c0f | ||
|
|
42c6a11780 | ||
|
|
4fa024045d | ||
|
|
9542c23717 | ||
|
|
7d2d932f50 | ||
|
|
bd7bd7e802 | ||
|
|
4fc30ec4bc | ||
|
|
00458ee754 | ||
|
|
3f1f83438d | ||
|
|
f593c7d92f | ||
|
|
feeb4946d1 | ||
|
|
f671d3f624 | ||
|
|
0cd7b3b71f | ||
|
|
d80e70e2b1 | ||
|
|
f8965f1785 | ||
|
|
23f1a8225a | ||
|
|
cbb5182cea | ||
|
|
ff8f29be24 | ||
|
|
64302252c0 | ||
|
|
d768b9cc0e | ||
|
|
4bc7d7735d | ||
|
|
8aa629fc56 | ||
|
|
ec273d2928 | ||
|
|
06d767279b | ||
|
|
b1209712d1 | ||
|
|
ecf2307542 | ||
|
|
24a2467338 | ||
|
|
4c65bf8142 | ||
|
|
31d0683592 | ||
|
|
41f4c76006 | ||
|
|
d0485f98a9 | ||
|
|
ec565fa0de | ||
|
|
4f9c028676 | ||
|
|
5dff563c75 | ||
|
|
9183e0b2aa | ||
|
|
6701ce8c1a | ||
|
|
3a81e2ec27 | ||
|
|
b96f1cd7c4 | ||
|
|
50abda71cb | ||
|
|
73ffc9cf44 | ||
|
|
7decac105f | ||
|
|
89f067807b | ||
|
|
5cd9c608a7 | ||
|
|
531e86f5e7 | ||
|
|
fb6d5a6a0a | ||
|
|
fe5400a3bb | ||
|
|
9502dd9835 | ||
|
|
203ee72052 | ||
|
|
29d206bba3 | ||
|
|
110fde34ea | ||
|
|
2c2b569c6c | ||
|
|
6c83b539c8 | ||
|
|
b7a1c2cb41 | ||
|
|
cff7e2c4da | ||
|
|
59302ded0f | ||
|
|
ea32353890 | ||
|
|
0965465601 | ||
|
|
2319a8c9f4 | ||
|
|
63c5d69e10 | ||
|
|
e369695da5 | ||
|
|
775900bb14 | ||
|
|
9d3d284df7 | ||
|
|
395642f69c | ||
|
|
8d2fd22e3e | ||
|
|
e668a5089e | ||
|
|
f54f19100c | ||
|
|
4a19f609fc | ||
|
|
e109e00aa8 | ||
|
|
e1c8174b3f | ||
|
|
0986cddae1 | ||
|
|
86d28aafd6 | ||
|
|
f842e86885 | ||
|
|
5a30ba683e | ||
|
|
c102a0d858 | ||
|
|
eae5989845 | ||
|
|
f4f41cd900 | ||
|
|
078f8038e4 | ||
|
|
d5fba47dc6 | ||
|
|
3e89a53fc1 | ||
|
|
7179910bc6 | ||
|
|
12a442970e | ||
|
|
42264eb180 | ||
|
|
a31b704203 | ||
|
|
129c551fa0 | ||
|
|
d8dad44e43 | ||
|
|
e27f6f1b14 | ||
|
|
052813ba4a | ||
|
|
7a3a2f3e9a | ||
|
|
9ff3c1ab10 | ||
|
|
a0422899a5 | ||
|
|
6fb66a1d80 | ||
|
|
4d3fb5b873 | ||
|
|
af28156498 | ||
|
|
99555539a7 | ||
|
|
04d63ca931 | ||
|
|
2351dbe717 | ||
|
|
717118cfb4 | ||
|
|
3dba586f83 | ||
|
|
36a7886668 | ||
|
|
0f98e729ce | ||
|
|
ccfa904300 | ||
|
|
9e1e0142e9 | ||
|
|
3ddee56359 | ||
|
|
bbfad3a0ef | ||
|
|
026a83591d | ||
|
|
6c516cf4bf | ||
|
|
c000034cab | ||
|
|
f84ff8de92 | ||
|
|
bb73af3806 | ||
|
|
cfd0853d79 | ||
|
|
2a01a935c0 | ||
|
|
02fa97504e | ||
|
|
eb06c07fdb | ||
|
|
0f521c3af9 | ||
|
|
ee077ffa16 | ||
|
|
e358b8706f | ||
|
|
793b3e7134 | ||
|
|
0bed38c78b | ||
|
|
46f9b3d9b9 | ||
|
|
1275d7ebc4 | ||
|
|
3744dbfd5d | ||
|
|
8fb239fb8f | ||
|
|
9eb8ed1804 | ||
|
|
a3bfcf01b7 | ||
|
|
71da25eca5 | ||
|
|
217da07007 | ||
|
|
70e5ccda6f | ||
|
|
777167f46e | ||
|
|
f2952c6567 | ||
|
|
2c726f6c52 | ||
|
|
1cbfdbdac5 | ||
|
|
63544088cd | ||
|
|
bd30b1f900 | ||
|
|
35fb6f0e52 | ||
|
|
36063e2ca6 | ||
|
|
08d3578d38 | ||
|
|
2090f05236 | ||
|
|
7fbcfa391b | ||
|
|
2ab4db3a2e | ||
|
|
be6fead812 | ||
|
|
badfcb0e76 | ||
|
|
cf43685740 | ||
|
|
0bf1286c3a | ||
|
|
184123194b | ||
|
|
bc013e31c8 | ||
|
|
b31384f429 | ||
|
|
ec553f06c8 | ||
|
|
95fed87ad4 | ||
|
|
d5452d6517 | ||
|
|
e366ca9375 | ||
|
|
12caa3b214 | ||
|
|
226c3d0ce2 | ||
|
|
a1a8c6f141 | ||
|
|
1518b8d4f7 | ||
|
|
999b11deb5 | ||
|
|
30a8028827 | ||
|
|
8ad83a5f9f | ||
|
|
504b33ba2a | ||
|
|
5cbb480f6e | ||
|
|
46f49048c8 | ||
|
|
5cad037d7d | ||
|
|
75874e1ed0 | ||
|
|
9387ad1891 | ||
|
|
ca831170f4 | ||
|
|
c51b074e32 | ||
|
|
c9b58a4d9d | ||
|
|
99142f9fec | ||
|
|
46e956475a | ||
|
|
5ecfc2d437 | ||
|
|
ca2f8e1aa5 | ||
|
|
204f0b7a10 | ||
|
|
699883f2fc | ||
|
|
eefce8bab6 | ||
|
|
02ae2353d4 | ||
|
|
0671742703 | ||
|
|
1eb7e5d59a | ||
|
|
33daaf4a35 | ||
|
|
f5c492bb7e | ||
|
|
c81fc5f25b | ||
|
|
eb64f268d3 | ||
|
|
f8f5a71564 | ||
|
|
1161106d9c | ||
|
|
c6f423087d | ||
|
|
182cb2d33b | ||
|
|
49dfa7fc17 | ||
|
|
28a44631fc | ||
|
|
29b84f9281 | ||
|
|
7105e82922 | ||
|
|
8b53ca2fdc | ||
|
|
112a72ac6f | ||
|
|
46d8fb125a | ||
|
|
a44204b185 | ||
|
|
4e3a9fd9ea | ||
|
|
d4f79b1331 | ||
|
|
78e70fec3b | ||
|
|
fbfd71adcf | ||
|
|
9657e8bd40 | ||
|
|
276b93fc57 | ||
|
|
95a7365fee | ||
|
|
dad44db0bc | ||
|
|
0dca866f11 | ||
|
|
bb5bb4d4c7 | ||
|
|
b9beb6c804 | ||
|
|
782121829a | ||
|
|
5d5565e5a8 | ||
|
|
9e43955fbb | ||
|
|
25a299fb74 | ||
|
|
485c6e86bb | ||
|
|
a9454c319a | ||
|
|
712cb185b4 | ||
|
|
4e59bd0442 | ||
|
|
06e1cd15c0 | ||
|
|
273ccc648d | ||
|
|
ccf56ddec1 | ||
|
|
04c5b9e7bf | ||
|
|
36ea12e135 | ||
|
|
6b002f24a8 | ||
|
|
6fa724d7b7 | ||
|
|
02a6d0d056 | ||
|
|
28d180e850 | ||
|
|
3a1ee94acf | ||
|
|
776cea7055 | ||
|
|
4b7cd6ce6e | ||
|
|
67ef6872af | ||
|
|
3c39aeee43 | ||
|
|
e9baf4acb5 | ||
|
|
a21e2dd412 | ||
|
|
7feecb507d | ||
|
|
26f00ccaae | ||
|
|
31b9195a6e | ||
|
|
45a22e26be | ||
|
|
7dd6a7e7f3 | ||
|
|
067fb0f9f0 | ||
|
|
d34de098e5 | ||
|
|
428d016e26 | ||
|
|
15d483b332 | ||
|
|
92bb56e344 | ||
|
|
b9380b2c3a | ||
|
|
ccbc109db2 | ||
|
|
58fbbd98a4 | ||
|
|
2aae789e2a | ||
|
|
e5ff927f7d | ||
|
|
afd7aebe20 | ||
|
|
7148f27d33 | ||
|
|
6975167a77 | ||
|
|
57cddee3fd | ||
|
|
684ee545cf | ||
|
|
bff80c2dc7 | ||
|
|
acb289f6d0 | ||
|
|
05655632cc | ||
|
|
1896e1cc35 | ||
|
|
0f9ce8bbb9 | ||
|
|
8076c2d8c1 | ||
|
|
17f9464208 | ||
|
|
843cf26140 | ||
|
|
a3264c1cd1 | ||
|
|
46452edf55 | ||
|
|
d90e118f56 | ||
|
|
7cc3fc6a3a | ||
|
|
98ebd5e358 | ||
|
|
f05e37767f | ||
|
|
03c15473b9 | ||
|
|
df8f6372f1 | ||
|
|
2ec7bc1caa | ||
|
|
4f8f82f69f | ||
|
|
724daabc5a | ||
|
|
83f0f1bfe3 | ||
|
|
aac355b077 | ||
|
|
f13c961863 | ||
|
|
fefc6bc22a | ||
|
|
d42bfc7aae | ||
|
|
dc2570a408 | ||
|
|
a325470b8f | ||
|
|
c7925db0e7 | ||
|
|
dad923489b | ||
|
|
453ca5b180 | ||
|
|
9d3953f3ac | ||
|
|
db10ebf807 | ||
|
|
88a8fd2bbd | ||
|
|
8c05ad134e | ||
|
|
505931736c | ||
|
|
01af6f6855 | ||
|
|
8b163348a2 | ||
|
|
53e4bf533f | ||
|
|
33c2ee702b | ||
|
|
a7a70ce423 | ||
|
|
96e8fbfa78 | ||
|
|
bf94a20e57 | ||
|
|
65940c6df2 | ||
|
|
56f5276bae | ||
|
|
454b2b488b | ||
|
|
2eb0f76f32 | ||
|
|
9424bf7c46 | ||
|
|
fa5237179b | ||
|
|
586769fbf0 | ||
|
|
2df09c533b | ||
|
|
9d65515290 | ||
|
|
607367feb2 | ||
|
|
9f89447070 | ||
|
|
284db21a3a | ||
|
|
02374dcd57 | ||
|
|
92a18448eb | ||
|
|
a3305249a6 | ||
|
|
f9208c9d72 | ||
|
|
2c52a2f7e6 | ||
|
|
f1b9ea94dc | ||
|
|
d22eed50ad | ||
|
|
498e795e4b | ||
|
|
1794549a20 | ||
|
|
d1fcecf873 | ||
|
|
f557e9f965 | ||
|
|
7ffef849d2 | ||
|
|
448a9846c9 | ||
|
|
3188f356eb | ||
|
|
e7868868c4 | ||
|
|
208b6e73dc | ||
|
|
6993cba55a | ||
|
|
e03abc1a64 | ||
|
|
777bd5e26d | ||
|
|
a6afcc944c | ||
|
|
ae0c3c5f27 | ||
|
|
bb4fdc5b7f | ||
|
|
dfa6d6da51 | ||
|
|
81b867fa20 | ||
|
|
3aa4b8a410 | ||
|
|
f0977b48e5 | ||
|
|
baccf7e3ad | ||
|
|
97764866f2 | ||
|
|
c89926399b | ||
|
|
a38b4e063b | ||
|
|
4c22a098c1 | ||
|
|
18aa573a16 | ||
|
|
d61ade4482 | ||
|
|
920b92c096 | ||
|
|
10a2084163 | ||
|
|
e6d78f3e22 | ||
|
|
cdd5fc749c | ||
|
|
f6ec647eb6 | ||
|
|
4a73a5a6b3 | ||
|
|
286ed78436 | ||
|
|
4393523929 | ||
|
|
d9abaa2f06 | ||
|
|
88e4c26b8f | ||
|
|
f20cfb53a6 | ||
|
|
82b5ff620d | ||
|
|
44f839e104 | ||
|
|
3bbcd2a20d | ||
|
|
d0b3b27975 | ||
|
|
7345dd8076 | ||
|
|
2e57f84657 | ||
|
|
58e0f50c48 | ||
|
|
910c0e0eab | ||
|
|
709aec83e2 | ||
|
|
db94f5b405 | ||
|
|
4142d5d28a | ||
|
|
b8b4fe7a8a | ||
|
|
d5aef6fb87 | ||
|
|
dd144cc9bc | ||
|
|
7eef7f6cfe | ||
|
|
6332bfc6f3 | ||
|
|
b2d91ba4c9 | ||
|
|
53b0bbd936 | ||
|
|
3748ab77d2 | ||
|
|
8931f4e271 | ||
|
|
10b0798a30 | ||
|
|
67f6dfc2f4 | ||
|
|
fc381da21b | ||
|
|
98eef1eb12 | ||
|
|
72c3191c02 | ||
|
|
ad5f36f85e | ||
|
|
6dfab75f08 | ||
|
|
e176772512 | ||
|
|
487b7480af | ||
|
|
5d2ef3a9d3 | ||
|
|
7b68642fa3 | ||
|
|
abf47274a1 | ||
|
|
3abf38ab93 | ||
|
|
9ed370693d | ||
|
|
964ea904a1 | ||
|
|
1a54aadc19 | ||
|
|
7872a6a442 | ||
|
|
9dfdc8195d | ||
|
|
77055991af | ||
|
|
ec9d00c597 | ||
|
|
a18c00ee95 | ||
|
|
713fd66da6 | ||
|
|
ea09a18956 | ||
|
|
c5b6ca53fa | ||
|
|
14d04604cb | ||
|
|
1c143f3b23 | ||
|
|
bac829b425 | ||
|
|
7185f6cedf | ||
|
|
8386951511 | ||
|
|
b9e88527dd | ||
|
|
aeacd80bcb | ||
|
|
653711fa96 | ||
|
|
463de8d7e7 | ||
|
|
4e43223f3a | ||
|
|
8393ae2851 | ||
|
|
fdf18cf533 | ||
|
|
5ee8c1e779 | ||
|
|
2955f93573 | ||
|
|
bc8c5e581c | ||
|
|
ad4259625c | ||
|
|
246c828d7a | ||
|
|
3d55fc09f7 | ||
|
|
1bb77e1d4b | ||
|
|
3d9d17d9b9 | ||
|
|
5c58dfe1ae | ||
|
|
2678514077 | ||
|
|
ee71f4a1c8 | ||
|
|
62506a26a1 | ||
|
|
61dc0a046d | ||
|
|
c817d1ae4b | ||
|
|
ecfda6de15 | ||
|
|
2f8a69b774 | ||
|
|
61af5fe226 | ||
|
|
fd4407a798 | ||
|
|
4eef254688 | ||
|
|
d5c2d25c74 | ||
|
|
0700c96901 | ||
|
|
9b9a20b437 | ||
|
|
f14a9e3ba1 | ||
|
|
cb02a7c15e | ||
|
|
a8e06c6cc6 | ||
|
|
176855b680 | ||
|
|
3aa01aaa18 | ||
|
|
04d44d9bd7 | ||
|
|
762544ea6f | ||
|
|
2a289e0468 | ||
|
|
21e13b6b92 | ||
|
|
e57fb5a7c6 | ||
|
|
5a89b4f194 | ||
|
|
7a6b228d8f | ||
|
|
fbd73b0717 | ||
|
|
7a527f2ed3 | ||
|
|
e6290c3396 | ||
|
|
8acb9291fe | ||
|
|
3ded06390c | ||
|
|
936bceba5d | ||
|
|
d94294e3f6 | ||
|
|
390f08d25f | ||
|
|
f0d2b4ed2f | ||
|
|
80cd80a5cf | ||
|
|
17f1085ffb | ||
|
|
9b55a9691f | ||
|
|
13b4a3854b | ||
|
|
f6b2102e48 | ||
|
|
71189e4f2d | ||
|
|
041cef91de | ||
|
|
2a0e97c043 | ||
|
|
bcc6be0d29 | ||
|
|
b4ea82f327 | ||
|
|
48346ae805 | ||
|
|
b5dbde84c4 | ||
|
|
e69d9f4c38 | ||
|
|
de0c71cb06 | ||
|
|
8b2eddc72d | ||
|
|
cf286986e2 | ||
|
|
7d8dc2a4d4 | ||
|
|
531c7ddba3 | ||
|
|
ac0058e951 | ||
|
|
56bf277fe0 | ||
|
|
1cc999a4f9 | ||
|
|
c6b1a475e9 | ||
|
|
8d76e16220 | ||
|
|
995d53df3e | ||
|
|
282421deb8 | ||
|
|
eebf7871cb | ||
|
|
9d46cee07a | ||
|
|
78724e981c |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
vendor
|
||||
26
.editorconfig
Normal file
26
.editorconfig
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
root = true
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.php]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.blade.php]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.stub]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json, .travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
7
.eslintignore
Normal file
7
.eslintignore
Normal file
@@ -0,0 +1,7 @@
|
||||
.travis/*
|
||||
.idea/*
|
||||
.vscode/*
|
||||
node_modules/*
|
||||
public/*
|
||||
gulpfile.js
|
||||
webpack.mix.js
|
||||
28
.eslintrc
Normal file
28
.eslintrc
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"rules": {
|
||||
"camelcase": 0,
|
||||
"no-console": 0,
|
||||
"func-names": 0,
|
||||
"prefer-object-spread": 0,
|
||||
"no-param-reassign": [
|
||||
2,
|
||||
{
|
||||
"props": false
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is. Please upload the Laravel logs as well from `storage/logs/laravel.log` (or the file with the correct date)
|
||||
|
||||
**Version**
|
||||
Please enter the version
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context and attach logs (from `storage/logs/laravel-<date>.log`)
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
10
.github/stale.yml
vendored
Normal file
10
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
daysUntilStale: 60
|
||||
daysUntilClose: false
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
exemptMilestones: true
|
||||
staleLabel: wontfix
|
||||
markComment: false
|
||||
closeComment: false
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,9 +1,12 @@
|
||||
_ide_helper.php
|
||||
.php_cs.cache
|
||||
.phpstorm.meta.php
|
||||
.phpunit.result.cache
|
||||
/vendor
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
|
||||
composer.phar
|
||||
yarn-error.log
|
||||
*.bak
|
||||
|
||||
# Laravel 4 specific
|
||||
|
||||
15
.htaccess
15
.htaccess
@@ -4,8 +4,8 @@ Options -Indexes
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} ^(.*)
|
||||
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Deny all these files/folders
|
||||
RedirectMatch 403 ^/.git/.*?$
|
||||
@@ -20,6 +20,7 @@ RedirectMatch 403 ^/storage/.*?$
|
||||
RedirectMatch 403 ^/tests/.*?$
|
||||
RedirectMatch 403 ^/vendor/.*?$
|
||||
RedirectMatch 403 ^/.bowerrc$
|
||||
RedirectMatch 403 ^/.env
|
||||
RedirectMatch 403 ^/artisan$
|
||||
RedirectMatch 403 ^/composer.json
|
||||
RedirectMatch 403 ^/composer.lock
|
||||
@@ -32,12 +33,6 @@ RedirectMatch 403 ^/package.json
|
||||
RedirectMatch 403 ^/package-lock.json
|
||||
RedirectMatch 403 ^/phpunit.xml
|
||||
RedirectMatch 403 ^/webpack.mix.js
|
||||
RedirectMatch 403 ^/yarn.lock
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)/$ /$1 [L,R=301]
|
||||
|
||||
# Handle Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
RewriteRule ^(.*)$ public/$1 [L]
|
||||
|
||||
37
.php_cs
Normal file
37
.php_cs
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in('app')
|
||||
->in('config');
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setHideProgress(true)
|
||||
->setUsingCache(false)
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'strict_param' => true,
|
||||
'no_php4_constructor' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
'no_superfluous_elseif' => true,
|
||||
'single_line_comment_style' => false,
|
||||
'simple_to_complex_string_variable' => true,
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'binary_operator_spaces' => [
|
||||
'align_double_arrow' => true,
|
||||
],
|
||||
/*
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'declare',
|
||||
'for',
|
||||
'return',
|
||||
'throw',
|
||||
'try',
|
||||
],
|
||||
],
|
||||
*/
|
||||
])
|
||||
->setFinder($finder);
|
||||
30
.styleci.yml
Normal file
30
.styleci.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
preset: recommended
|
||||
risky: true
|
||||
enabled:
|
||||
- align_double_arrow_minimal
|
||||
# - align_equals_minimal
|
||||
# - date_time_immutable
|
||||
- ereg_to_preg
|
||||
- function_to_constant
|
||||
# - mb_str_functions
|
||||
- modernize_types_casting
|
||||
# - native_function_invocation
|
||||
- no_blank_lines_after_return
|
||||
- no_homoglyph_names
|
||||
- no_php4_constructor
|
||||
- no_useless_else
|
||||
- phpdoc_add_missing_param_annotation
|
||||
disabled:
|
||||
- align_double_arrow
|
||||
- blank_line_before_return
|
||||
# - hash_to_slash_comment
|
||||
- phpdoc_summary
|
||||
- phpdoc_var_without_name
|
||||
# - unalign_equals
|
||||
finder:
|
||||
exclude:
|
||||
- node_modules
|
||||
- storage
|
||||
- vendor
|
||||
name: "*.php"
|
||||
not-name: "*.blade.php"
|
||||
138
.travis.yml
138
.travis.yml
@@ -1,58 +1,160 @@
|
||||
#
|
||||
# Travis CI config file
|
||||
#
|
||||
|
||||
language: php
|
||||
php:
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
#- '7.2'
|
||||
#- nightly
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '7.4'
|
||||
|
||||
env:
|
||||
- DB=mysql
|
||||
- DB=mariadb
|
||||
|
||||
cache:
|
||||
# Cache lives for 10 min
|
||||
# Default of 3m might not be long enough for all the runs
|
||||
timeout: 600
|
||||
directories:
|
||||
- "$HOME/.composer/cache"
|
||||
- "$HOME/.npm"
|
||||
|
||||
services:
|
||||
- mysql
|
||||
#- redis-server
|
||||
|
||||
addons:
|
||||
mariadb: '10.2'
|
||||
|
||||
install:
|
||||
- php --version
|
||||
- mysql --version
|
||||
- composer install --dev --no-interaction --verbose
|
||||
- cp .travis/env.travis.php env.php
|
||||
- cp .travis/phpunit.travis.xml phpunit.xml
|
||||
|
||||
before_script:
|
||||
- cp .travis/env.travis.php env.php
|
||||
- composer install --no-interaction --verbose
|
||||
- php artisan database:create --reset
|
||||
- php artisan migrate:refresh --seed
|
||||
|
||||
script:
|
||||
- php artisan database:create --reset
|
||||
- php artisan migrate:refresh --seed
|
||||
- cp .travis/phpunit.travis.xml phpunit.xml
|
||||
- vendor/bin/phpunit --debug --verbose
|
||||
- vendor/bin/php-cs-fixer fix --config=.php_cs -v --dry-run --diff --using-cache=no
|
||||
- vendor/bin/phpunit --debug --verbose
|
||||
|
||||
after_failure:
|
||||
- cat storage/logs/*.log
|
||||
- cat storage/logs/*.log
|
||||
|
||||
# Refer to: https://github.com/doctrine/dbal/blob/master/.travis.yml#L39
|
||||
jobs:
|
||||
include:
|
||||
# Different test stages
|
||||
# - stage: Test
|
||||
# name: PHP 7.2 + MySQL 5.7
|
||||
# php: 7.2
|
||||
# env: DB=mysql
|
||||
# services:
|
||||
# - mysql
|
||||
# - stage: Test
|
||||
# name: PHP 7.3 + MySQL 5.7
|
||||
# php: 7.3
|
||||
# env: DB=mysql
|
||||
# services:
|
||||
# - mysql
|
||||
# - stage: Test
|
||||
# name: PHP 7.4 + MySQL 5.7
|
||||
# php: 7.4
|
||||
# env: DB=mysql
|
||||
# services:
|
||||
# - mysql
|
||||
# - stage: Test
|
||||
# name: PHP 7.2 + MariaDB 10.1
|
||||
# php: 7.2
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.1'
|
||||
# - stage: Test
|
||||
# name: PHP 7.3 + MariaDB 10.1
|
||||
# php: 7.3
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.1'
|
||||
# - stage: Test
|
||||
# name: PHP 7.4 + MariaDB 10.1
|
||||
# php: 7.4
|
||||
# env: DB=mariadb MARIADB_VERSION=10.1
|
||||
# addons:
|
||||
# mariadb: '10.1'
|
||||
# - stage: Test
|
||||
# name: PHP 7.2 + MariaDB 10.2
|
||||
# php: 7.2
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.2'
|
||||
# - stage: Test
|
||||
# name: PHP 7.3 + MariaDB 10.3
|
||||
# php: 7.3
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.2'
|
||||
# - stage: Test
|
||||
# name: PHP 7.4 + MariaDB 10.2
|
||||
# php: 7.4
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.2'
|
||||
# - stage: Test
|
||||
# name: PHP 7.2 + MariaDB 10.3
|
||||
# php: 7.2
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.3'
|
||||
# - stage: Test
|
||||
# name: PHP 7.3 + MariaDB 10.3
|
||||
# php: 7.3
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.3'
|
||||
# - stage: Test
|
||||
# name: PHP 7.4 + MariaDB 10.3
|
||||
# php: 7.4
|
||||
# env: DB=mariadb
|
||||
# addons:
|
||||
# mariadb: '10.3'
|
||||
|
||||
# Just packages up a release
|
||||
- stage: package
|
||||
script: skip
|
||||
before_deploy:
|
||||
- curl -sL https://raw.githubusercontent.com/travis-ci/artifacts/master/install | bash
|
||||
- curl -sL https://raw.githubusercontent.com/travis-ci/artifacts/6b10798/install | bash
|
||||
|
||||
# Configure the conditional deployment
|
||||
# https://docs.travis-ci.com/user/deployment/#examples-of-conditional-deployment
|
||||
deploy:
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: ./.travis/deploy_script.sh
|
||||
on:
|
||||
all_branches: true
|
||||
php: '7.0'
|
||||
repo: nabeelio/phpvms
|
||||
php: '7.2'
|
||||
tags: false
|
||||
|
||||
# RELEASE STAGE
|
||||
# Only runs when there's a tag applied to this release (tag should be the version)
|
||||
# This uses Github Releases and posts it there (provider: releases)
|
||||
# https://docs.travis-ci.com/user/deployment/releases
|
||||
- stage: release
|
||||
script: skip
|
||||
before_deploy:
|
||||
- curl -sL https://raw.githubusercontent.com/travis-ci/artifacts/master/install | bash
|
||||
- curl -sL https://raw.githubusercontent.com/travis-ci/artifacts/6b10798/install | bash
|
||||
- ./.travis/deploy_script.sh
|
||||
deploy:
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: kAOYEThsSF8wM7vx+e+xWKhlvsNzhgKn1bk0zLBb7RLUM5pHIGKV/j0KrCNspwIUEPF0O594H6hCyswlpIZfxW2mTnmPqfbKxG/H2rLEAoOV0/MqzeC/gffxm7Eop6Sn4T/UC9kLSgqRynllbYtJDK6aWESdnvK3Fka0Cnpn7l/2phEf2J/nOF6QT/utpws1E0MUGqrKvX1/UYIu8np5e5aYLPOXnqahK8qzJFL4CyNBv+fhXuXfmOF4UbNbSPnrg/kY0QpUtFpz9ebvg5BjfMXJT0P4Q1BjgKBN76A7vz+ZfPmW6SqKv3o1yisXAgBWzylXh8B6pK+cUk4uXbagcGcIdkGOI6pQ5sLq+JOkBhVjSfogERePkt44KPif4EMsLRw/Jp4pTMy/vmgrON/jkbA+jXsOARTG5vAwIq4lyZzZXWUfirYwXeCfasgf+xTdo9C0cOE0jlqojO7SdF2CinDk9BduYpBTectea8Xx+YP5R1JCZNORDYynlLHKMW/8PJyAG+AsbcfKNTobQAfxw1nHa7GoKP1j4MSx1UtbulZdhmeRX/nUTFIvfgEDrl4cdBlt0/o5SuyN92DiCnvJZaYHcgXwYMvoqdXxBCnBKsM/1BZcykWi7Zt/q8krWYCOfCzBN4TDdmrKsEOUkCSOL9mI6gERHGmcGZN05PxU950=
|
||||
api_key: $GITHUB_TOKEN
|
||||
file_glob: true
|
||||
file: build/*
|
||||
on:
|
||||
tags: true
|
||||
repo: nabeelio/phpvms
|
||||
php: '7.0'
|
||||
php: '7.2'
|
||||
|
||||
27
.travis/Formatting.xml
Normal file
27
.travis/Formatting.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<code_scheme name="PHPVMS" version="173">
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
|
||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||
<option name="ALIGN_CLASS_CONSTANTS" value="true" />
|
||||
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
@@ -2,66 +2,131 @@
|
||||
|
||||
if [ "$TRAVIS" = "true" ]; then
|
||||
|
||||
cd $TRAVIS_BUILD_DIR
|
||||
cd $TRAVIS_BUILD_DIR
|
||||
|
||||
if test "$TRAVIS_TAG"; then
|
||||
PKG_NAME=$TRAVIS_TAG
|
||||
else
|
||||
echo "On branch $TRAVIS_BRANCH"
|
||||
if test "$TRAVIS_TAG"; then
|
||||
PKG_NAME=$TRAVIS_TAG
|
||||
VERSION=$TRAVIS_TAG
|
||||
|
||||
if [ "$TRAVIS_BRANCH" != "master" ] && [ "$TRAVIS_BRANCH" != "dev" ]; then
|
||||
echo "Not on valid branch, exiting"
|
||||
exit 0;
|
||||
fi;
|
||||
# Pass in the tag as the version to write out
|
||||
php artisan phpvms:version --write $VERSION
|
||||
else
|
||||
echo "On branch $TRAVIS_BRANCH"
|
||||
|
||||
BASE_VERSION=`php artisan phpvms:version --base-only`
|
||||
PKG_NAME=${BASE_VERSION}-${TRAVIS_BRANCH}
|
||||
if [ "$TRAVIS_BRANCH" != "master" ] && [ "$TRAVIS_BRANCH" != "dev" ]; then
|
||||
echo "Not on valid branch, exiting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
FILE_NAME="phpvms-$PKG_NAME"
|
||||
TAR_NAME="$FILE_NAME.tar.gz"
|
||||
echo "Writing $TAR_NAME"
|
||||
# Write the version out but place the branch ID in there
|
||||
# This is only for the dev branch
|
||||
BASE_VERSION=$(php artisan phpvms:version --base-only)
|
||||
|
||||
php artisan phpvms:version --write > VERSION
|
||||
VERSION=`cat VERSION`
|
||||
echo "Version: $VERSION"
|
||||
# This now includes the pre-release version, so "-dev" by default
|
||||
PKG_NAME=${BASE_VERSION}
|
||||
|
||||
echo "Cleaning files"
|
||||
# Don't pass in a version here, just write out the latest hash
|
||||
php artisan phpvms:version --write >VERSION
|
||||
VERSION=$(cat VERSION)
|
||||
fi
|
||||
|
||||
make clean
|
||||
echo "Version: $VERSION"
|
||||
echo "Package name: $TAR_NAME"
|
||||
|
||||
rm -rf env.php config.php
|
||||
find ./vendor -type d -name ".git" -print0 | xargs rm -rf
|
||||
find . -type d -name "sass-cache" -print0 | xargs rm -rf
|
||||
FILE_NAME="phpvms-$PKG_NAME"
|
||||
TAR_NAME="$FILE_NAME.tar.gz"
|
||||
|
||||
# clear any app specific stuff that might have been loaded in
|
||||
find storage/app/public -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/app -mindepth 1 -not -name '.gitignore' -not -name public -print0 -exec rm -rf {} +
|
||||
echo "Cleaning files"
|
||||
|
||||
# Remove any development files
|
||||
rm -rf .sass-cache
|
||||
rm -rf .idea phpvms.iml .travis .dpl
|
||||
rm -rf .phpstorm.meta.php _ide_helper.php phpunit.xml Procfile
|
||||
rm -rf vendor
|
||||
composer install --no-dev --prefer-dist --no-interaction --verbose
|
||||
|
||||
# remove large sized files
|
||||
rm -rf .git
|
||||
rm -rf node_modules
|
||||
rm -rf composer.phar
|
||||
# Leftover individual files to delete
|
||||
declare -a remove_files=(
|
||||
.git
|
||||
.github
|
||||
.sass-cache
|
||||
.idea
|
||||
.travis
|
||||
docker
|
||||
_ide_helper.php
|
||||
.dockerignore
|
||||
.dpl
|
||||
.editorconfig
|
||||
.eslintignore
|
||||
.eslintrc
|
||||
.php_cs
|
||||
.php_cs.cache
|
||||
.phpstorm.meta.php
|
||||
.styleci.yml
|
||||
.phpunit.result.cache
|
||||
env.php
|
||||
intellij_style.xml
|
||||
config.php
|
||||
docker-compose.yml
|
||||
Makefile
|
||||
phpcs.xml
|
||||
phpunit.xml
|
||||
phpvms.iml
|
||||
Procfile
|
||||
phpstan.neon
|
||||
node_modules
|
||||
composer.phar
|
||||
vendor/willdurand/geocoder/tests
|
||||
)
|
||||
|
||||
# delete files in vendor that are rather large
|
||||
rm -rf vendor/willdurand/geocoder/tests
|
||||
for file in "${remove_files[@]}"; do
|
||||
rm -rf $file
|
||||
done
|
||||
|
||||
echo "creating tarball"
|
||||
cd /tmp
|
||||
tar -czf $TAR_NAME -C $TRAVIS_BUILD_DIR/../ phpvms
|
||||
sha256sum $TAR_NAME > "$TAR_NAME.sha256"
|
||||
find ./vendor -type d -name ".git" -print0 | xargs rm -rf
|
||||
find . -type d -name "sass-cache" -print0 | xargs rm -rf
|
||||
|
||||
echo "uploading to s3"
|
||||
mkdir -p $TRAVIS_BUILD_DIR/build
|
||||
cd $TRAVIS_BUILD_DIR/build
|
||||
# clear any app specific stuff that might have been loaded in
|
||||
find bootstrap/cache -mindepth 1 -maxdepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/app -mindepth 1 -maxdepth 1 -not -name '.gitignore' -not -name public -not -name import -print0 -exec rm -rf {} +
|
||||
find storage/app/public -mindepth 1 -maxdepth 1 -not -name '.gitignore' -not -name avatars -not -name uploads -print0 -exec rm -rf {} +
|
||||
find storage/app/public/avatars -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/app/public/uploads -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/debugbar -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/docker -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/framework/cache -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/framework/sessions -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/framework/views -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
find storage/logs -mindepth 1 -not -name '.gitignore' -print0 -exec rm -rf {} +
|
||||
|
||||
mv "/tmp/$TAR_NAME" "/tmp/$TAR_NAME.sha256" .
|
||||
artifacts upload --target-paths "/" $TAR_NAME $TRAVIS_BUILD_DIR/VERSION $TAR_NAME.sha256
|
||||
mkdir -p storage/app/public/avatars
|
||||
mkdir -p storage/app/public/uploads
|
||||
mkdir -p storage/framework/cache
|
||||
mkdir -p storage/framework/sessions
|
||||
mkdir -p storage/framework/views
|
||||
|
||||
curl -X POST --data "{\"content\": \"A new build is available at http://downloads.phpvms.net/$TAR_NAME ($VERSION)\"}" -H "Content-Type: application/json" $DISCORD_WEBHOOK_URL
|
||||
# Regenerate the autoloader and classes
|
||||
composer dump-autoload
|
||||
make clean
|
||||
|
||||
cd /tmp
|
||||
tar -czf $TAR_NAME -C $TRAVIS_BUILD_DIR/../ phpvms
|
||||
sha256sum $TAR_NAME >"$TAR_NAME.sha256"
|
||||
|
||||
echo "Uploading to S3"
|
||||
mkdir -p $TRAVIS_BUILD_DIR/build
|
||||
cd $TRAVIS_BUILD_DIR/build
|
||||
|
||||
mv "/tmp/$TAR_NAME" "/tmp/$TAR_NAME.sha256" .
|
||||
artifacts upload --target-paths "/" $TAR_NAME $TRAVIS_BUILD_DIR/VERSION $TAR_NAME.sha256
|
||||
|
||||
# Upload the version for a tagged release. Move to a version file in different
|
||||
# tags. Within phpVMS, we have an option of which version to track in the admin
|
||||
if test "$TRAVIS_TAG"; then
|
||||
echo "Uploading release version file"
|
||||
cp "$TRAVIS_BUILD_DIR/VERSION" release_version
|
||||
artifacts upload --target-paths "/" release_version
|
||||
else
|
||||
echo "Uploading ${TRAVIS_BRANCH}_version file"
|
||||
cp $TRAVIS_BUILD_DIR/VERSION ${TRAVIS_BRANCH}_version
|
||||
artifacts upload --target-paths "/" ${TRAVIS_BRANCH}_version
|
||||
fi
|
||||
|
||||
curl -X POST --data "{\"content\": \"A new build is available at http://downloads.phpvms.net/$TAR_NAME ($VERSION)\"}" -H "Content-Type: application/json" $DISCORD_WEBHOOK_URL
|
||||
fi
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
APP_ENV=prod
|
||||
APP_KEY=base64:ve66Z5Kt/zTN3p++0zOPu854PHfZkwJE5VuoFAlzHtI=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_URL=http://localhost
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=phpvms
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
CACHE_DRIVER=array
|
||||
@@ -2,29 +2,28 @@
|
||||
exit();
|
||||
?>
|
||||
|
||||
APP_ENV=dev
|
||||
APP_KEY=base64:zdgcDqu9PM8uGWCtMxd74ZqdGJIrnw812oRMmwDF6KY=
|
||||
APP_URL=http://localhost
|
||||
APP_SKIN=default
|
||||
APP_DEBUG=true
|
||||
APP_LOCALE=en
|
||||
APP_ENV="dev"
|
||||
APP_KEY="base64:zdgcDqu9PM8uGWCtMxd74ZqdGJIrnw812oRMmwDF6KY="
|
||||
APP_URL="http://localhost"
|
||||
APP_SKIN="default"
|
||||
APP_DEBUG="true"
|
||||
APP_LOCALE="en"
|
||||
|
||||
PHPVMS_INSTALLED=true
|
||||
VACENTRAL_API_KEY=
|
||||
PHPVMS_INSTALLED="true"
|
||||
|
||||
APP_LOG=daily
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_LOG_MAX_FILES=3
|
||||
APP_LOG="daily"
|
||||
APP_LOG_LEVEL="debug"
|
||||
APP_LOG_MAX_FILES="3"
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=phpvms
|
||||
DB_USERNAME=root
|
||||
DB_CONNECTION="mysql"
|
||||
DB_HOST="127.0.0.1"
|
||||
DB_PORT="3306"
|
||||
DB_DATABASE="phpvms"
|
||||
DB_USERNAME="root"
|
||||
DB_PASSWORD=
|
||||
|
||||
CACHE_DRIVER=file
|
||||
CACHE_DRIVER="file"
|
||||
CACHE_PREFIX=
|
||||
|
||||
SESSION_DRIVER=file
|
||||
QUEUE_DRIVER=database
|
||||
SESSION_DRIVER="file"
|
||||
QUEUE_DRIVER="database"
|
||||
|
||||
@@ -13,14 +13,33 @@
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<extensions>
|
||||
<extension class="Tests\Bootstrap"/>
|
||||
</extensions>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./app</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<listeners>
|
||||
<listener class="NunoMaduro\Collision\Adapters\Phpunit\Listener"/>
|
||||
</listeners>
|
||||
<php>
|
||||
<ini name="error_reporting" value="E_ALL"/>
|
||||
<ini name="display_errors" value="On"/>
|
||||
<ini name="display_startup_errors" value="On"/>
|
||||
<server name="APP_ENV" value="testing"/>
|
||||
<server name="APP_KEY" value="base64:ve66Z5Kt/zTN3p++0zOPu854PHfZkwJE5VuoFAlzHtI="/>
|
||||
<server name="APP_DEBUG" value="true"/>
|
||||
<server name="APP_LOG_LEVEL" value="debug"/>
|
||||
<server name="DB_CONNECTION" value="memory"/>
|
||||
<server name="CACHE_DRIVER" value="array"/>
|
||||
<server name="SESSION_DRIVER" value="array"/>
|
||||
<server name="QUEUE_DRIVER" value="sync"/>
|
||||
<server name="APP_CONFIG_CACHE" value="bootstrap/cache/config.phpunit.php"/>
|
||||
<server name="APP_SERVICES_CACHE" value="bootstrap/cache/services.phpunit.php"/>
|
||||
<server name="APP_PACKAGES_CACHE" value="bootstrap/cache/packages.phpunit.php"/>
|
||||
<server name="APP_ROUTES_CACHE" value="bootstrap/cache/routes.phpunit.php"/>
|
||||
<server name="APP_EVENTS_CACHE" value="bootstrap/cache/events.phpunit.php"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
|
||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,8 +1,9 @@
|
||||
# Changelog
|
||||
## Beta 2 (7.0.0-beta.2)
|
||||
|
||||
## [Unreleased]
|
||||
- Switching to semver
|
||||
- PHP 7.2 minimum
|
||||
- Lots of fixes, view the [Github Milestone](https://github.com/nabeelio/phpvms/milestone/2?closed=1) for details
|
||||
|
||||
## 7.0.0-alpha1
|
||||
## Beta 1 (v7.0.0-beta)
|
||||
|
||||
### Added
|
||||
- Initial release
|
||||
- Initial Release
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at gm@nabs.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM php:7.4-fpm-alpine
|
||||
|
||||
WORKDIR /var/www/
|
||||
|
||||
RUN apk add gmp-dev
|
||||
RUN curl --silent --show-error https://getcomposer.org/installer | php
|
||||
|
||||
# Copy any config files in
|
||||
COPY resources/docker/php/ext-opcache.ini $PHP_INI_DIR/conf.d/
|
||||
COPY resources/docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf
|
||||
RUN ln -sf /dev/stderr /var/log/fpm-error.log
|
||||
|
||||
RUN docker-php-ext-install \
|
||||
calendar \
|
||||
pdo_mysql \
|
||||
gmp \
|
||||
opcache && \
|
||||
docker-php-ext-enable pdo_mysql opcache
|
||||
|
||||
COPY . /var/www/
|
||||
RUN php composer.phar install \
|
||||
--ignore-platform-reqs \
|
||||
--no-interaction \
|
||||
--no-plugins \
|
||||
--no-scripts \
|
||||
--prefer-dist
|
||||
|
||||
EXPOSE 9000
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2017, phpvms
|
||||
Copyright (c) 2017, phpvms - http://www.phpvms.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
26
Makefile
26
Makefile
@@ -19,7 +19,7 @@ clean:
|
||||
@php artisan view:clear
|
||||
@find bootstrap/cache -type f -not -name '.gitignore' -print0 | xargs -0 rm -rf
|
||||
|
||||
@find storage/framework/cache/ -mindepth 1 -not -name '.gitignore' -print0 | xargs -0 rm -rf
|
||||
@find storage/framework/cache/ -mindepth 1 -type f -not -name '.gitignore' -print0 | xargs -0 rm -rf
|
||||
@find storage/framework/sessions/ -mindepth 1 -type f -not -name '.gitignore' -print0 | xargs -0 rm -rf
|
||||
@find storage/framework/views/ -mindepth 1 -not -name '.gitignore' -print0 | xargs -0 rm -rf
|
||||
|
||||
@@ -29,6 +29,13 @@ clean:
|
||||
clean-routes:
|
||||
@php artisan route:clear
|
||||
|
||||
.PHONY: clear
|
||||
clear:
|
||||
@php artisan cache:clear
|
||||
@php artisan config:clear
|
||||
@php artisan route:clear
|
||||
@php artisan view:clear
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
@php $(COMPOSER) install --no-interaction
|
||||
@@ -36,8 +43,7 @@ build:
|
||||
# This is to build all the stylesheets, etc
|
||||
.PHONY: build-assets
|
||||
build-assets:
|
||||
npm update
|
||||
npm run dev
|
||||
yarn run production
|
||||
|
||||
.PHONY: install
|
||||
install: build
|
||||
@@ -60,9 +66,9 @@ reset: clean
|
||||
.PHONY: reload-db
|
||||
reload-db:
|
||||
@php artisan database:create --reset
|
||||
@php artisan migrate:refresh --seed
|
||||
@php artisan phpvms:import app/Database/seeds/sample.yml
|
||||
#php artisan phpvms:navdata
|
||||
@php artisan migrate --seed
|
||||
@echo "Done!"
|
||||
@make clean
|
||||
|
||||
.PHONY: tests
|
||||
tests: test
|
||||
@@ -72,6 +78,14 @@ test:
|
||||
#php artisan database:create --reset
|
||||
vendor/bin/phpunit --debug --verbose
|
||||
|
||||
.PHONY: phpcs
|
||||
phpcs:
|
||||
@vendor/bin/php-cs-fixer fix --config=.php_cs -v --diff --dry-run
|
||||
|
||||
#.PHONY: phpstan
|
||||
#phpstan:
|
||||
# vendor/bin/phpstan analyse -c phpstan.neon -v --level 2 app
|
||||
|
||||
.PHONY: replay-acars
|
||||
replay-acars:
|
||||
#@php artisan phpvms:replay AAL10,AAL3113,BAW172,DAL988,FIN6,MSR986 --manual
|
||||
|
||||
4
Procfile
4
Procfile
@@ -1,5 +1,5 @@
|
||||
dnsmasq: /usr/local/sbin/dnsmasq --keep-in-foreground
|
||||
#dnsmasq: /usr/local/sbin/dnsmasq --keep-in-foreground
|
||||
php-fpm: /usr/local/sbin/php-fpm --nodaemonize
|
||||
nginx: /usr/local/bin/nginx -g 'daemon off;'
|
||||
#mysql: /usr/local/bin/mysqld
|
||||
mysql: docker-compose --file ~/docker/mysql/docker-compose.yml up
|
||||
#mailhog: /usr/local/bin/mailhog
|
||||
|
||||
44
README.md
44
README.md
@@ -1,21 +1,20 @@
|
||||
# phpvms <sup>7</sup>
|
||||
|
||||
[](https://travis-ci.org/nabeelio/phpvms) [](https://www.codacy.com/app/nabeelio/phpvms?utm_source=github.com&utm_medium=referral&utm_content=nabeelio/phpvms&utm_campaign=Badge_Grade) [](https://packagist.org/packages/nabeel/phpvms) [](https://packagist.org/packages/nabeel/phpvms) [](https://packagist.org/packages/nabeel/phpvms) [](https://packagist.org/packages/nabeel/phpvms)
|
||||
[](https://travis-ci.org/nabeelio/phpvms) [](https://www.codacy.com/app/nabeelio/phpvms?utm_source=github.com&utm_medium=referral&utm_content=nabeelio/phpvms&utm_campaign=Badge_Grade) [](https://packagist.org/packages/nabeel/phpvms)  [](https://packagist.org/packages/nabeel/phpvms)
|
||||
|
||||
The next phpvms version built on the laravel framework. work in progress. If you're looking for
|
||||
the old, phpVMS classic, it's [available here](https://github.com/nabeelio/phpvms_v2).
|
||||
The next phpvms version built on the laravel framework. work in progress. The latest documentation, with installation instructions is available
|
||||
[on the phpVMS documentation](http://docs.phpvms.net/) page.
|
||||
|
||||
# installation
|
||||
|
||||
A full distribution, with all of the composer dependencies, is available at this
|
||||
[GitHub Releases](https://github.com/nabeelio/phpvms/releases) link.
|
||||
|
||||
The latest documentation, with installation instructions is available
|
||||
[on the phpVMS documentation](http://docs.phpvms.net/) page.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 7.0+, extensions:
|
||||
- PHP 7.1+, extensions:
|
||||
- cURL
|
||||
- JSON
|
||||
- mbstring
|
||||
@@ -25,11 +24,38 @@ The latest documentation, with installation instructions is available
|
||||
- Database:
|
||||
- MySQL 5.5+ (or MySQL variant, including MariaDB and Percona)
|
||||
|
||||
[View more details on requirements](http://docs.phpvms.net/basics/requirements)
|
||||
[View more details on requirements](http://docs.phpvms.net/setup/requirements)
|
||||
|
||||
## Installer
|
||||
|
||||
1. Upload to your server
|
||||
2. Visit the site, and follow the link to the installer
|
||||
1. Visit the site, and follow the link to the installer
|
||||
|
||||
[View installation details](http://docs.phpvms.net/basics/installation)
|
||||
[View installation details](http://docs.phpvms.net/setup/installation)
|
||||
|
||||
# development environment
|
||||
|
||||
A full development environment can be brought up using Docker:
|
||||
|
||||
```bash
|
||||
composer install
|
||||
yarn install
|
||||
docker-compose build
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Then go to `http://localhost`. If you're using dnsmasq, the `app` container is listening on `phpvms.test`, or you can add to your `/etc/hosts` file:
|
||||
|
||||
```
|
||||
127.0.0.1 phpvms.test
|
||||
```
|
||||
|
||||
## Building JS/CSS assets
|
||||
|
||||
Yarn is required, run:
|
||||
|
||||
```bash
|
||||
make build-assets
|
||||
```
|
||||
|
||||
This will build all of the assets according to the webpack file.
|
||||
|
||||
@@ -2,36 +2,25 @@
|
||||
|
||||
namespace App\Bootstrap;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\Config\Repository as RepositoryContract;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
|
||||
/**
|
||||
* Class LoadConfiguration
|
||||
* @package App\Bootstrap
|
||||
*
|
||||
* I'm overriding this to take advantage of the configuration caching
|
||||
* and not needing to read the files from disk every time.
|
||||
*
|
||||
* Hopefully it won't affect anything within core framework but this
|
||||
* should be ok. Will just have to be cognizant of any changes to the
|
||||
* LoadConfiguration parent class, or if the Kernel changes the boot
|
||||
* order -NS
|
||||
*/
|
||||
class LoadConfiguration extends \Illuminate\Foundation\Bootstrap\LoadConfiguration
|
||||
{
|
||||
/**
|
||||
* Load the configuration items from all of the files.
|
||||
* Load the configuration items from all of the files. This reads the config.php from
|
||||
* that's sitting in the root, and then recursively merges it with the current configs
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Config\Repository $repository
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Config\Repository $repository
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
|
||||
{
|
||||
parent::loadConfigurationFiles($app, $repository);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Read in the base config, only if it exists
|
||||
*/
|
||||
if (file_exists($app->basePath().'/config.php')) {
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class BaseCommand extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* Streaming file read
|
||||
* @param $filename
|
||||
* @return \Generator
|
||||
*/
|
||||
public function readFile($filename)
|
||||
{
|
||||
$fp = fopen($filename, 'rb');
|
||||
|
||||
while (($line = fgets($fp)) !== false) {
|
||||
$line = rtrim($line, "\r\n");
|
||||
if ($line[0] === ';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $line;
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cmd
|
||||
* @param bool $return
|
||||
* @return string
|
||||
*/
|
||||
public function runCommand($cmd, $return=false, $verbose=true)
|
||||
{
|
||||
if (\is_array($cmd)) {
|
||||
$cmd = join(' ', $cmd);
|
||||
}
|
||||
|
||||
if($verbose) {
|
||||
$this->info('Running "' . $cmd . '"');
|
||||
}
|
||||
|
||||
$val = '';
|
||||
$process = new Process($cmd);
|
||||
$process->run(function ($type, $buffer) use ($return, $val) {
|
||||
if ($return) {
|
||||
$val .= $buffer;
|
||||
} else {
|
||||
echo $buffer;
|
||||
}
|
||||
|
||||
/*if (Process::ERR === $type) {
|
||||
echo $buffer;
|
||||
} else {
|
||||
echo $buffer;
|
||||
}*/
|
||||
});
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,26 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
use App\Contracts\Command;
|
||||
use App\Facades\Utils;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class AcarsReplay extends BaseCommand
|
||||
class AcarsReplay extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:replay {files} {--manual} {--write-all} {--no-submit}';
|
||||
protected $description = 'Replay an ACARS file';
|
||||
|
||||
/**
|
||||
* API Key to post as
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiKey = 'testadminapikey';
|
||||
|
||||
/**
|
||||
* For automatic updates, how many seconds to sleep between updates
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $sleepTime = 10;
|
||||
@@ -36,7 +37,6 @@ class AcarsReplay extends BaseCommand
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
|
||||
/**
|
||||
* Return an instance of an HTTP client all ready to post
|
||||
*/
|
||||
@@ -46,148 +46,159 @@ class AcarsReplay extends BaseCommand
|
||||
|
||||
$this->httpClient = new Client([
|
||||
'base_uri' => config('app.url'),
|
||||
'headers' => [
|
||||
'headers' => [
|
||||
'Authorization' => $this->apiKey,
|
||||
]
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/*protected function getArguments()
|
||||
{
|
||||
return [
|
||||
['--files', InputOption::VALUE_OPTIONAL]
|
||||
];
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Make a request to start a PIREP
|
||||
*
|
||||
* @param \stdClass $flight
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function startPirep($flight): string
|
||||
{
|
||||
# convert the planned flight time to be completely in minutes
|
||||
$pft = Utils::hoursToMinutes($flight->planned_hrsenroute,
|
||||
$flight->planned_minenroute);
|
||||
// convert the planned flight time to be completely in minutes
|
||||
$pft = Utils::hoursToMinutes(
|
||||
$flight->planned_hrsenroute,
|
||||
$flight->planned_minenroute
|
||||
);
|
||||
|
||||
$flight_number = substr($flight->callsign, 3);
|
||||
|
||||
$response = $this->httpClient->post('/api/pireps/prefile', [
|
||||
'json' => [
|
||||
'airline_id' => 1,
|
||||
'flight_number' => $flight_number,
|
||||
'aircraft_id' => 1,
|
||||
'dpt_airport_id' => $flight->planned_depairport,
|
||||
'arr_airport_id' => $flight->planned_destairport,
|
||||
'level' => $flight->planned_altitude,
|
||||
'planned_flight_time' => $pft,
|
||||
'route' => $flight->planned_route,
|
||||
]
|
||||
'airline_id' => 1,
|
||||
'flight_number' => $flight_number,
|
||||
'aircraft_id' => 1,
|
||||
'dpt_airport_id' => $flight->planned_depairport,
|
||||
'arr_airport_id' => $flight->planned_destairport,
|
||||
'level' => $flight->planned_altitude,
|
||||
'planned_flight_time' => $pft,
|
||||
'route' => $flight->planned_route,
|
||||
],
|
||||
]);
|
||||
|
||||
$body = \json_decode($response->getBody()->getContents());
|
||||
|
||||
return $body->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the PIREP as filed
|
||||
*
|
||||
* @param $pirep_id
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function filePirep($pirep_id)
|
||||
{
|
||||
$response = $this->httpClient->post('/api/pireps/'.$pirep_id.'/file', [
|
||||
'json'=> []
|
||||
'json' => [],
|
||||
]);
|
||||
|
||||
$body = \json_decode($response->getBody()->getContents());
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pirep_id
|
||||
* @param $data
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function postUpdate($pirep_id, $data)
|
||||
{
|
||||
$uri = '/api/pireps/' . $pirep_id . '/acars/position';
|
||||
$uri = '/api/pireps/'.$pirep_id.'/acars/position';
|
||||
|
||||
$position = [
|
||||
'log' => '',
|
||||
'lat' => $data->latitude,
|
||||
'lon' => $data->longitude,
|
||||
'heading' => $data->heading,
|
||||
'altitude' => $data->altitude,
|
||||
'gs' => $data->groundspeed,
|
||||
'log' => '',
|
||||
'lat' => $data->latitude,
|
||||
'lon' => $data->longitude,
|
||||
'heading' => $data->heading,
|
||||
'altitude' => $data->altitude,
|
||||
'gs' => $data->groundspeed,
|
||||
'transponder' => $data->transponder,
|
||||
];
|
||||
|
||||
$upd = [
|
||||
'positions' => [
|
||||
$position
|
||||
]
|
||||
$position,
|
||||
],
|
||||
];
|
||||
|
||||
$this->info("Update: $data->callsign, $position[lat] x $position[lon] \t\t"
|
||||
. "hdg: $position[heading]\t\talt: $position[altitude]\t\tgs: $position[gs]");
|
||||
."hdg: $position[heading]\t\talt: $position[altitude]\t\tgs: $position[gs]");
|
||||
|
||||
$response = $this->httpClient->post($uri, [
|
||||
'json' => $upd
|
||||
'json' => $upd,
|
||||
]);
|
||||
|
||||
$body = \json_decode($response->getBody()->getContents());
|
||||
|
||||
return [
|
||||
$data->callsign,
|
||||
$position['lat'],
|
||||
$position['lon'],
|
||||
$position['heading'],
|
||||
$position['altitude'],
|
||||
$position['gs']
|
||||
$position['gs'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse this file and run the updates
|
||||
*
|
||||
* @param array $files
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function updatesFromFile(array $files)
|
||||
{
|
||||
/**
|
||||
* @var $flights Collection
|
||||
*/
|
||||
$flights = collect($files)->transform(function ($f)
|
||||
{
|
||||
$file = storage_path('/replay/' . $f . '.json');
|
||||
$flights = collect($files)->transform(function ($f) {
|
||||
$file = $f;
|
||||
if (file_exists($file)) {
|
||||
$this->info('Loading ' . $file);
|
||||
$this->info('Loading '.$file);
|
||||
$contents = file_get_contents($file);
|
||||
$contents = \json_decode($contents);
|
||||
|
||||
return collect($contents->updates);
|
||||
} else {
|
||||
$this->error($file . ' not found, skipping');
|
||||
return false;
|
||||
}
|
||||
$this->error($file.' not found, skipping');
|
||||
|
||||
return false;
|
||||
})
|
||||
# remove any of errored file entries
|
||||
// remove any of errored file entries
|
||||
->filter(function ($value, $key) {
|
||||
return $value !== false;
|
||||
});
|
||||
|
||||
$this->info('Starting playback');
|
||||
|
||||
/**
|
||||
/*
|
||||
* File the initial pirep to get a "preflight" status
|
||||
*/
|
||||
$flights->each(function ($updates, $idx)
|
||||
{
|
||||
$flights->each(function ($updates, $idx) {
|
||||
$update = $updates->first();
|
||||
$pirep_id = $this->startPirep($update);
|
||||
$this->pirepList[$update->callsign] = $pirep_id;
|
||||
$this->info('Prefiled ' . $update->callsign . ', ID: ' . $pirep_id);
|
||||
$this->info('Prefiled '.$update->callsign.', ID: '.$pirep_id);
|
||||
});
|
||||
|
||||
/**
|
||||
/*
|
||||
* Iterate through all of the flights, retrieving the updates
|
||||
* from each individual flight. Remove the update. Continue through
|
||||
* until there are no updates left, at which point we remove the flight
|
||||
@@ -202,15 +213,15 @@ class AcarsReplay extends BaseCommand
|
||||
|
||||
$this->postUpdate($pirep_id, $update);
|
||||
|
||||
# we're done and don't put the "no-submit" option
|
||||
if($updates->count() === 0 && !$this->option('no-submit')) {
|
||||
// we're done and don't put the "no-submit" option
|
||||
if ($updates->count() === 0 && !$this->option('no-submit')) {
|
||||
$this->filePirep($pirep_id);
|
||||
}
|
||||
})->filter(function ($updates, $idx) {
|
||||
return $updates->count() > 0;
|
||||
});
|
||||
|
||||
if(!$this->option('write-all')) {
|
||||
if (!$this->option('write-all')) {
|
||||
if (!$this->option('manual')) {
|
||||
sleep($this->sleepTime);
|
||||
} else {
|
||||
@@ -223,9 +234,11 @@ class AcarsReplay extends BaseCommand
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
public function handle(): void
|
||||
{
|
||||
$files = $this->argument('files');
|
||||
$manual_mode = $this->option('manual');
|
||||
@@ -233,6 +246,7 @@ class AcarsReplay extends BaseCommand
|
||||
if ($this->option('write-all')) {
|
||||
$this->info('In "dump-all" mode, just writing it all in');
|
||||
} else {
|
||||
/* @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (!$manual_mode) {
|
||||
$this->info('Going to send updates every 10s');
|
||||
} else {
|
||||
|
||||
40
app/Console/Commands/ComposerCommand.php
Normal file
40
app/Console/Commands/ComposerCommand.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class ComposerCommand extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:composer {cmd}';
|
||||
protected $description = 'Composer related tasks';
|
||||
|
||||
/**
|
||||
* Run composer update related commands
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
switch (trim($this->argument('cmd'))) {
|
||||
case 'post-update':
|
||||
$this->postUpdate();
|
||||
break;
|
||||
default:
|
||||
$this->error('Command exists');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any composer post update tasks
|
||||
*/
|
||||
protected function postUpdate(): void
|
||||
{
|
||||
if (config('app.env') === 'dev') {
|
||||
/* @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (class_exists(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class)) {
|
||||
Artisan::call('ide-helper:generate');
|
||||
Artisan::call('ide-helper:meta');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
95
app/Console/Commands/CreateConfigs.php
Normal file
95
app/Console/Commands/CreateConfigs.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App;
|
||||
use App\Contracts\Command;
|
||||
use App\Services\Installer\SeederService;
|
||||
use DatabaseSeeder;
|
||||
use Modules\Installer\Services\ConfigService;
|
||||
|
||||
/**
|
||||
* Create the config files
|
||||
*/
|
||||
class CreateConfigs extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:config {db_host} {db_name} {db_user} {db_pass}';
|
||||
protected $description = 'Create the config files';
|
||||
|
||||
private $databaseSeeder;
|
||||
private $seederSvc;
|
||||
|
||||
public function __construct(DatabaseSeeder $databaseSeeder, SeederService $seederSvc)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->databaseSeeder = $databaseSeeder;
|
||||
$this->seederSvc = $seederSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*
|
||||
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->writeConfigs();
|
||||
|
||||
// Reload the configuration
|
||||
App::boot();
|
||||
|
||||
$this->info('Recreating database');
|
||||
$this->call('database:create', [
|
||||
'--reset' => true,
|
||||
]);
|
||||
|
||||
$this->info('Running migrations');
|
||||
$this->call('migrate:fresh', [
|
||||
'--seed' => true,
|
||||
]);
|
||||
|
||||
$this->seederSvc->syncAllSeeds();
|
||||
|
||||
$this->info('Done!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite the configuration files
|
||||
*
|
||||
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
|
||||
*/
|
||||
protected function writeConfigs()
|
||||
{
|
||||
/** @var ConfigService $cfgSvc */
|
||||
$cfgSvc = app(ConfigService::class);
|
||||
|
||||
$this->info('Removing the old config files');
|
||||
|
||||
// Remove the old files
|
||||
$config_file = base_path('config.php');
|
||||
if (file_exists($config_file)) {
|
||||
unlink($config_file);
|
||||
}
|
||||
|
||||
$env_file = base_path('env.php');
|
||||
if (file_exists($env_file)) {
|
||||
unlink($env_file);
|
||||
}
|
||||
|
||||
//{name} {db_host} {db_name} {db_user} {db_pass}
|
||||
|
||||
$this->info('Regenerating the config files');
|
||||
$cfgSvc->createConfigFiles([
|
||||
'APP_ENV' => 'dev',
|
||||
'SITE_NAME' => $this->argument('name'),
|
||||
'DB_CONN' => 'mysql',
|
||||
'DB_HOST' => $this->argument('db_host'),
|
||||
'DB_NAME' => $this->argument('db_name'),
|
||||
'DB_USER' => $this->argument('db_user'),
|
||||
'DB_PASS' => $this->argument('db_pass'),
|
||||
]);
|
||||
|
||||
$this->info('Config files generated!');
|
||||
}
|
||||
}
|
||||
@@ -2,49 +2,56 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Log;
|
||||
use App\Console\Services\Database;
|
||||
use App\Contracts\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Tivie\OS\Detector;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
|
||||
class CreateDatabase extends BaseCommand
|
||||
class CreateDatabase extends Command
|
||||
{
|
||||
protected $signature = 'database:create {--reset} {--conn=?}';
|
||||
protected $signature = 'database:create {--reset} {--migrate} {--conn=?}';
|
||||
protected $description = 'Create a database';
|
||||
protected $os;
|
||||
|
||||
/**
|
||||
* CreateDatabase constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->os = new \Tivie\OS\Detector();
|
||||
$this->os = new Detector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the mysql database
|
||||
*
|
||||
* @param $dbkey
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function create_mysql($dbkey)
|
||||
{
|
||||
$host = config($dbkey . 'host');
|
||||
$port = config($dbkey . 'port');
|
||||
$name = config($dbkey . 'database');
|
||||
$user = config($dbkey . 'username');
|
||||
$pass = config($dbkey . 'password');
|
||||
|
||||
$dbSvc = new \App\Console\Services\Database();
|
||||
$host = config($dbkey.'host');
|
||||
$port = config($dbkey.'port');
|
||||
$name = config($dbkey.'database');
|
||||
$user = config($dbkey.'username');
|
||||
$pass = config($dbkey.'password');
|
||||
|
||||
$dbSvc = new Database();
|
||||
$dsn = $dbSvc->createDsn($host, $port);
|
||||
Log::info('Connection string: ' . $dsn);
|
||||
Log::info('Connection string: '.$dsn);
|
||||
|
||||
try {
|
||||
$conn = $dbSvc->createPDO($dsn, $user, $pass);
|
||||
} catch (\PDOException $e) {
|
||||
Log::error($e);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->option('reset') === true) {
|
||||
$sql = "DROP DATABASE IF EXISTS `$name`";
|
||||
|
||||
try {
|
||||
Log::info('Dropping database: '.$sql);
|
||||
$conn->exec($sql);
|
||||
@@ -60,12 +67,14 @@ class CreateDatabase extends BaseCommand
|
||||
$conn->exec($sql);
|
||||
} catch (\PDOException $e) {
|
||||
Log::error($e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the sqlite database
|
||||
*
|
||||
* @param $dbkey
|
||||
*/
|
||||
protected function create_sqlite($dbkey)
|
||||
@@ -76,14 +85,14 @@ class CreateDatabase extends BaseCommand
|
||||
}
|
||||
|
||||
if ($this->option('reset') === true) {
|
||||
$cmd = ['rm', '-rf', config($dbkey . 'database')];
|
||||
$cmd = ['rm', '-rf', config($dbkey.'database')];
|
||||
$this->runCommand($cmd);
|
||||
}
|
||||
|
||||
if (!file_exists(config($dbkey . 'database'))) {
|
||||
if (!file_exists(config($dbkey.'database'))) {
|
||||
$cmd = [
|
||||
$exec,
|
||||
config($dbkey . 'database'),
|
||||
config($dbkey.'database'),
|
||||
'""',
|
||||
];
|
||||
|
||||
@@ -109,21 +118,17 @@ class CreateDatabase extends BaseCommand
|
||||
}
|
||||
}*/
|
||||
|
||||
$this->info('Using connection "' . config('database.default') . '"');
|
||||
$this->info('Using connection "'.config('database.default').'"');
|
||||
|
||||
$conn = config('database.default');
|
||||
$dbkey = 'database.connections.' . $conn . '.';
|
||||
$dbkey = 'database.connections.'.$conn.'.';
|
||||
|
||||
if (config($dbkey . 'driver') === 'mysql') {
|
||||
if (config($dbkey.'driver') === 'mysql') {
|
||||
$this->create_mysql($dbkey);
|
||||
}
|
||||
|
||||
elseif (config($dbkey . 'driver') === 'sqlite') {
|
||||
} elseif (config($dbkey.'driver') === 'sqlite') {
|
||||
$this->create_sqlite($dbkey);
|
||||
}
|
||||
|
||||
// TODO: Eventually
|
||||
elseif (config($dbkey . 'driver') === 'postgres') {
|
||||
} // TODO: Eventually
|
||||
elseif (config($dbkey.'driver') === 'postgres') {
|
||||
$this->create_postgres($dbkey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,40 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use DB;
|
||||
use PDO;
|
||||
|
||||
use App\Models\Airline;
|
||||
use App\Models\User;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
use App\Contracts\Command;
|
||||
use App\Models\Acars;
|
||||
use App\Models\Airline;
|
||||
use App\Models\Pirep;
|
||||
use App\Models\User;
|
||||
use App\Repositories\AcarsRepository;
|
||||
use App\Services\AirportService;
|
||||
use App\Services\AwardService;
|
||||
use App\Services\DatabaseService;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use PDO;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class DevCommands extends BaseCommand
|
||||
class DevCommands extends Command
|
||||
{
|
||||
protected $signature = 'phpvms {cmd}';
|
||||
protected $signature = 'phpvms {cmd} {param?}';
|
||||
protected $description = 'Developer commands';
|
||||
protected $dbSvc;
|
||||
|
||||
/**
|
||||
* DevCommands constructor.
|
||||
*
|
||||
* @param DatabaseService $dbSvc
|
||||
*/
|
||||
public function __construct(DatabaseService $dbSvc)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->dbSvc = $dbSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
@@ -30,13 +50,20 @@ class DevCommands extends BaseCommand
|
||||
}
|
||||
|
||||
$commands = [
|
||||
'clear-acars' => 'clearAcars',
|
||||
'clear-users' => 'clearUsers',
|
||||
'compile-assets' => 'compileAssets',
|
||||
'db-attrs' => 'dbAttrs',
|
||||
'clear-acars' => 'clearAcars',
|
||||
'clear-users' => 'clearUsers',
|
||||
'compile-assets' => 'compileAssets',
|
||||
'db-attrs' => 'dbAttrs',
|
||||
'list-awards' => 'listAwardClasses',
|
||||
'live-flights' => 'liveFlights',
|
||||
'manual-insert' => 'manualInsert',
|
||||
'metar' => 'getMetar',
|
||||
'recalculate-stats' => 'recalculateStats',
|
||||
'reset-install' => 'resetInstall',
|
||||
'xml-to-yaml' => 'xmlToYaml',
|
||||
];
|
||||
|
||||
if(!array_key_exists($command, $commands)) {
|
||||
if (!array_key_exists($command, $commands)) {
|
||||
$this->error('Command not found!');
|
||||
exit();
|
||||
}
|
||||
@@ -44,12 +71,29 @@ class DevCommands extends BaseCommand
|
||||
$this->{$commands[$command]}();
|
||||
}
|
||||
|
||||
/**
|
||||
* List all award classes
|
||||
*/
|
||||
protected function listAwardClasses()
|
||||
{
|
||||
$awardSvc = app(AwardService::class);
|
||||
$awards = $awardSvc->findAllAwardClasses();
|
||||
|
||||
$headers = ['Award Name', 'Class'];
|
||||
$formatted_awards = [];
|
||||
foreach ($awards as $award) {
|
||||
$formatted_awards[] = [$award->name, \get_class($award)];
|
||||
}
|
||||
|
||||
$this->table($headers, $formatted_awards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the data from the ACARS and PIREP tables
|
||||
*/
|
||||
protected function clearAcars()
|
||||
{
|
||||
if(config('database.default') === 'mysql') {
|
||||
if (config('database.default') === 'mysql') {
|
||||
DB::statement('SET foreign_key_checks=0');
|
||||
}
|
||||
|
||||
@@ -103,9 +147,154 @@ class DevCommands extends BaseCommand
|
||||
$server_version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
$emulate_prepares = version_compare($server_version, $emulate_prepares_below_version, '<');
|
||||
|
||||
$this->info('Server Version: '. $server_version);
|
||||
$this->info('Server Version: '.$server_version);
|
||||
$this->info('Emulate Prepares: '.$emulate_prepares);
|
||||
|
||||
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the sequelpro xml export to yaml
|
||||
*/
|
||||
protected function xmlToYaml()
|
||||
{
|
||||
$file = $this->argument('param');
|
||||
$this->info('Reading '.$file);
|
||||
|
||||
$xml_str = file_get_contents($file);
|
||||
$xml = new \SimpleXMLElement($xml_str);
|
||||
|
||||
$yaml = [];
|
||||
$table_name = (string) $xml->database->table_data['name'];
|
||||
$this->info('Writing table "'.$table_name.'"');
|
||||
|
||||
$count = 0;
|
||||
$yaml[$table_name] = [];
|
||||
|
||||
foreach ($xml->database->table_data->row as $row) {
|
||||
$yaml_row = [];
|
||||
foreach ($row->field as $field) {
|
||||
$fname = (string) $field['name'];
|
||||
$fvalue = (string) $field;
|
||||
|
||||
$yaml_row[$fname] = $fvalue;
|
||||
}
|
||||
|
||||
$yaml[$table_name][] = $yaml_row;
|
||||
$count++;
|
||||
}
|
||||
|
||||
$this->info('Exporting '.$count.' rows');
|
||||
|
||||
$file_name = $table_name.'.yml';
|
||||
file_put_contents(storage_path($file_name), Yaml::dump($yaml, 4, 2));
|
||||
$this->info('Writing yaml to storage: '.$file_name);
|
||||
}
|
||||
|
||||
protected function getMetar(): void
|
||||
{
|
||||
$icao = $this->argument('param');
|
||||
if (!$icao) {
|
||||
$this->error('Enter an ICAO!');
|
||||
exit();
|
||||
}
|
||||
|
||||
$airportSvc = app(AirportService::class);
|
||||
$metar = $airportSvc->getMetar($icao);
|
||||
$this->info($metar->raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the rows from the file, manually advancing each row
|
||||
*/
|
||||
protected function manualInsert(): void
|
||||
{
|
||||
$file = $this->argument('param');
|
||||
$this->info('Reading '.$file);
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$this->error('File '.$file.' doesn\'t exist');
|
||||
exit;
|
||||
}
|
||||
|
||||
$yml = Yaml::parse(file_get_contents($file));
|
||||
foreach ($yml as $table => $rows) {
|
||||
$this->info('Importing table '.$table);
|
||||
$this->info('Number of rows: '.\count($rows));
|
||||
|
||||
foreach ($rows as $row) {
|
||||
try {
|
||||
$this->dbSvc->insert_row($table, $row);
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e);
|
||||
}
|
||||
|
||||
$this->confirm('Insert next row?', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate the stats for all users
|
||||
*/
|
||||
protected function recalculateStats(): void
|
||||
{
|
||||
$userSvc = app(UserService::class);
|
||||
$userSvc->recalculateAllUserStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the tables, etc from the database, for a clean install
|
||||
*/
|
||||
protected function resetInstall(): void
|
||||
{
|
||||
$confirm = $this->ask('This will erase your entire install and database, are you sure? y/n ');
|
||||
if (strtolower($confirm) !== 'y') {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
try {
|
||||
if (config('database.default') === 'mysql') {
|
||||
DB::statement('SET foreign_key_checks=0');
|
||||
}
|
||||
|
||||
$this->info('Dropping all tables');
|
||||
$tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();
|
||||
foreach ($tables as $table) {
|
||||
Schema::dropIfExists($table);
|
||||
}
|
||||
} catch (QueryException $e) {
|
||||
$this->error('DB error: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$this->info('Deleting config file');
|
||||
|
||||
try {
|
||||
unlink('config.php');
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$this->info('Deleting env file');
|
||||
|
||||
try {
|
||||
unlink('env.php');
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$this->info('Clearing caches');
|
||||
Artisan::call('cache:clear');
|
||||
Artisan::call('route:clear');
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('view:clear');
|
||||
|
||||
$this->info('Done!');
|
||||
}
|
||||
|
||||
public function liveFlights(): void
|
||||
{
|
||||
$acarsRepo = app(AcarsRepository::class);
|
||||
$flights = $acarsRepo->getPositions(setting('acars.live_time'))->toArray();
|
||||
|
||||
dd($flights);
|
||||
}
|
||||
}
|
||||
|
||||
89
app/Console/Commands/DevInstall.php
Normal file
89
app/Console/Commands/DevInstall.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use Modules\Installer\Services\ConfigService;
|
||||
|
||||
/**
|
||||
* Create a fresh development install
|
||||
*/
|
||||
class DevInstall extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:dev-install {--reset-db} {--reset-configs}';
|
||||
protected $description = 'Run a developer install and run the sample migration';
|
||||
|
||||
private $databaseSeeder;
|
||||
|
||||
public function __construct(\DatabaseSeeder $databaseSeeder)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->databaseSeeder = $databaseSeeder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*
|
||||
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->option('reset-configs')) {
|
||||
$this->rewriteConfigs();
|
||||
}
|
||||
|
||||
// Reload the configuration
|
||||
\App::boot();
|
||||
|
||||
$this->info('Recreating database');
|
||||
$this->call('database:create', [
|
||||
'--reset' => true,
|
||||
]);
|
||||
|
||||
$this->info('Running migrations');
|
||||
$this->call('migrate:fresh', [
|
||||
'--seed' => true,
|
||||
]);
|
||||
|
||||
$this->info('Done!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite the configuration files
|
||||
*
|
||||
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
|
||||
*/
|
||||
protected function rewriteConfigs()
|
||||
{
|
||||
$cfgSvc = app(ConfigService::class);
|
||||
|
||||
$this->info('Removing the old config files');
|
||||
|
||||
// Remove the old files
|
||||
$config_file = base_path('config.php');
|
||||
if (file_exists($config_file)) {
|
||||
unlink($config_file);
|
||||
}
|
||||
|
||||
$env_file = base_path('env.php');
|
||||
if (file_exists($env_file)) {
|
||||
unlink($env_file);
|
||||
}
|
||||
|
||||
$this->info('Removing the sqlite db');
|
||||
$db_file = storage_path('db.sqlite');
|
||||
if (file_exists($db_file)) {
|
||||
unlink($db_file);
|
||||
}
|
||||
|
||||
$this->info('Regenerating the config files');
|
||||
$cfgSvc->createConfigFiles([
|
||||
'APP_ENV' => 'dev',
|
||||
'SITE_NAME' => 'phpvms test',
|
||||
'DB_CONN' => 'sqlite',
|
||||
]);
|
||||
|
||||
$this->info('Config files generated!');
|
||||
}
|
||||
}
|
||||
55
app/Console/Commands/ImportCsv.php
Normal file
55
app/Console/Commands/ImportCsv.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use App\Services\ImportService;
|
||||
|
||||
class ImportCsv extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:csv-import {type} {file}';
|
||||
protected $description = 'Import from a CSV file';
|
||||
|
||||
private $importer;
|
||||
|
||||
/**
|
||||
* Import constructor.
|
||||
*
|
||||
* @param ImportService $importer
|
||||
*/
|
||||
public function __construct(ImportService $importer)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->importer = $importer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$type = $this->argument('type');
|
||||
$file = $this->argument('file');
|
||||
|
||||
if (\in_array($type, ['flight', 'flights'], true)) {
|
||||
$status = $this->importer->importFlights($file);
|
||||
} elseif ($type === 'aircraft') {
|
||||
$status = $this->importer->importAircraft($file);
|
||||
} elseif (\in_array($type, ['airport', 'airports'], true)) {
|
||||
$status = $this->importer->importAirports($file);
|
||||
} elseif ($type === 'subfleet') {
|
||||
$status = $this->importer->importSubfleets($file);
|
||||
}
|
||||
|
||||
foreach ($status['success'] as $line) {
|
||||
$this->info($line);
|
||||
}
|
||||
|
||||
foreach ($status['errors'] as $line) {
|
||||
$this->error($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use DB;
|
||||
use App\Console\BaseCommand;
|
||||
|
||||
class Importer extends BaseCommand
|
||||
{
|
||||
protected $signature = 'phpvms:importer {db_host} {db_name} {db_user} {db_pass?} {table_prefix=phpvms_}';
|
||||
protected $description = 'Import from an older version of phpVMS';
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$db_creds = [
|
||||
'host' => $this->argument('db_host'),
|
||||
'name' => $this->argument('db_name'),
|
||||
'user' => $this->argument('db_user'),
|
||||
'pass' => $this->argument('db_pass'),
|
||||
'table_prefix' => $this->argument('table_prefix')
|
||||
];
|
||||
|
||||
$importerSvc = new \App\Console\Services\Importer($db_creds);
|
||||
$importerSvc->run();
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
|
||||
class Install extends BaseCommand
|
||||
{
|
||||
protected $signature = 'phpvms:install
|
||||
{--update}
|
||||
{--airline-name?}
|
||||
{--airline-code?}';
|
||||
|
||||
protected $description = 'Install or update phpVMS';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Installing phpVMS...');
|
||||
|
||||
$this->setupDatabase();
|
||||
|
||||
# Only run these if we're doing an initial install
|
||||
if(!$this->option('update')) {
|
||||
$this->writeLocalConfig();
|
||||
$this->initialData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the database and run the migrations
|
||||
* Only call the database creation if we're not
|
||||
* explicitly trying to upgrade
|
||||
*/
|
||||
protected function setupDatabase()
|
||||
{
|
||||
if(!$this->option('update')) {
|
||||
$this->call('database:create');
|
||||
}
|
||||
|
||||
$this->info('Running database migrations...');
|
||||
$this->call('migrate');
|
||||
|
||||
# TODO: Call initial seed data, for the groups and other supporting data
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a local config file
|
||||
*/
|
||||
protected function writeLocalConfig()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an initial airline and admin user/password
|
||||
*/
|
||||
protected function initialData()
|
||||
{
|
||||
# TODO: Prompt for initial airline info
|
||||
$airline_name = $this->option('airline-name');
|
||||
if(!$airline_name) {
|
||||
$airline_name = $this->ask('Enter your airline name');
|
||||
}
|
||||
|
||||
$airline_code = $this->option('airline-code');
|
||||
if(!$airline_code) {
|
||||
$airline_code = $this->ask('Enter your airline code');
|
||||
}
|
||||
|
||||
# TODO: Prompt for admin user/password
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,38 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
use App\Models\Navdata;
|
||||
use App\Contracts\Command;
|
||||
use App\Models\Enums\NavaidType;
|
||||
use App\Models\Navdata;
|
||||
|
||||
|
||||
class NavdataCommand extends BaseCommand
|
||||
class NavdataImport extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:navdata';
|
||||
protected $description = '';
|
||||
|
||||
/**
|
||||
* Read and parse in the navaid file
|
||||
* @throws \League\Geotools\Exception\InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function read_wp_nav_aid()
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Emptying the current navdata...');
|
||||
Navdata::query()->truncate();
|
||||
|
||||
$this->info('Looking for nav files...');
|
||||
$this->read_wp_nav_aid();
|
||||
$this->read_wp_nav_fix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse in the navaid file
|
||||
*
|
||||
* @throws \League\Geotools\Exception\InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function read_wp_nav_aid(): void
|
||||
{
|
||||
/*
|
||||
* ....,....1....,....2....,....3....,....4....,....5....,....6..
|
||||
@@ -50,7 +67,7 @@ class NavdataCommand extends BaseCommand
|
||||
$file_path = storage_path('/navdata/WPNAVAID.txt');
|
||||
if (!file_exists($file_path)) {
|
||||
$this->error('WPNAVAID.txt not found in storage/navdata');
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->info('Importing navaids (WPNAVAID.txt) ...');
|
||||
@@ -58,10 +75,9 @@ class NavdataCommand extends BaseCommand
|
||||
|
||||
$imported = 0;
|
||||
|
||||
foreach($generator as $line) {
|
||||
|
||||
foreach ($generator as $line) {
|
||||
$navaid = [
|
||||
'id' => trim(substr($line, 24, 4)), // ident column
|
||||
'id' => trim(substr($line, 24, 4)), // ident column
|
||||
'name' => trim(substr($line, 0, 24)),
|
||||
'type' => trim(substr($line, 29, 4)),
|
||||
'lat' => trim(substr($line, 33, 9)),
|
||||
@@ -70,9 +86,8 @@ class NavdataCommand extends BaseCommand
|
||||
'class' => trim($line[60]),
|
||||
];
|
||||
|
||||
# Map to the Navaid enum
|
||||
switch($navaid['type'])
|
||||
{
|
||||
// Map to the Navaid enum
|
||||
switch ($navaid['type']) {
|
||||
case 'ILS':
|
||||
$navaid['type'] = NavaidType::LOC;
|
||||
break;
|
||||
@@ -101,22 +116,22 @@ class NavdataCommand extends BaseCommand
|
||||
}*/
|
||||
|
||||
Navdata::updateOrCreate([
|
||||
'id' => $navaid['id'], 'name' => $navaid['name']
|
||||
'id' => $navaid['id'], 'name' => $navaid['name'],
|
||||
], $navaid);
|
||||
|
||||
$imported++;
|
||||
if($imported % 100 === 0) {
|
||||
$this->info('Imported ' . $imported . ' entries...');
|
||||
if ($imported % 100 === 0) {
|
||||
$this->info('Imported '.$imported.' entries...');
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported a total of ' . $imported . ' nav aids');
|
||||
$this->info('Imported a total of '.$imported.' nav aids');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function read_wp_nav_fix()
|
||||
public function read_wp_nav_fix(): void
|
||||
{
|
||||
/*
|
||||
* ....,....1....,....2....,...3....,....4....,....
|
||||
@@ -138,9 +153,9 @@ class NavdataCommand extends BaseCommand
|
||||
*/
|
||||
|
||||
$file_path = storage_path('/navdata/WPNAVFIX.txt');
|
||||
if(!file_exists($file_path)) {
|
||||
if (!file_exists($file_path)) {
|
||||
$this->error('WPNAVFIX.txt not found in storage/navdata');
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->info('Importing navaids (WPNAVFIX.txt) ...');
|
||||
@@ -149,37 +164,23 @@ class NavdataCommand extends BaseCommand
|
||||
$imported = 0;
|
||||
foreach ($generator as $line) {
|
||||
$navfix = [
|
||||
'id' => trim(substr($line, 0, 4)), // ident column
|
||||
'id' => trim(substr($line, 0, 4)), // ident column
|
||||
'name' => trim(substr($line, 24, 6)),
|
||||
'type' => NavaidType::FIX,
|
||||
'lat' => trim(substr($line, 30, 10)),
|
||||
'lon' => trim(substr($line, 40, 11)),
|
||||
'lat' => trim(substr($line, 30, 10)),
|
||||
'lon' => trim(substr($line, 40, 11)),
|
||||
];
|
||||
|
||||
switch ($navfix['type']) {
|
||||
default:
|
||||
$navfix['type'] = NavaidType::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
Navdata::updateOrCreate(['id' => $navfix['id']], $navfix);
|
||||
Navdata::updateOrCreate([
|
||||
'id' => $navfix['id'], 'name' => $navfix['name'],
|
||||
], $navfix);
|
||||
|
||||
$imported++;
|
||||
if ($imported % 100 === 0) {
|
||||
$this->info('Imported ' . $imported . ' entries...');
|
||||
$this->info('Imported '.$imported.' entries...');
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported a total of ' . $imported . ' nav fixes');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Emptying the current navdata...');
|
||||
Navdata::query()->truncate();
|
||||
|
||||
$this->info('Looking for nav files...');
|
||||
$this->read_wp_nav_aid();
|
||||
$this->read_wp_nav_fix();
|
||||
$this->info('Imported a total of '.$imported.' nav fixes');
|
||||
}
|
||||
}
|
||||
52
app/Console/Commands/PirepExport.php
Normal file
52
app/Console/Commands/PirepExport.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class PirepExport extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:pirep-export {id}';
|
||||
protected $description = 'PIREP table export';
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$pirep_id = $this->argument('id');
|
||||
if (empty($pirep_id)) {
|
||||
$this->error('No PIREP ID specified');
|
||||
exit();
|
||||
}
|
||||
|
||||
// List the tables to export and the column name for the pirep id
|
||||
$tables = [
|
||||
'pireps' => 'id',
|
||||
'acars' => 'pirep_id',
|
||||
'pirep_comments' => 'pirep_id',
|
||||
'pirep_fares' => 'pirep_id',
|
||||
'pirep_field_values' => 'pirep_id',
|
||||
'expenses' => 'ref_model_id',
|
||||
'journal_transactions' => 'ref_model_id',
|
||||
];
|
||||
|
||||
$export_tables = [];
|
||||
foreach ($tables as $table => $key) {
|
||||
$export_tables[$table] = [];
|
||||
|
||||
$rows = DB::table($table)
|
||||
->where($key, '=', $pirep_id)
|
||||
->get();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$export_tables[$table][] = (array) $row;
|
||||
}
|
||||
}
|
||||
|
||||
$yaml = Yaml::dump($export_tables, 4, 2);
|
||||
echo $yaml;
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use GuzzleHttp\Client;
|
||||
use App\Console\BaseCommand;
|
||||
|
||||
class TestApi extends BaseCommand
|
||||
class TestApi extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:test-api {apikey} {url}';
|
||||
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
@@ -17,11 +16,11 @@ class TestApi extends BaseCommand
|
||||
public function handle()
|
||||
{
|
||||
$this->httpClient = new Client([
|
||||
'headers' => [
|
||||
'Authorization' => $this->argument('apikey'),
|
||||
'Content-type' => 'application/json',
|
||||
'X-API-Key' => $this->argument('apikey'),
|
||||
]
|
||||
'headers' => [
|
||||
'Authorization' => $this->argument('apikey'),
|
||||
'Content-type' => 'application/json',
|
||||
'X-API-Key' => $this->argument('apikey'),
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $this->httpClient->get($this->argument('url'));
|
||||
|
||||
@@ -2,56 +2,63 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Console\BaseCommand;
|
||||
use App\Contracts\Command;
|
||||
use App\Services\VersionService;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Version extends BaseCommand
|
||||
class Version extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:version {--write} {--base-only}';
|
||||
protected $signature = 'phpvms:version {--write} {--base-only} {--write-full-version} {version?}';
|
||||
|
||||
/**
|
||||
* Create the version number that gets written out
|
||||
*/
|
||||
protected function createVersionNumber($cfg)
|
||||
private $versionSvc;
|
||||
|
||||
public function __construct(VersionService $versionSvc)
|
||||
{
|
||||
exec($cfg['git']['git-local'], $version);
|
||||
$version = substr($version[0], 0, $cfg['build']['length']);
|
||||
parent::__construct();
|
||||
|
||||
# prefix with the date in YYMMDD format
|
||||
$date = date('ymd');
|
||||
|
||||
$version = $date.'-'.$version;
|
||||
|
||||
return $version;
|
||||
$this->versionSvc = $versionSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*
|
||||
* @throws \Symfony\Component\Yaml\Exception\ParseException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$version_file = config_path('version.yml');
|
||||
$cfg = Yaml::parse(file_get_contents($version_file));
|
||||
if ($this->option('write')) {
|
||||
// Write the updated build number out to the file
|
||||
$version_file = config_path('version.yml');
|
||||
$cfg = Yaml::parse(file_get_contents($version_file));
|
||||
|
||||
// If a version is being passed in, the update the build, etc data against this
|
||||
if ($this->argument('version')) {
|
||||
$version = \SemVer\SemVer\Version::fromString($this->argument('version'));
|
||||
if ($this->option('write_full_version')) {
|
||||
$cfg['current']['major'] = $version->getMajor();
|
||||
$cfg['current']['minor'] = $version->getMinor();
|
||||
$cfg['current']['patch'] = $version->getPatch();
|
||||
}
|
||||
|
||||
$prerelease = $version->getPreRelease();
|
||||
if (strpos($prerelease, '.') !== false) {
|
||||
$prerelease = explode('.', $prerelease);
|
||||
$cfg['current']['prerelease'] = $prerelease[0];
|
||||
$cfg['current']['buildmetadata'] = $prerelease[1];
|
||||
} else {
|
||||
$cfg['current']['prerelease'] = $prerelease;
|
||||
}
|
||||
}
|
||||
|
||||
// Always write out the build ID/build number which is the commit hash
|
||||
$build_number = $this->versionSvc->getBuildId($cfg);
|
||||
$cfg['current']['commit'] = $build_number;
|
||||
$cfg['build']['number'] = $build_number;
|
||||
|
||||
if($this->option('write')) {
|
||||
$version = $this->createVersionNumber($cfg);
|
||||
$cfg['build']['number'] = $version;
|
||||
file_put_contents($version_file, Yaml::dump($cfg, 4, 2));
|
||||
}
|
||||
|
||||
# Only show the major.minor.patch version
|
||||
if($this->option('base-only')) {
|
||||
$version = 'v'.$cfg['current']['major'] . '.'
|
||||
.$cfg['current']['minor'] . '.'
|
||||
.$cfg['current']['patch'];
|
||||
|
||||
print $version;
|
||||
} else {
|
||||
$this->call('version:show', [
|
||||
'--format' => 'compact',
|
||||
'--suppress-app-name' => true
|
||||
]);
|
||||
}
|
||||
$version = $this->versionSvc->getCurrentVersion(!$this->option('base-only'));
|
||||
echo $version."\n";
|
||||
}
|
||||
}
|
||||
|
||||
41
app/Console/Commands/YamlExport.php
Normal file
41
app/Console/Commands/YamlExport.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use DB;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Class YamlExport
|
||||
*/
|
||||
class YamlExport extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:yaml-export {tables*}';
|
||||
protected $description = 'YAML table export';
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$tables = $this->argument('tables');
|
||||
if (empty($tables)) {
|
||||
$this->error('No tables specified');
|
||||
exit();
|
||||
}
|
||||
|
||||
$export_tables = [];
|
||||
foreach ($tables as $table) {
|
||||
$export_tables[$table] = [];
|
||||
|
||||
$rows = DB::table($table)->get();
|
||||
foreach ($rows as $row) {
|
||||
$export_tables[$table][] = (array) $row;
|
||||
}
|
||||
}
|
||||
|
||||
$yaml = Yaml::dump($export_tables, 4, 2);
|
||||
echo $yaml;
|
||||
}
|
||||
}
|
||||
@@ -2,50 +2,55 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use DB;
|
||||
use App\Console\BaseCommand;
|
||||
use App\Contracts\Command;
|
||||
use App\Services\DatabaseService;
|
||||
|
||||
class ImportCommand extends BaseCommand
|
||||
/**
|
||||
* Class YamlImport
|
||||
*/
|
||||
class YamlImport extends Command
|
||||
{
|
||||
protected $signature = 'phpvms:import {files*}';
|
||||
protected $signature = 'phpvms:yaml-import {files*}';
|
||||
protected $description = 'Developer commands';
|
||||
|
||||
protected $dbSvc;
|
||||
|
||||
/**
|
||||
* YamlImport constructor.
|
||||
*
|
||||
* @param DatabaseService $dbSvc
|
||||
*/
|
||||
public function __construct(DatabaseService $dbSvc)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->dbSvc = $dbSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run dev related commands
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$files = $this->argument('files');
|
||||
if(empty($files)) {
|
||||
if (empty($files)) {
|
||||
$this->error('No files to import specified!');
|
||||
exit();
|
||||
}
|
||||
|
||||
$ignore_errors = true;
|
||||
/*$ignore_errors = $this->option('ignore_errors');
|
||||
if(!$ignore_errors) {
|
||||
$ignore_errors = false;
|
||||
}*/
|
||||
|
||||
foreach($files as $file) {
|
||||
if(!file_exists($file)) {
|
||||
$this->error('File ' . $file .' doesn\'t exist');
|
||||
foreach ($files as $file) {
|
||||
if (!file_exists($file)) {
|
||||
$this->error('File '.$file.' doesn\'t exist');
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->info('Importing ' . $file);
|
||||
$this->info('Importing '.$file);
|
||||
|
||||
$imported = $this->dbSvc->seed_from_yaml_file($file, $ignore_errors);
|
||||
foreach($imported as $table => $count) {
|
||||
foreach ($imported as $table => $count) {
|
||||
$this->info('Imported '.$count.' records from "'.$table.'"');
|
||||
}
|
||||
}
|
||||
23
app/Console/Cron/Hourly.php
Normal file
23
app/Console/Cron/Hourly.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Cron;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use App\Events\CronHourly;
|
||||
|
||||
/**
|
||||
* This just calls the CronHourly event, so all of the
|
||||
* listeners, etc can just be called to run those tasks
|
||||
*/
|
||||
class Hourly extends Command
|
||||
{
|
||||
protected $signature = 'cron:hourly';
|
||||
protected $description = 'Run the hourly cron tasks';
|
||||
protected $schedule;
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$this->redirectLoggingToFile('cron');
|
||||
event(new CronHourly());
|
||||
}
|
||||
}
|
||||
25
app/Console/Cron/Monthly.php
Normal file
25
app/Console/Cron/Monthly.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Cron;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use App\Events\CronMonthly;
|
||||
|
||||
/**
|
||||
* This just calls the CronMonthly event, so all of the
|
||||
* listeners, etc can just be called to run those tasks
|
||||
*
|
||||
* The actual cron tasks are in app/Cron
|
||||
*/
|
||||
class Monthly extends Command
|
||||
{
|
||||
protected $signature = 'cron:monthly';
|
||||
protected $description = 'Run the monthly cron tasks';
|
||||
protected $schedule;
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$this->redirectLoggingToFile('cron');
|
||||
event(new CronMonthly());
|
||||
}
|
||||
}
|
||||
25
app/Console/Cron/Nightly.php
Normal file
25
app/Console/Cron/Nightly.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Cron;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use App\Events\CronNightly;
|
||||
|
||||
/**
|
||||
* This just calls the CronNightly event, so all of the
|
||||
* listeners, etc can just be called to run those tasks
|
||||
*
|
||||
* The actual cron tasks are in app/Cron
|
||||
*/
|
||||
class Nightly extends Command
|
||||
{
|
||||
protected $signature = 'cron:nightly';
|
||||
protected $description = 'Run the nightly cron tasks';
|
||||
protected $schedule;
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$this->redirectLoggingToFile('cron');
|
||||
event(new CronNightly());
|
||||
}
|
||||
}
|
||||
25
app/Console/Cron/Weekly.php
Normal file
25
app/Console/Cron/Weekly.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Cron;
|
||||
|
||||
use App\Contracts\Command;
|
||||
use App\Events\CronWeekly;
|
||||
|
||||
/**
|
||||
* This just calls the CronWeekly event, so all of the
|
||||
* listeners, etc can just be called to run those tasks.
|
||||
*
|
||||
* The actual cron tasks are in app/Cron
|
||||
*/
|
||||
class Weekly extends Command
|
||||
{
|
||||
protected $signature = 'cron:weekly';
|
||||
protected $description = 'Run the weekly cron tasks';
|
||||
protected $schedule;
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$this->redirectLoggingToFile('cron');
|
||||
event(new CronWeekly());
|
||||
}
|
||||
}
|
||||
@@ -2,37 +2,37 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Cron\Hourly;
|
||||
use App\Console\Cron\Monthly;
|
||||
use App\Console\Cron\Nightly;
|
||||
use App\Console\Cron\Weekly;
|
||||
use App\Services\CronService;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* The Artisan commands provided by your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
Commands\AcarsReplay::class,
|
||||
Commands\CreateDatabase::class,
|
||||
Commands\DevCommands::class,
|
||||
Commands\ImportCommand::class,
|
||||
Commands\Importer::class,
|
||||
Commands\Install::class,
|
||||
Commands\NavdataCommand::class,
|
||||
Commands\TestApi::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->command('inspire')
|
||||
// ->hourly();
|
||||
$schedule->command(Nightly::class)->dailyAt('01:00');
|
||||
$schedule->command(Weekly::class)->weeklyOn(0);
|
||||
$schedule->command(Monthly::class)->monthlyOn(1);
|
||||
$schedule->command(Hourly::class)->hourly();
|
||||
|
||||
// When spatie-backups runs
|
||||
$schedule->command('backup:clean')->daily()->at('01:00');
|
||||
$schedule->command('backup:run')->daily()->at('02:00');
|
||||
|
||||
// Update the last time the cron was run
|
||||
$cronSvc = app(CronService::class);
|
||||
$cronSvc->updateLastRunTime();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,9 +40,9 @@ class Kernel extends ConsoleKernel
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands()
|
||||
protected function commands(): void
|
||||
{
|
||||
require app_path('Routes/console.php');
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
$this->load(__DIR__.'/Commands');
|
||||
$this->load(__DIR__.'/Cron');
|
||||
}
|
||||
}
|
||||
|
||||
23
app/Console/Logger.php
Normal file
23
app/Console/Logger.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Monolog\Handler\StreamHandler;
|
||||
|
||||
/**
|
||||
* Just a simple custom logger that dumps to the console
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
public function __invoke(array $config)
|
||||
{
|
||||
$logger = new \Monolog\Logger('console');
|
||||
|
||||
try {
|
||||
$logger->pushHandler(new StreamHandler('php://stdout'));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
return $logger;
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,26 @@
|
||||
namespace App\Console\Services;
|
||||
|
||||
use PDO;
|
||||
use Doctrine\DBAL\Driver\PDOException;
|
||||
|
||||
/**
|
||||
* Class Database
|
||||
* @package App\Console\Services
|
||||
*/
|
||||
class Database
|
||||
{
|
||||
/**
|
||||
* Create the base connection DSN, optionally include the DB name
|
||||
* @param $host
|
||||
* @param $port
|
||||
*
|
||||
* @param $host
|
||||
* @param $port
|
||||
* @param null $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createDsn($host, $port, $name=null)
|
||||
public function createDsn($host, $port, $name = null)
|
||||
{
|
||||
$conn = config('database.default');
|
||||
$dsn = "$conn:host=$host;port=$port";
|
||||
if(filled($name)) {
|
||||
if (filled($name)) {
|
||||
$dsn .= ';dbname='.$name;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,10 @@ class Database
|
||||
* @param $dsn
|
||||
* @param $user
|
||||
* @param $pass
|
||||
* @return PDO
|
||||
*
|
||||
* @throws \PDOException
|
||||
*
|
||||
* @return PDO
|
||||
*/
|
||||
public function createPDO($dsn, $user, $pass)
|
||||
{
|
||||
|
||||
@@ -1,689 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Services;
|
||||
|
||||
use PDO;
|
||||
use Carbon\Carbon;
|
||||
use Doctrine\DBAL\Driver\PDOException;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
use App\Models\Enums\FlightType;
|
||||
use App\Models\Enums\PirepSource;
|
||||
use App\Models\Pirep;
|
||||
use App\Models\Aircraft;
|
||||
use App\Models\Airline;
|
||||
use App\Models\Airport;
|
||||
use App\Models\Flight;
|
||||
use App\Models\Rank;
|
||||
use App\Models\Subfleet;
|
||||
use App\Models\User;
|
||||
use App\Models\Enums\UserState;
|
||||
use App\Facades\Utils;
|
||||
|
||||
/**
|
||||
* Class Importer
|
||||
* TODO: Batch import
|
||||
* @package App\Console\Services
|
||||
*/
|
||||
class Importer
|
||||
{
|
||||
/**
|
||||
* Hold references
|
||||
*/
|
||||
private $mappedEntities = [];
|
||||
|
||||
/**
|
||||
* Hold the PDO connection to the old database
|
||||
* @var
|
||||
*/
|
||||
private $conn;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $creds = [];
|
||||
|
||||
/**
|
||||
* Hold the instance of the console logger
|
||||
* @var
|
||||
*/
|
||||
private $log;
|
||||
|
||||
/**
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
||||
const BATCH_READ_ROWS = 300;
|
||||
const SUBFLEET_NAME = 'Imported Aircraft';
|
||||
|
||||
/**
|
||||
* Importer constructor.
|
||||
* @param $db_creds
|
||||
*/
|
||||
public function __construct($db_creds)
|
||||
{
|
||||
// Setup the logger
|
||||
$this->log = new ConsoleOutput();
|
||||
|
||||
# The db credentials
|
||||
$this->creds = array_merge([
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 3306,
|
||||
'name' => '',
|
||||
'user' => '',
|
||||
'pass' => '',
|
||||
'table_prefix' => 'phpvms_'
|
||||
], $db_creds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->reconnect();
|
||||
|
||||
# Import all the different parts
|
||||
$this->importRanks();
|
||||
$this->importAirlines();
|
||||
$this->importAircraft();
|
||||
$this->importAirports();
|
||||
|
||||
$this->importUsers();
|
||||
$this->importFlights();
|
||||
$this->importPireps();
|
||||
|
||||
# Finish up
|
||||
$this->findLastPireps();
|
||||
$this->recalculateRanks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconnect to the old phpVMS DB using PDO
|
||||
*/
|
||||
protected function reconnect()
|
||||
{
|
||||
$dsn = 'mysql:' . implode(';', [
|
||||
'host=' . $this->creds['host'],
|
||||
'port=' . $this->creds['port'],
|
||||
'dbname=' . $this->creds['name']
|
||||
]);
|
||||
|
||||
$this->info('Connection string: ' . $dsn);
|
||||
|
||||
try {
|
||||
$this->conn = new PDO($dsn, $this->creds['user'], $this->creds['pass']);
|
||||
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
} catch (\PDOException $e) {
|
||||
$this->error($e);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
*/
|
||||
protected function comment($message)
|
||||
{
|
||||
$this->log->writeln('<comment>' . $message . '</comment>');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
*/
|
||||
protected function error($message) {
|
||||
$this->log->writeln('<error>' . $message . '</error>');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
protected function info($message)
|
||||
{
|
||||
if(\is_array($message)) {
|
||||
print_r($message);
|
||||
}
|
||||
else {
|
||||
$this->log->writeln('<info>'.$message.'</info>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name with the prefix
|
||||
* @param $table
|
||||
* @return string
|
||||
*/
|
||||
protected function tableName($table)
|
||||
{
|
||||
if($this->creds['table_prefix'] !== false) {
|
||||
return $this->creds['table_prefix'].$table;
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return bool
|
||||
*/
|
||||
protected function saveModel($model)
|
||||
{
|
||||
try {
|
||||
$model->save();
|
||||
return true;
|
||||
} catch (QueryException $e) {
|
||||
if($e->getCode() !== '23000') {
|
||||
$this->error($e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new mapping between an old ID and the new one
|
||||
* @param $entity
|
||||
* @param $old_id
|
||||
* @param $new_id
|
||||
*/
|
||||
protected function addMapping($entity, $old_id, $new_id)
|
||||
{
|
||||
if(!array_key_exists($entity, $this->mappedEntities)) {
|
||||
$this->mappedEntities[$entity] = [];
|
||||
}
|
||||
|
||||
$this->mappedEntities[$entity][$old_id] = $new_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID for a mapping
|
||||
* @param $entity
|
||||
* @param $old_id
|
||||
* @return bool
|
||||
*/
|
||||
protected function getMapping($entity, $old_id)
|
||||
{
|
||||
if(!array_key_exists($entity, $this->mappedEntities)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$entity = $this->mappedEntities[$entity];
|
||||
if(array_key_exists($old_id, $entity)) {
|
||||
return $entity[$old_id];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $date
|
||||
* @return Carbon
|
||||
*/
|
||||
protected function parseDate($date)
|
||||
{
|
||||
$carbon = Carbon::parse($date);
|
||||
return $carbon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a decimal duration and convert it to minutes
|
||||
* @param $duration
|
||||
* @return float|int
|
||||
*/
|
||||
protected function convertDuration($duration)
|
||||
{
|
||||
if(strpos($duration, '.') !== false) {
|
||||
$delim = '.';
|
||||
} elseif(strpos($duration, ':')) {
|
||||
$delim = ':';
|
||||
} else {
|
||||
# no delimiter, assume it's just a straight hour
|
||||
return (int) $duration * 60;
|
||||
}
|
||||
|
||||
$hm = explode($delim, $duration);
|
||||
$hours = (int) $hm[0] * 60;
|
||||
$mins = (int) $hm[1];
|
||||
|
||||
return $hours + $mins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getTotalRows($table)
|
||||
{
|
||||
$table = $this->tableName($table);
|
||||
|
||||
$sql = 'SELECT COUNT(*) FROM ' . $table;
|
||||
$rows = $this->conn->query($sql)->fetchColumn();
|
||||
|
||||
$this->info('Found '.$rows.' rows in '.$table);
|
||||
return (int) $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all the rows in a table, but read them in a batched manner
|
||||
* @param string $table The name of the table
|
||||
* @param null $read_rows Number of rows to read
|
||||
* @return \Generator
|
||||
*/
|
||||
protected function readRows($table, $read_rows=null)
|
||||
{
|
||||
// Set the table prefix if it has been entered
|
||||
$this->tableName($table);
|
||||
|
||||
$offset = 0;
|
||||
if($read_rows === null) {
|
||||
$read_rows = self::BATCH_READ_ROWS;
|
||||
}
|
||||
|
||||
$total_rows = $this->getTotalRows($table);
|
||||
|
||||
while($offset < $total_rows)
|
||||
{
|
||||
$rows_to_read = $offset + $read_rows;
|
||||
if($rows_to_read > $total_rows) {
|
||||
$rows_to_read = $total_rows;
|
||||
}
|
||||
|
||||
$this->info('Reading '.$offset.' to '.$rows_to_read.' of '.$total_rows);
|
||||
|
||||
$sql = 'SELECT * FROM ' . $this->tableName($table)
|
||||
. ' LIMIT ' . self::BATCH_READ_ROWS . ' OFFSET ' . $offset;
|
||||
|
||||
try {
|
||||
foreach ($this->conn->query($sql) as $row) {
|
||||
yield $row;
|
||||
}
|
||||
} catch(PDOException $e) {
|
||||
// Without incrementing the offset, it should re-run the same query
|
||||
$this->error($e);
|
||||
|
||||
if(strpos($e->getMessage(), 'server has gone away') !== false) {
|
||||
$this->reconnect();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$offset += self::BATCH_READ_ROWS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subfleet
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getSubfleet()
|
||||
{
|
||||
$airline = Airline::first();
|
||||
$subfleet = Subfleet::firstOrCreate(
|
||||
['airline_id' => $airline->id, 'name' => self::SUBFLEET_NAME],
|
||||
['type' => 'PHPVMS']
|
||||
);
|
||||
|
||||
return $subfleet;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* All the individual importers, done on a per-table basis
|
||||
* Some tables get saved locally for tables that use FK refs
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import all of the ranks
|
||||
*/
|
||||
protected function importRanks()
|
||||
{
|
||||
$this->comment('--- RANK IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('ranks') as $row)
|
||||
{
|
||||
$rank = Rank::firstOrCreate(
|
||||
['name' => $row->rank],
|
||||
['image_link' => $row->rankimage, 'hours'=>$row->minhours]
|
||||
);
|
||||
|
||||
$this->addMapping('ranks', $row->rankid, $rank->id);
|
||||
$this->addMapping('ranks', $row->rank, $rank->id);
|
||||
|
||||
if($rank->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' ranks');
|
||||
}
|
||||
|
||||
/**
|
||||
* Import all of the airlines. Save them all in the private var $airlines
|
||||
* They're used to lookup from other reference tables
|
||||
*/
|
||||
protected function importAirlines()
|
||||
{
|
||||
$this->comment('--- AIRLINE IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('airlines') as $row)
|
||||
{
|
||||
$airline = Airline::firstOrCreate(
|
||||
['icao' => $row->code],
|
||||
['iata' => $row->code, 'name' => $row->name, 'active' => $row->enabled]
|
||||
);
|
||||
|
||||
$this->addMapping('airlines', $row->id, $airline->id);
|
||||
$this->addMapping('airlines', $row->code, $airline->id);
|
||||
|
||||
if ($airline->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported '. $count.' airlines');
|
||||
}
|
||||
|
||||
/**
|
||||
* Imported the aircraft
|
||||
*/
|
||||
protected function importAircraft()
|
||||
{
|
||||
$this->comment('--- AIRCRAFT IMPORT ---');
|
||||
|
||||
$subfleet = $this->getSubfleet();
|
||||
|
||||
$this->info('Subfleet ID is '.$subfleet->id);
|
||||
|
||||
$count = 0;
|
||||
foreach($this->readRows('aircraft') as $row)
|
||||
{
|
||||
$aircraft = Aircraft::firstOrCreate(
|
||||
['name' => $row->fullname, 'registration' => $row->registration],
|
||||
['icao' => $row->icao,
|
||||
'subfleet_id' => $subfleet->id,
|
||||
'active' => $row->enabled
|
||||
]);
|
||||
|
||||
$this->addMapping('aircraft', $row->id, $aircraft->id);
|
||||
|
||||
if($aircraft->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' aircraft');
|
||||
}
|
||||
|
||||
/**
|
||||
* Import all of the airports
|
||||
*/
|
||||
protected function importAirports()
|
||||
{
|
||||
$this->comment('--- AIRPORT IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('airports') as $row)
|
||||
{
|
||||
$attrs = [
|
||||
'id' => trim($row->icao),
|
||||
'icao' => trim($row->icao),
|
||||
'name' => $row->name,
|
||||
'country' => $row->country,
|
||||
'lat' => $row->lat,
|
||||
'lon' => $row->lng,
|
||||
'hub' => $row->hub,
|
||||
];
|
||||
|
||||
$airport = Airport::updateOrCreate(
|
||||
['id' => $attrs['id']],
|
||||
$attrs
|
||||
);
|
||||
|
||||
if($airport->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' airports');
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the flights and schedules
|
||||
*/
|
||||
protected function importFlights()
|
||||
{
|
||||
$this->comment('--- FLIGHT SCHEDULE IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('schedules') as $row)
|
||||
{
|
||||
$airline_id = $this->getMapping('airlines', $row->code);
|
||||
|
||||
$flight_num = trim($row->flightnum);
|
||||
|
||||
$attrs = [
|
||||
'dpt_airport_id' => $row->depicao,
|
||||
'arr_airport_id' => $row->arricao,
|
||||
'route' => $row->route ?: '',
|
||||
'distance' => round($row->distance ?: 0, 2),
|
||||
'level' => $row->flightlevel ?: 0,
|
||||
'dpt_time' => $row->deptime ?: '',
|
||||
'arr_time' => $row->arrtime ?: '',
|
||||
'flight_time' => $this->convertDuration($row->flighttime) ?: '',
|
||||
'notes' => $row->notes ?: '',
|
||||
'active' => $row->enabled ?: true,
|
||||
];
|
||||
|
||||
try {
|
||||
$flight = Flight::updateOrCreate(
|
||||
['airline_id' => $airline_id, 'flight_number' => $flight_num],
|
||||
$attrs
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
#$this->error($e);
|
||||
}
|
||||
|
||||
$this->addMapping('flights', $row->id, $flight->id);
|
||||
|
||||
// TODO: deserialize route_details into ACARS table
|
||||
|
||||
if($flight->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' flights');
|
||||
}
|
||||
|
||||
/**
|
||||
* Import all of the PIREPs
|
||||
*/
|
||||
protected function importPireps()
|
||||
{
|
||||
$this->comment('--- PIREP IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('pireps') as $row)
|
||||
{
|
||||
$pirep_id = $row->pirepid;
|
||||
$user_id = $this->getMapping('users', $row->pilotid);
|
||||
$airline_id = $this->getMapping('airlines', $row->code);
|
||||
$aircraft_id = $this->getMapping('aircraft', $row->aircraft);
|
||||
|
||||
$attrs = [
|
||||
#'id' => $pirep_id,
|
||||
'user_id' => $user_id,
|
||||
'airline_id' => $airline_id,
|
||||
'aircraft_id' => $aircraft_id,
|
||||
'flight_number' => $row->flightnum ?: '',
|
||||
'dpt_airport_id' => $row->depicao,
|
||||
'arr_airport_id' => $row->arricao,
|
||||
'block_fuel' => $row->fuelused,
|
||||
'route' => $row->route ?: '',
|
||||
'source_name' => $row->source,
|
||||
'created_at' => $this->parseDate($row->submitdate),
|
||||
'updated_at' => $this->parseDate($row->modifieddate),
|
||||
];
|
||||
|
||||
# Set the distance
|
||||
$distance = round($row->distance ?: 0, 2);
|
||||
$attrs['distance'] = $distance;
|
||||
$attrs['planned_distance'] = $distance;
|
||||
|
||||
# Set the flight time properly
|
||||
$duration = $this->convertDuration($row->flighttime_stamp);
|
||||
$attrs['flight_time'] = $duration;
|
||||
$attrs['planned_flight_time'] = $duration;
|
||||
|
||||
# Set how it was filed
|
||||
if(strtoupper($row->source) === 'MANUAL') {
|
||||
$attrs['source'] = PirepSource::MANUAL;
|
||||
} else {
|
||||
$attrs['source'] = PirepSource::ACARS;
|
||||
}
|
||||
|
||||
# Set the flight type
|
||||
$row->flighttype = strtoupper($row->flighttype);
|
||||
if($row->flighttype === 'P') {
|
||||
$attrs['flight_type'] = FlightType::PASSENGER;
|
||||
} elseif($row->flighttype === 'C') {
|
||||
$attrs['flight_type'] = FlightType::CARGO;
|
||||
} else {
|
||||
$attrs['flight_type'] = FlightType::CHARTER;
|
||||
}
|
||||
|
||||
# Set the flight level of the PIREP is set
|
||||
if(property_exists($row, 'flightlevel')) {
|
||||
$attrs['level'] = $row->flightlevel;
|
||||
} else {
|
||||
$attrs['level'] = 0;
|
||||
}
|
||||
|
||||
$pirep = Pirep::updateOrCreate(
|
||||
['id' => $pirep_id],
|
||||
$attrs
|
||||
);
|
||||
|
||||
$source = strtoupper($row->source);
|
||||
if($source === 'SMARTCARS') {
|
||||
# TODO: Parse smartcars log into the acars table
|
||||
} elseif($source === 'KACARS') {
|
||||
# TODO: Parse kACARS log into acars table
|
||||
} elseif($source === 'XACARS') {
|
||||
# TODO: Parse XACARS log into acars table
|
||||
}
|
||||
|
||||
# TODO: Add extra fields in as PIREP fields
|
||||
$this->addMapping('pireps', $row->pirepid, $pirep->id);
|
||||
|
||||
if ($pirep->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' pireps');
|
||||
}
|
||||
|
||||
protected function importUsers()
|
||||
{
|
||||
$this->comment('--- USER IMPORT ---');
|
||||
|
||||
$count = 0;
|
||||
foreach ($this->readRows('pilots', 50) as $row) {
|
||||
|
||||
# TODO: What to do about pilot ids
|
||||
|
||||
$name = $row->firstname . ' ' . $row->lastname;
|
||||
|
||||
$airline_id = $this->getMapping('airlines', $row->code);
|
||||
$rank_id = $this->getMapping('ranks', $row->rank);
|
||||
$state = $this->getUserState($row->retired);
|
||||
|
||||
$new_password = Str::random(60);
|
||||
|
||||
$attrs = [
|
||||
'name' => $name,
|
||||
'password' => Hash::make($new_password),
|
||||
'api_key' => Utils::generateApiKey(),
|
||||
'airline_id' => $airline_id,
|
||||
'rank_id' => $rank_id,
|
||||
'home_airport_id' => $row->hub,
|
||||
'curr_airport_id' => $row->hub,
|
||||
'flights' => (int)$row->totalflights,
|
||||
'flight_time' => Utils::hoursToMinutes($row->totalhours),
|
||||
'state' => $state,
|
||||
'created_at' => $this->parseDate($row->joindate),
|
||||
];
|
||||
|
||||
$user = User::updateOrCreate(
|
||||
['email' => $row->email],
|
||||
$attrs
|
||||
);
|
||||
|
||||
$this->addMapping('users', $row->pilotid, $user->id);
|
||||
|
||||
if ($user->wasRecentlyCreated) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Imported ' . $count . ' users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through and set the last PIREP ID for the users
|
||||
*/
|
||||
protected function findLastPireps()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate all of the user ranks
|
||||
*/
|
||||
protected function recalculateRanks()
|
||||
{
|
||||
/*$this->comment('--- RECALCULATING RANKS ---');*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's new state from their original state
|
||||
* @param $state
|
||||
* @return int
|
||||
*/
|
||||
protected function getUserState($state)
|
||||
{
|
||||
// TODO: This state might differ between simpilot and classic version
|
||||
|
||||
$state = (int) $state;
|
||||
|
||||
// Declare array of classic states
|
||||
$phpvms_classic_states = [
|
||||
'ACTIVE' => 0,
|
||||
'INACTIVE' => 1,
|
||||
'BANNED' => 2,
|
||||
'ON_LEAVE' => 3
|
||||
];
|
||||
|
||||
// Decide which state they will be in accordance with v7
|
||||
if ($state === $phpvms_classic_states['ACTIVE']) {
|
||||
return UserState::ACTIVE;
|
||||
} elseif ($state === $phpvms_classic_states['INACTIVE']) {
|
||||
# TODO: Make an inactive state?
|
||||
return UserState::REJECTED;
|
||||
} elseif ($state === $phpvms_classic_states['BANNED']) {
|
||||
return UserState::SUSPENDED;
|
||||
} elseif ($state === $phpvms_classic_states['ON_LEAVE']) {
|
||||
return UserState::ON_LEAVE;
|
||||
} else {
|
||||
$this->error('Unknown status: '. $state);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
app/Contracts/AirportLookup.php
Normal file
27
app/Contracts/AirportLookup.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Models\Airport;
|
||||
|
||||
abstract class AirportLookup
|
||||
{
|
||||
/**
|
||||
* Lookup the information for an airport. Needs to return an instance of the
|
||||
* Airport model, or an array with the properties listed in the Airport model.
|
||||
*
|
||||
* The in-use implementation can be changed in the config/phpvms.php file, so
|
||||
* different services can be used, in-case vaCentral one isn't working or there
|
||||
* is a better one available. Don't handle any caching in this layer, that happens
|
||||
* at the service layer
|
||||
*
|
||||
* Return null if there's an error or nothing was found
|
||||
*
|
||||
* @example App\Services\AirportLookup\VaCentralLookup
|
||||
*
|
||||
* @param string $icao
|
||||
*
|
||||
* @return Airport|null
|
||||
*/
|
||||
abstract public function getAirport($icao);
|
||||
}
|
||||
99
app/Contracts/Award.php
Normal file
99
app/Contracts/Award.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Facades\Utils;
|
||||
use App\Models\Award as AwardModel;
|
||||
use App\Models\User;
|
||||
use App\Models\UserAward;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Base class for the Awards, you need to extend this, and implement:
|
||||
* $name
|
||||
* $param_description (optional)
|
||||
* public function check($parameter=null)
|
||||
*
|
||||
* See: http://docs.phpvms.net/customizing/awards
|
||||
*/
|
||||
abstract class Award
|
||||
{
|
||||
public $name = '';
|
||||
public $param_description = '';
|
||||
|
||||
/**
|
||||
* Each award class just needs to return true or false if it should actually
|
||||
* be awarded to a user. This is the only method that needs to be implemented
|
||||
*
|
||||
* @param null $parameter Optional parameters that are passed in from the UI
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function check($parameter = null): bool;
|
||||
|
||||
/*
|
||||
* You don't really need to mess with anything below here
|
||||
*/
|
||||
|
||||
protected $award;
|
||||
protected $user;
|
||||
|
||||
public function __construct(AwardModel $award = null, User $user = null)
|
||||
{
|
||||
$this->award = $award;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main handler for this award class to determine if
|
||||
* it should be awarded or not. Declared as final to prevent a child
|
||||
* from accidentally overriding and breaking something
|
||||
*/
|
||||
final public function handle(): void
|
||||
{
|
||||
// Check if the params are a JSON object or array
|
||||
$param = $this->award->ref_model_params;
|
||||
if (Utils::isObject($this->award->ref_model_params)) {
|
||||
$param = json_decode($this->award->ref_model_params);
|
||||
}
|
||||
|
||||
if ($this->check($param)) {
|
||||
$this->addAward();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the award to this user, if they don't already have it
|
||||
*
|
||||
* @return bool|UserAward
|
||||
*/
|
||||
protected function addAward()
|
||||
{
|
||||
$w = [
|
||||
'user_id' => $this->user->id,
|
||||
'award_id' => $this->award->id,
|
||||
];
|
||||
|
||||
$found = UserAward::where($w)->count('id');
|
||||
if ($found > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Associate this award to the user now
|
||||
$award = new UserAward($w);
|
||||
|
||||
try {
|
||||
$award->save();
|
||||
} catch (Exception $e) {
|
||||
Log::error(
|
||||
'Error saving award: '.$e->getMessage(),
|
||||
$e->getTrace()
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $award;
|
||||
}
|
||||
}
|
||||
116
app/Contracts/Command.php
Normal file
116
app/Contracts/Command.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class BaseCommand
|
||||
*/
|
||||
abstract class Command extends \Illuminate\Console\Command
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function handle();
|
||||
|
||||
/**
|
||||
* Adjust the logging depending on where we're running from
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Running in the console but not in the tests
|
||||
if (app()->runningInConsole() && env('APP_ENV') !== 'testing') {
|
||||
$this->redirectLoggingToFile('stdout');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splice the logger and replace the active handlers with the handlers from the
|
||||
* a stack in config/logging.php
|
||||
*
|
||||
* @param string $channel_name Channel name from config/logging.php
|
||||
*/
|
||||
public function redirectLoggingToFile($channel_name): void
|
||||
{
|
||||
$logger = app(\Illuminate\Log\Logger::class);
|
||||
|
||||
// Close the existing loggers
|
||||
try {
|
||||
$handlers = $logger->getHandlers();
|
||||
foreach ($handlers as $handler) {
|
||||
$handler->close();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error closing handlers: '.$e->getMessage());
|
||||
}
|
||||
|
||||
// Open the handlers for the channel name,
|
||||
// and then set them to the main logger
|
||||
try {
|
||||
$logger->setHandlers(
|
||||
Log::channel($channel_name)->getHandlers()
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Couldn\'t splice the logger: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streaming file reader
|
||||
*
|
||||
* @param $filename
|
||||
*
|
||||
* @return \Generator
|
||||
*/
|
||||
public function readFile($filename): ?\Generator
|
||||
{
|
||||
$fp = fopen($filename, 'rb');
|
||||
while (($line = fgets($fp)) !== false) {
|
||||
$line = rtrim($line, "\r\n");
|
||||
if ($line[0] === ';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $line;
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cmd
|
||||
* @param bool $return
|
||||
* @param mixed $verbose
|
||||
*
|
||||
* @throws \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @throws \Symfony\Component\Process\Exception\LogicException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function runCommand($cmd, $return = false, $verbose = true): string
|
||||
{
|
||||
if (\is_array($cmd)) {
|
||||
$cmd = implode(' ', $cmd);
|
||||
}
|
||||
|
||||
if ($verbose) {
|
||||
$this->info('Running "'.$cmd.'"');
|
||||
}
|
||||
|
||||
$val = '';
|
||||
$process = new Process($cmd);
|
||||
$process->run(function ($type, $buffer) use ($return, &$val) {
|
||||
if ($return) {
|
||||
$val .= $buffer;
|
||||
} else {
|
||||
echo $buffer;
|
||||
}
|
||||
});
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
101
app/Contracts/Controller.php
Executable file
101
app/Contracts/Controller.php
Executable file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class Controller
|
||||
*/
|
||||
abstract class Controller extends \Illuminate\Routing\Controller
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
use DispatchesJobs;
|
||||
use ValidatesRequests;
|
||||
|
||||
/**
|
||||
* Write a error to the flash and redirect the user to a route
|
||||
*
|
||||
* @param $message
|
||||
* @param $route
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function flashError($message, $route)
|
||||
{
|
||||
flash()->error($message);
|
||||
return redirect(route($route))->withInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut function to get the attributes from a request while running the validations
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $attrs_or_validations
|
||||
* @param array $addtl_fields
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromReq($request, $attrs_or_validations, $addtl_fields = null)
|
||||
{
|
||||
// See if a list of values is passed in, or if a validation list is passed in
|
||||
$is_validation = false;
|
||||
if (\count(array_filter(array_keys($attrs_or_validations), '\is_string')) > 0) {
|
||||
$is_validation = true;
|
||||
}
|
||||
|
||||
if ($is_validation) {
|
||||
$this->validate($request, $attrs_or_validations);
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
foreach ($attrs_or_validations as $idx => $field) {
|
||||
if ($is_validation) {
|
||||
$field = $idx;
|
||||
}
|
||||
|
||||
if ($request instanceof Request) {
|
||||
if ($request->filled($field)) {
|
||||
$fields[$field] = $request->input($field);
|
||||
}
|
||||
} else {
|
||||
/* @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (array_key_exists($field, $request)) {
|
||||
$fields[$field] = $request[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($addtl_fields) && \is_array($addtl_fields)) {
|
||||
$fields = array_merge($fields, $addtl_fields);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple normalized method for forming the JSON responses
|
||||
*
|
||||
* @param $message
|
||||
* @param null|mixed $count
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function message($message, $count = null)
|
||||
{
|
||||
$attrs = [
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
if ($count !== null) {
|
||||
$attrs['count'] = $count;
|
||||
}
|
||||
|
||||
return response()->json($attrs);
|
||||
}
|
||||
}
|
||||
167
app/Contracts/Enum.php
Normal file
167
app/Contracts/Enum.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
/**
|
||||
* Borrowed some ideas from myclabs/php-enum after this was created
|
||||
*/
|
||||
abstract class Enum
|
||||
{
|
||||
protected static $cache = [];
|
||||
protected static $codes = [];
|
||||
protected static $labels = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Create an instance of this Enum
|
||||
*
|
||||
* @param $val
|
||||
*/
|
||||
public function __construct($val)
|
||||
{
|
||||
$this->value = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value that's been set if this is an instance
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
final public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the label, try to return the translated version as well
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
final public static function label($value)
|
||||
{
|
||||
if (isset(static::$labels[$value])) {
|
||||
return trans(static::$labels[$value]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the (translated) labels
|
||||
*/
|
||||
final public static function labels(): array
|
||||
{
|
||||
$labels = [];
|
||||
foreach (static::$labels as $key => $label) {
|
||||
$labels[$key] = trans($label);
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numeric value from a string code
|
||||
*
|
||||
* @param $code
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function getFromCode($code)
|
||||
{
|
||||
return array_search($code, static::$codes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the integer value into one of the codes
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return false|int|string
|
||||
*/
|
||||
public static function convertToCode($value)
|
||||
{
|
||||
$value = (int) $value;
|
||||
if (!array_key_exists($value, static::$codes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return static::$codes[$value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Select box entry items
|
||||
*
|
||||
* @param bool $add_blank
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function select($add_blank = false): array
|
||||
{
|
||||
$labels = [];
|
||||
if ($add_blank) {
|
||||
$labels[] = '';
|
||||
}
|
||||
|
||||
foreach (static::$labels as $key => $label) {
|
||||
$labels[$key] = trans($label);
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all possible values as an array
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @return array Constant name in key, constant value in value
|
||||
*/
|
||||
public static function toArray(): array
|
||||
{
|
||||
$class = static::class;
|
||||
if (!array_key_exists($class, static::$cache)) {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
static::$cache[$class] = $reflection->getConstants();
|
||||
}
|
||||
|
||||
return static::$cache[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Enum $enum
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
final public function equals(self $enum): bool
|
||||
{
|
||||
return $this->getValue() === $enum->getValue() && static::class === \get_class($enum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a
|
||||
* class constant
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
$array = static::toArray();
|
||||
if (isset($array[$name])) {
|
||||
return new static($array[$name]);
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException(
|
||||
"No static method or enum constant '$name' in class ".static::class
|
||||
);
|
||||
}
|
||||
}
|
||||
25
app/Contracts/FormRequest.php
Normal file
25
app/Contracts/FormRequest.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
/**
|
||||
* Class FormRequest
|
||||
*/
|
||||
class FormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
246
app/Contracts/ImportExport.php
Normal file
246
app/Contracts/ImportExport.php
Normal file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Models\Airline;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Log;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Common functionality used across all of the importers
|
||||
*/
|
||||
class ImportExport
|
||||
{
|
||||
public $assetType;
|
||||
public $status = [
|
||||
'success' => [],
|
||||
'errors' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* Hold the columns for the particular table
|
||||
*/
|
||||
public static $columns = [];
|
||||
|
||||
/**
|
||||
* @param mixed $row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function export($row): array
|
||||
{
|
||||
throw new \RuntimeException('export not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @param mixed $index
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function import(array $row, $index): bool
|
||||
{
|
||||
throw new \RuntimeException('import not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the airline from the ICAO. Create it if it doesn't exist
|
||||
*
|
||||
* @param $code
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function getAirline($code)
|
||||
{
|
||||
$airline = Airline::firstOrCreate([
|
||||
'icao' => $code,
|
||||
], ['name' => $code]);
|
||||
|
||||
return $airline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return static::$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a basic check that the number of columns match
|
||||
*
|
||||
* @param $row
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkColumns($row): bool
|
||||
{
|
||||
return \count($row) === \count($this->getColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bubble up an error to the interface that we need to stop
|
||||
*
|
||||
* @param $error
|
||||
* @param $e
|
||||
*
|
||||
* @throws ValidationException
|
||||
*/
|
||||
protected function throwError($error, \Exception $e = null): void
|
||||
{
|
||||
Log::error($error);
|
||||
if ($e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
|
||||
$validator = Validator::make([], []);
|
||||
$validator->errors()->add('csv_file', $error);
|
||||
|
||||
throw new ValidationException($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the log messages for this importer
|
||||
*
|
||||
* @param $msg
|
||||
*/
|
||||
public function log($msg): void
|
||||
{
|
||||
$this->status['success'][] = $msg;
|
||||
Log::info($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the error log for this import
|
||||
*
|
||||
* @param $msg
|
||||
*/
|
||||
public function errorLog($msg): void
|
||||
{
|
||||
$this->status['errors'][] = $msg;
|
||||
Log::error($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a key-value pair to an array
|
||||
*
|
||||
* @param $kvp_str
|
||||
* @param array $arr
|
||||
*/
|
||||
protected function kvpToArray($kvp_str, array &$arr)
|
||||
{
|
||||
$item = explode('=', $kvp_str);
|
||||
if (\count($item) === 1) { // just a list?
|
||||
$arr[] = trim($item[0]);
|
||||
} else { // actually a key-value pair
|
||||
$k = trim($item[0]);
|
||||
$v = trim($item[1]);
|
||||
$arr[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a multi column values field. E.g:
|
||||
* Y?price=200&cost=100; F?price=1200
|
||||
* or
|
||||
* gate=B32;cost index=100
|
||||
*
|
||||
* Converted into a multi-dimensional array
|
||||
*
|
||||
* @param $field
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function parseMultiColumnValues($field)
|
||||
{
|
||||
$ret = [];
|
||||
$split_values = explode(';', $field);
|
||||
|
||||
// No multiple values in here, just a straight value
|
||||
if (\count($split_values) === 1) {
|
||||
if (trim($split_values[0]) === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [$split_values[0]];
|
||||
}
|
||||
|
||||
foreach ($split_values as $value) {
|
||||
// This isn't in the query string format, so it's
|
||||
// just a straight key-value pair set
|
||||
if (strpos($value, '?') === false) {
|
||||
$this->kvpToArray($value, $ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
// This contains the query string, which turns it
|
||||
// into the multi-level array
|
||||
|
||||
$query_str = explode('?', $value);
|
||||
$parent = trim($query_str[0]);
|
||||
|
||||
$children = [];
|
||||
$kvp = explode('&', trim($query_str[1]));
|
||||
foreach ($kvp as $items) {
|
||||
if (!$items) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->kvpToArray($items, $children);
|
||||
}
|
||||
|
||||
$ret[$parent] = $children;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $obj
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function objectToMultiString($obj)
|
||||
{
|
||||
if (!\is_array($obj)) {
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$ret_list = [];
|
||||
foreach ($obj as $key => $val) {
|
||||
if (is_numeric($key) && !\is_array($val)) {
|
||||
$ret_list[] = $val;
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = trim($key);
|
||||
|
||||
if (!\is_array($val)) {
|
||||
$val = trim($val);
|
||||
$ret_list[] = "{$key}={$val}";
|
||||
} else {
|
||||
$q = [];
|
||||
foreach ($val as $subkey => $subval) {
|
||||
if (is_numeric($subkey)) {
|
||||
$q[] = $subval;
|
||||
} else {
|
||||
$q[] = "{$subkey}={$subval}";
|
||||
}
|
||||
}
|
||||
|
||||
$q = implode('&', $q);
|
||||
if (!empty($q)) {
|
||||
$ret_list[] = "{$key}?{$q}";
|
||||
} else {
|
||||
$ret_list[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode(';', $ret_list);
|
||||
}
|
||||
}
|
||||
22
app/Contracts/Listener.php
Normal file
22
app/Contracts/Listener.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
abstract class Listener
|
||||
{
|
||||
public static $callbacks = [];
|
||||
|
||||
/**
|
||||
* Sets up any callbacks that are defined in the child class
|
||||
*
|
||||
* @param $events
|
||||
*/
|
||||
public function subscribe(Dispatcher $events): void
|
||||
{
|
||||
foreach (static::$callbacks as $klass => $cb) {
|
||||
$events->listen($klass, get_class($this).'@'.$cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
app/Contracts/Metar.php
Normal file
55
app/Contracts/Metar.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Base class for implementing retrieving METARs
|
||||
*/
|
||||
abstract class Metar
|
||||
{
|
||||
/**
|
||||
* Implement retrieving the METAR - return the METAR string. Needs to be protected,
|
||||
* since this shouldn't be directly called. Call `get_metar($icao)` instead
|
||||
*
|
||||
* @param $icao
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function metar($icao): string;
|
||||
|
||||
/**
|
||||
* Download the METAR, wrap in caching
|
||||
*
|
||||
* @param $icao
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_metar($icao): string
|
||||
{
|
||||
$cache = config('cache.keys.WEATHER_LOOKUP');
|
||||
$key = $cache['key'].$icao;
|
||||
|
||||
if (Cache::has($key)) {
|
||||
$raw_metar = Cache::get($key);
|
||||
if ($raw_metar !== '') {
|
||||
return $raw_metar;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$raw_metar = $this->metar($icao);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error getting METAR: '.$e->getMessage(), $e->getTrace());
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($raw_metar !== '') {
|
||||
Cache::put($key, $raw_metar, $cache['time']);
|
||||
}
|
||||
|
||||
return $raw_metar;
|
||||
}
|
||||
}
|
||||
11
app/Contracts/Middleware.php
Normal file
11
app/Contracts/Middleware.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
interface Middleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next);
|
||||
}
|
||||
63
app/Contracts/Migration.php
Normal file
63
app/Contracts/Migration.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Support\Database;
|
||||
use DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class Migration
|
||||
*/
|
||||
abstract class Migration extends \Illuminate\Database\Migrations\Migration
|
||||
{
|
||||
/**
|
||||
* At a minimum, this function needs to be implemented
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function up();
|
||||
|
||||
/**
|
||||
* A method to reverse a migration doesn't need to be made
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed a YAML file into the database
|
||||
*
|
||||
* @param string $file Full path to yml file to seed
|
||||
*/
|
||||
public function seedFile($file): void
|
||||
{
|
||||
try {
|
||||
$path = base_path($file);
|
||||
Database::seed_from_yaml_file($path, false);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Unable to load '.$file.' file');
|
||||
Log::error($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rows to a table
|
||||
*
|
||||
* @param $table
|
||||
* @param $rows
|
||||
*/
|
||||
public function addData($table, $rows)
|
||||
{
|
||||
foreach ($rows as $row) {
|
||||
try {
|
||||
DB::table($table)->insert($row);
|
||||
} catch (\Exception $e) {
|
||||
// setting already exists, just ignore it
|
||||
if ($e->getCode() === 23000) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
app/Contracts/Model.php
Normal file
22
app/Contracts/Model.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
/**
|
||||
* @property mixed $id
|
||||
* @property bool $skip_mutator
|
||||
*
|
||||
* @mixin \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
abstract class Model extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
/**
|
||||
* Max length of ID for string columns
|
||||
*/
|
||||
public const ID_MAX_LENGTH = 12;
|
||||
|
||||
/**
|
||||
* For the factories, skip the mutators. Only apply to one instance
|
||||
*/
|
||||
public $skip_mutator = false;
|
||||
}
|
||||
137
app/Contracts/Repository.php
Normal file
137
app/Contracts/Repository.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
use Prettus\Repository\Eloquent\BaseRepository;
|
||||
|
||||
abstract class Repository extends BaseRepository
|
||||
{
|
||||
/**
|
||||
* @param $id
|
||||
* @param array $columns
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function findWithoutFail($id, array $columns = ['*'])
|
||||
{
|
||||
try {
|
||||
return $this->find($id, $columns);
|
||||
} catch (\Exception $e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $values
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($values)
|
||||
{
|
||||
$validator = Validator::make(
|
||||
$values,
|
||||
$this->model()->rules
|
||||
);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $validator->messages();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return N most recent items, sorted by created_at
|
||||
*
|
||||
* @param int $count
|
||||
* @param string $sort_by created_at (default) or updated_at
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function recent($count = null, $sort_by = 'created_at')
|
||||
{
|
||||
return $this->orderBy($sort_by, 'desc')->paginate($count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find records with a WHERE clause but also sort them
|
||||
*
|
||||
* @param $where
|
||||
* @param $sort_by
|
||||
* @param $order_by
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereOrder($where, $sort_by, $order_by = 'asc')
|
||||
{
|
||||
return $this->scopeQuery(function ($query) use ($where, $sort_by, $order_by) {
|
||||
$q = $query->where($where);
|
||||
// See if there are multi-column sorts
|
||||
if (\is_array($sort_by)) {
|
||||
foreach ($sort_by as $key => $sort) {
|
||||
$q = $q->orderBy($key, $sort);
|
||||
}
|
||||
} else {
|
||||
$q = $q->orderBy($sort_by, $order_by);
|
||||
}
|
||||
|
||||
return $q;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find records where values don't match a list but sort the rest
|
||||
*
|
||||
* @param string $col
|
||||
* @param array $values
|
||||
* @param string $sort_by
|
||||
* @param string $order_by
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotInOrder($col, $values, $sort_by, $order_by = 'asc')
|
||||
{
|
||||
return $this->scopeQuery(function ($query) use ($col, $values, $sort_by, $order_by) {
|
||||
$q = $query->whereNotIn($col, $values);
|
||||
// See if there are multi-column sorts
|
||||
if (\is_array($sort_by)) {
|
||||
foreach ($sort_by as $key => $sort) {
|
||||
$q = $q->orderBy($key, $sort);
|
||||
}
|
||||
} else {
|
||||
$q = $q->orderBy($sort_by, $order_by);
|
||||
}
|
||||
|
||||
return $q;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all data of repository, paginated. Added in extra parameter to read from the
|
||||
* request which page it should be on
|
||||
*
|
||||
* @param null $limit
|
||||
* @param array $columns
|
||||
* @param string $method
|
||||
*
|
||||
* @throws \Prettus\Repository\Exceptions\RepositoryException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function paginate($limit = null, $columns = ['*'], $method = 'paginate')
|
||||
{
|
||||
$this->applyCriteria();
|
||||
$this->applyScope();
|
||||
|
||||
$max = config('repository.pagination.limit', 50);
|
||||
$limit = (int) ($limit ?? request()->query('limit') ?? $max);
|
||||
$page = (int) request()->query('page', 1);
|
||||
|
||||
$results = $this->model->{$method}($limit, $columns, 'page', $page);
|
||||
$results->appends(app('request')->query());
|
||||
$this->resetModel();
|
||||
|
||||
return $this->parserResult($results);
|
||||
}
|
||||
}
|
||||
24
app/Contracts/RouteFinder.php
Normal file
24
app/Contracts/RouteFinder.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
/**
|
||||
* Abstract class for finding a route from a departure airport to an arrival airport
|
||||
* Can allow for multiple, configurable methods for finding a route, whether it reaches
|
||||
* out to a REST API or implement some sort of internal logic to look through a file
|
||||
* or whatever the logic might be.
|
||||
*
|
||||
* Just one public-facing method needs to be implemented
|
||||
*/
|
||||
abstract class RouteFinder
|
||||
{
|
||||
/**
|
||||
* Find a route from the departure ICAO to the arrival ICAO
|
||||
*
|
||||
* @param $dptIcao
|
||||
* @param $arrIcao
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function findRoute($dptIcao, $arrIcao): string;
|
||||
}
|
||||
10
app/Contracts/Service.php
Normal file
10
app/Contracts/Service.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
/**
|
||||
* Class Service
|
||||
*/
|
||||
abstract class Service
|
||||
{
|
||||
}
|
||||
129
app/Contracts/Unit.php
Normal file
129
app/Contracts/Unit.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use ArrayAccess;
|
||||
use PhpUnitsOfMeasure\Exception\UnknownUnitOfMeasure;
|
||||
|
||||
/**
|
||||
* Abstract unit wrapper
|
||||
*/
|
||||
class Unit implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* The unit this is kept as
|
||||
*/
|
||||
public $unit;
|
||||
|
||||
/**
|
||||
* All of the units of this class
|
||||
*/
|
||||
public $units;
|
||||
|
||||
/**
|
||||
* Holds an instance of the PhpUnit type
|
||||
*
|
||||
* @var \PhpUnitsOfMeasure\AbstractPhysicalQuantity
|
||||
*/
|
||||
protected $instance;
|
||||
|
||||
/**
|
||||
* Units that are included as part of the REST response
|
||||
*/
|
||||
public $responseUnits = [];
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function value()
|
||||
{
|
||||
return $this->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just call toUnit() on the PhpUnitOfMeasure instance
|
||||
*
|
||||
* @param string $unit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function toUnit($unit)
|
||||
{
|
||||
return $this->instance->toUnit($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the units that get sent back in a response
|
||||
*/
|
||||
public function getResponseUnits(): array
|
||||
{
|
||||
$response = [];
|
||||
foreach ($this->responseUnits as $unit) {
|
||||
$response[$unit] = $this[$unit];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess
|
||||
*
|
||||
* @param $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return $this->offsetGet($offset) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess
|
||||
*
|
||||
* @param $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
try {
|
||||
$value = $this->instance->toUnit($offset);
|
||||
if (!$value) {
|
||||
return;
|
||||
}
|
||||
} catch (UnknownUnitOfMeasure $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
return round($value, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess
|
||||
*
|
||||
* @param $offset
|
||||
* @param $value
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
// $this->units[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess
|
||||
*
|
||||
* @param $offset
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
// $this->units[$offset] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->offsetGet($this->unit);
|
||||
}
|
||||
}
|
||||
26
app/Contracts/Widget.php
Normal file
26
app/Contracts/Widget.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Arrilot\Widgets\AbstractWidget;
|
||||
|
||||
/**
|
||||
* Class Widget
|
||||
*/
|
||||
abstract class Widget extends AbstractWidget
|
||||
{
|
||||
public $cacheTime = 0;
|
||||
|
||||
/**
|
||||
* Render the template
|
||||
*
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function view(string $template, array $vars = [])
|
||||
{
|
||||
return view($template, $vars);
|
||||
}
|
||||
}
|
||||
31
app/Cron/Hourly/RemoveExpiredBids.php
Normal file
31
app/Cron/Hourly/RemoveExpiredBids.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Hourly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronHourly;
|
||||
use App\Models\Bid;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Remove expired bids
|
||||
*/
|
||||
class RemoveExpiredBids extends Listener
|
||||
{
|
||||
/**
|
||||
* Remove expired bids
|
||||
*
|
||||
* @param CronHourly $event
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle(CronHourly $event): void
|
||||
{
|
||||
if (setting('bids.expire_time') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$date = Carbon::now()->subHours(setting('bids.expire_time'));
|
||||
Bid::whereDate('created_at', '<', $date)->delete();
|
||||
}
|
||||
}
|
||||
34
app/Cron/Hourly/RemoveExpiredLiveFlights.php
Normal file
34
app/Cron/Hourly/RemoveExpiredLiveFlights.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Hourly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronHourly;
|
||||
use App\Models\Enums\PirepState;
|
||||
use App\Models\Pirep;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Remove expired live flights
|
||||
*/
|
||||
class RemoveExpiredLiveFlights extends Listener
|
||||
{
|
||||
/**
|
||||
* Remove expired live flights that haven't had an update in the live time
|
||||
*
|
||||
* @param CronHourly $event
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle(CronHourly $event): void
|
||||
{
|
||||
if (setting('acars.live_time') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$date = Carbon::now()->subHours(setting('acars.live_time'));
|
||||
Pirep::whereDate('updated_at', '<', $date)
|
||||
->where('state', PirepState::IN_PROGRESS)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
40
app/Cron/Monthly/ApplyExpenses.php
Normal file
40
app/Cron/Monthly/ApplyExpenses.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Monthly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronMonthly;
|
||||
use App\Models\Enums\ExpenseType;
|
||||
use App\Services\Finance\RecurringFinanceService;
|
||||
|
||||
/**
|
||||
* Go through and apply any finances that are daily
|
||||
*/
|
||||
class ApplyExpenses extends Listener
|
||||
{
|
||||
private $financeSvc;
|
||||
|
||||
/**
|
||||
* ApplyExpenses constructor.
|
||||
*
|
||||
* @param RecurringFinanceService $financeSvc
|
||||
*/
|
||||
public function __construct(RecurringFinanceService $financeSvc)
|
||||
{
|
||||
$this->financeSvc = $financeSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply all of the expenses for a month
|
||||
*
|
||||
* @param CronMonthly $event
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*/
|
||||
public function handle(CronMonthly $event): void
|
||||
{
|
||||
$this->financeSvc->processExpenses(ExpenseType::MONTHLY);
|
||||
}
|
||||
}
|
||||
40
app/Cron/Nightly/ApplyExpenses.php
Normal file
40
app/Cron/Nightly/ApplyExpenses.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Models\Enums\ExpenseType;
|
||||
use App\Services\Finance\RecurringFinanceService;
|
||||
|
||||
/**
|
||||
* Go through and apply any finances that are daily
|
||||
*/
|
||||
class ApplyExpenses extends Listener
|
||||
{
|
||||
private $financeSvc;
|
||||
|
||||
/**
|
||||
* ApplyExpenses constructor.
|
||||
*
|
||||
* @param RecurringFinanceService $financeSvc
|
||||
*/
|
||||
public function __construct(RecurringFinanceService $financeSvc)
|
||||
{
|
||||
$this->financeSvc = $financeSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply all of the expenses for a day
|
||||
*
|
||||
* @param CronNightly $event
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
$this->financeSvc->processExpenses(ExpenseType::DAILY);
|
||||
}
|
||||
}
|
||||
33
app/Cron/Nightly/NewVersionCheck.php
Normal file
33
app/Cron/Nightly/NewVersionCheck.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Services\VersionService;
|
||||
|
||||
/**
|
||||
* Determine if any pilots should be set to ON LEAVE status
|
||||
*/
|
||||
class NewVersionCheck extends Listener
|
||||
{
|
||||
private $versionSvc;
|
||||
|
||||
/**
|
||||
* @param VersionService $versionSvc
|
||||
*/
|
||||
public function __construct(VersionService $versionSvc)
|
||||
{
|
||||
$this->versionSvc = $versionSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set any users to being on leave after X days
|
||||
*
|
||||
* @param CronNightly $event
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
$this->versionSvc->isNewVersionAvailable();
|
||||
}
|
||||
}
|
||||
50
app/Cron/Nightly/PilotLeave.php
Normal file
50
app/Cron/Nightly/PilotLeave.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Models\Enums\UserState;
|
||||
use App\Models\User;
|
||||
use App\Services\UserService;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Determine if any pilots should be set to ON LEAVE status
|
||||
*/
|
||||
class PilotLeave extends Listener
|
||||
{
|
||||
private $userSvc;
|
||||
|
||||
/**
|
||||
* PilotLeave constructor.
|
||||
*/
|
||||
public function __construct(UserService $userSvc)
|
||||
{
|
||||
$this->userSvc = $userSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set any users to being on leave after X days
|
||||
*
|
||||
* @param CronNightly $event
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
if (setting('pilots.auto_leave_days') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$date = Carbon::now()->subDay(setting('pilots.auto_leave_days'));
|
||||
$users = User::where('status', UserState::ACTIVE)
|
||||
->whereDate('updated_at', '<', $date);
|
||||
|
||||
foreach ($users as $user) {
|
||||
Log::info('Setting user '.$user->ident.' to ON LEAVE status');
|
||||
$this->userSvc->setStatusOnLeave($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
app/Cron/Nightly/RecalculateBalances.php
Normal file
54
app/Cron/Nightly/RecalculateBalances.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Models\Journal;
|
||||
use App\Repositories\JournalRepository;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* This recalculates the balances on all of the journals
|
||||
*/
|
||||
class RecalculateBalances extends Listener
|
||||
{
|
||||
private $journalRepo;
|
||||
|
||||
/**
|
||||
* Nightly constructor.
|
||||
*
|
||||
* @param JournalRepository $journalRepo
|
||||
*/
|
||||
public function __construct(JournalRepository $journalRepo)
|
||||
{
|
||||
$this->journalRepo = $journalRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate all the balances for the different ledgers
|
||||
*
|
||||
* @param CronNightly $event
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
Log::info('Recalculating balances');
|
||||
|
||||
$journals = Journal::all();
|
||||
foreach ($journals as $journal) {
|
||||
$old_balance = $journal->balance;
|
||||
|
||||
$this->journalRepo->recalculateBalance($journal);
|
||||
$journal->refresh();
|
||||
|
||||
Log::info('Adjusting balance on '.
|
||||
$journal->morphed_type.':'.$journal->morphed_id
|
||||
.' from '.$old_balance.' to '.$journal->balance);
|
||||
}
|
||||
|
||||
Log::info('Done calculating balances');
|
||||
}
|
||||
}
|
||||
38
app/Cron/Nightly/RecalculateStats.php
Normal file
38
app/Cron/Nightly/RecalculateStats.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* This recalculates the balances on all of the journals
|
||||
*/
|
||||
class RecalculateStats extends Listener
|
||||
{
|
||||
private $userSvc;
|
||||
|
||||
public function __construct(UserService $userService)
|
||||
{
|
||||
$this->userSvc = $userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate the stats for active users
|
||||
*
|
||||
* @param CronNightly $event
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
Log::info('Recalculating balances');
|
||||
|
||||
$this->userSvc->recalculateAllUserStats();
|
||||
|
||||
Log::info('Done recalculating stats');
|
||||
}
|
||||
}
|
||||
97
app/Cron/Nightly/SetActiveFlights.php
Normal file
97
app/Cron/Nightly/SetActiveFlights.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Cron\Nightly;
|
||||
|
||||
use App\Contracts\Listener;
|
||||
use App\Events\CronNightly;
|
||||
use App\Models\Enums\Days;
|
||||
use App\Models\Flight;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Figure out what flights need to be active for today
|
||||
*/
|
||||
class SetActiveFlights extends Listener
|
||||
{
|
||||
/**
|
||||
* @param CronNightly $event
|
||||
*/
|
||||
public function handle(CronNightly $event): void
|
||||
{
|
||||
$this->checkFlights();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look through every single flight, check the start/end dates,
|
||||
* as well of the days of week if this flight is active on this day
|
||||
*
|
||||
* TODO: Option to check the flight active/inactive against departure TZ
|
||||
* TODO: Move to FlightService
|
||||
*/
|
||||
public function checkFlights(): void
|
||||
{
|
||||
$today = Carbon::now('UTC');
|
||||
$flights = Flight::all();
|
||||
|
||||
/**
|
||||
* @var Flight $flight
|
||||
*/
|
||||
foreach ($flights as $flight) {
|
||||
if (!$flight->active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// dates aren't set, so just save if there were any changes above
|
||||
// and move onto the next one
|
||||
if ($flight->start_date === null || $flight->end_date === null) {
|
||||
if ($flight->days !== null && $flight->days > 0) {
|
||||
$visible = Days::isToday($flight->days);
|
||||
if ($flight->visible !== $visible) {
|
||||
Log::info('Flight '.$flight->ident.' to '.($visible ? 'shown' : 'hidden'));
|
||||
|
||||
$flight->visible = $visible;
|
||||
if ($visible === false) {
|
||||
Log::info('Today='.date('N').', start=no, mask='.$flight->days.', in='
|
||||
.Days::in($flight->days, Days::$isoDayMap[(int) date('N')]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log::info('Toggling flight '.$flight->ident.' to visible');
|
||||
$flight->visible = true;
|
||||
}
|
||||
|
||||
$flight->save();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the day of week now first
|
||||
|
||||
// Start/end date is set, so make sure today is valid for it to be alive
|
||||
// and then make sure if days of the week are specified, check that too
|
||||
if ($today->gte($flight->start_date) && $today->lte($flight->end_date)) {
|
||||
if ($flight->days !== null && $flight->days > 0) {
|
||||
$visible = Days::isToday($flight->days);
|
||||
if ($flight->visible !== $visible) {
|
||||
Log::info('Toggling flight '.$flight->ident.' to '.($visible ? 'shown' : 'hidden').'');
|
||||
|
||||
$flight->visible = $visible;
|
||||
if ($visible === false) {
|
||||
Log::info('Today='.date('N').', start='.$flight->start_date
|
||||
.', end='.$flight->end_date.', mask='.$flight->days.', in='
|
||||
.Days::in($flight->days, Days::$isoDayMap[(int) date('N')]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log::info('Toggling flight '.$flight->ident.' to visible');
|
||||
$flight->visible = true;
|
||||
}
|
||||
} else {
|
||||
$flight->visible = false;
|
||||
Log::info('Toggling flight '.$flight->ident.' to hidden, outside of start/end boundary');
|
||||
}
|
||||
|
||||
$flight->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,20 @@ use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Acars::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => null,
|
||||
'pirep_id' => null,
|
||||
'log' => $faker->text(100),
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'heading' => $faker->numberBetween(0, 359),
|
||||
'altitude' => $faker->numberBetween(20, 400),
|
||||
'vs' => $faker->numberBetween(-5000, 5000),
|
||||
'gs' => $faker->numberBetween(300, 500),
|
||||
'id' => null,
|
||||
'pirep_id' => null,
|
||||
'log' => $faker->text(100),
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'distance' => $faker->randomFloat(2, 0, 6000),
|
||||
'heading' => $faker->numberBetween(0, 359),
|
||||
'altitude' => $faker->numberBetween(20, 400),
|
||||
'vs' => $faker->numberBetween(-5000, 5000),
|
||||
'gs' => $faker->numberBetween(300, 500),
|
||||
'transponder' => $faker->numberBetween(200, 9999),
|
||||
'autopilot' => $faker->text(10),
|
||||
'fuel_flow' => $faker->randomFloat(2, 100, 1000),
|
||||
'sim_time' => $faker->dateTime('now', 'UTC'),
|
||||
'autopilot' => $faker->text(10),
|
||||
'fuel' => $faker->randomFloat(2, 100, 1000),
|
||||
'fuel_flow' => $faker->randomFloat(2, 100, 1000),
|
||||
'sim_time' => $faker->dateTime('now', 'UTC'),
|
||||
];
|
||||
});
|
||||
|
||||
@@ -4,20 +4,23 @@ use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Aircraft::class, function (Faker $faker) {
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 100000),
|
||||
'subfleet_id' => function() {
|
||||
'id' => null,
|
||||
'subfleet_id' => function () {
|
||||
return factory(App\Models\Subfleet::class)->create()->id;
|
||||
},
|
||||
'airport_id' => function () {
|
||||
return factory(App\Models\Airport::class)->create()->id;
|
||||
},
|
||||
'icao' => $faker->unique()->text(5),
|
||||
'name' => $faker->unique()->text(50),
|
||||
'iata' => $faker->unique()->text(5),
|
||||
'icao' => $faker->unique()->text(5),
|
||||
'name' => $faker->text(50),
|
||||
'registration' => $faker->unique()->text(10),
|
||||
'tail_number' => $faker->unique()->text(10),
|
||||
'active' => true,
|
||||
'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
|
||||
'updated_at' => function (array $pirep) {
|
||||
'hex_code' => \App\Support\ICAO::createHexCode(),
|
||||
'zfw' => $faker->randomFloat(2, 0, 50000),
|
||||
'status' => \App\Models\Enums\AircraftStatus::ACTIVE,
|
||||
'state' => \App\Models\Enums\AircraftState::PARKED,
|
||||
'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
|
||||
'updated_at' => function (array $pirep) {
|
||||
return $pirep['created_at'];
|
||||
},
|
||||
];
|
||||
|
||||
@@ -3,20 +3,23 @@
|
||||
use Faker\Generator as Faker;
|
||||
use Hashids\Hashids;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Add any number of airports. Don't really care if they're real or not
|
||||
*/
|
||||
$factory->define(App\Models\Airline::class, function (Faker $faker) {
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 10000),
|
||||
'id' => null,
|
||||
'icao' => function (array $apt) use ($faker) {
|
||||
$hashids = new Hashids(microtime(), 5);
|
||||
$mt = str_replace('.', '', microtime(true));
|
||||
|
||||
return $hashids->encode($mt);
|
||||
},
|
||||
'iata' => function (array $apt) { return $apt['icao']; },
|
||||
'name' => $faker->sentence(3),
|
||||
'iata' => function (array $apt) {
|
||||
return $apt['icao'];
|
||||
},
|
||||
'name' => $faker->sentence(3),
|
||||
'country' => $faker->country,
|
||||
'active' => 1
|
||||
'active' => 1,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,37 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Hashids\Hashids;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Create an ICAO for use in the factory.
|
||||
*/
|
||||
if (!function_exists('createFactoryICAO')) {
|
||||
function createFactoryICAO(): string
|
||||
{
|
||||
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$max = strlen($characters) - 1;
|
||||
$string = '';
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
try {
|
||||
$string .= $characters[random_int(0, $max)];
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add any number of airports. Don't really care if they're real or not
|
||||
*/
|
||||
$factory->define(App\Models\Airport::class, function (Faker $faker) {
|
||||
$usedIcaos = [];
|
||||
|
||||
return [
|
||||
'id' => function(array $apt) use ($faker) {
|
||||
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
$string = '';
|
||||
$max = strlen($characters) - 1;
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$string .= $characters[random_int(0, $max)];
|
||||
}
|
||||
'id' => function () use ($usedIcaos) {
|
||||
do {
|
||||
$airport = createFactoryICAO();
|
||||
} while (in_array($airport, $usedIcaos, true));
|
||||
|
||||
return $string;
|
||||
#return $faker->unique()->text(5);
|
||||
/*$hashids = new Hashids(microtime(), 5);
|
||||
$mt = str_replace('.', '', microtime(true));
|
||||
return $hashids->encode($mt);*/
|
||||
return $airport;
|
||||
},
|
||||
'icao' => function(array $apt) { return $apt['id']; },
|
||||
'iata' => function (array $apt) { return $apt['id']; },
|
||||
'name' => $faker->sentence(3),
|
||||
'country' => $faker->country,
|
||||
'tz' => $faker->timezone,
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'fuel_100ll_cost' => $faker->randomFloat(2),
|
||||
'fuel_jeta_cost' => $faker->randomFloat(2),
|
||||
'fuel_mogas_cost' => $faker->randomFloat(2),
|
||||
'icao' => function (array $apt) {
|
||||
return $apt['id'];
|
||||
},
|
||||
'iata' => function (array $apt) {
|
||||
return $apt['id'];
|
||||
},
|
||||
'name' => $faker->sentence(3),
|
||||
'country' => $faker->country,
|
||||
'timezone' => $faker->timezone,
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'hub' => false,
|
||||
'ground_handling_cost' => $faker->randomFloat(2, 0, 500),
|
||||
'fuel_100ll_cost' => $faker->randomFloat(2, 1, 10),
|
||||
'fuel_jeta_cost' => $faker->randomFloat(2, 1, 10),
|
||||
'fuel_mogas_cost' => $faker->randomFloat(2, 1, 10),
|
||||
];
|
||||
});
|
||||
|
||||
13
app/Database/factories/AwardsFactory.php
Normal file
13
app/Database/factories/AwardsFactory.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Award::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => null,
|
||||
'name' => $faker->name,
|
||||
'description' => $faker->text(10),
|
||||
'ref_model' => null,
|
||||
'ref_model_params' => null,
|
||||
];
|
||||
});
|
||||
18
app/Database/factories/ExpenseFactory.php
Normal file
18
app/Database/factories/ExpenseFactory.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Enums\ExpenseType;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Expense::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => null,
|
||||
'airline_id' => null,
|
||||
'name' => $faker->text(20),
|
||||
'amount' => $faker->randomFloat(2, 100, 1000),
|
||||
'type' => ExpenseType::FLIGHT,
|
||||
'multiplier' => false,
|
||||
'ref_model' => \App\Models\Expense::class,
|
||||
'ref_model_id' => null,
|
||||
'active' => true,
|
||||
];
|
||||
});
|
||||
@@ -4,10 +4,13 @@ use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Fare::class, function (Faker $faker) {
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 10000),
|
||||
'code' => $faker->text(5),
|
||||
'name' => $faker->text(20),
|
||||
'id' => null,
|
||||
'code' => $faker->unique()->text(50),
|
||||
'name' => $faker->text(50),
|
||||
'price' => $faker->randomFloat(2, 100, 1000),
|
||||
'cost' => function (array $fare) {
|
||||
return round($fare['price'] / 2);
|
||||
},
|
||||
'capacity' => $faker->randomFloat(0, 20, 500),
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Create flights
|
||||
*/
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
# Match the list available in tests/data/*.yml
|
||||
|
||||
$airlinesAvailable = [1];
|
||||
|
||||
$factory->define(App\Models\Flight::class, function (Faker $faker) use ($airlinesAvailable) {
|
||||
$factory->define(App\Models\Flight::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => substr($faker->unique()->sha1, 28, 12),
|
||||
'airline_id' => $faker->randomElement($airlinesAvailable),
|
||||
'flight_number' => $faker->unique()->numberBetween(10, 1000000),
|
||||
'route_code' => $faker->randomElement(['', $faker->text(5)]),
|
||||
'route_leg' => $faker->randomElement(['', $faker->text(5)]),
|
||||
'dpt_airport_id' => function() {
|
||||
'id' => $faker->unique()->numberBetween(10, 10000000),
|
||||
'airline_id' => function () {
|
||||
return factory(App\Models\Airline::class)->create()->id;
|
||||
},
|
||||
'flight_number' => $faker->unique()->numberBetween(10, 1000000),
|
||||
'route_code' => $faker->randomElement(['', $faker->text(5)]),
|
||||
'route_leg' => $faker->randomElement(['', $faker->numberBetween(0, 1000)]),
|
||||
'dpt_airport_id' => function () {
|
||||
return factory(App\Models\Airport::class)->create()->id;
|
||||
},
|
||||
'arr_airport_id' => function () {
|
||||
@@ -22,15 +22,21 @@ $factory->define(App\Models\Flight::class, function (Faker $faker) use ($airline
|
||||
'alt_airport_id' => function () {
|
||||
return factory(App\Models\Airport::class)->create()->id;
|
||||
},
|
||||
'route' => $faker->randomElement(['', $faker->text(5)]),
|
||||
'dpt_time' => $faker->time(),
|
||||
'arr_time' => $faker->time(),
|
||||
'flight_time' => $faker->randomFloat(2),
|
||||
'has_bid' => false,
|
||||
'active' => true,
|
||||
'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
|
||||
'updated_at' => function (array $pirep) {
|
||||
return $pirep['created_at'];
|
||||
'distance' => $faker->numberBetween(1, 1000),
|
||||
'route' => null,
|
||||
'level' => 0,
|
||||
'dpt_time' => $faker->time(),
|
||||
'arr_time' => $faker->time(),
|
||||
'flight_time' => $faker->numberBetween(60, 360),
|
||||
'has_bid' => false,
|
||||
'active' => true,
|
||||
'visible' => true,
|
||||
'days' => 0,
|
||||
'start_date' => null,
|
||||
'end_date' => null,
|
||||
'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
|
||||
'updated_at' => static function (array $flight) {
|
||||
return $flight['created_at'];
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
9
app/Database/factories/JournalFactory.php
Normal file
9
app/Database/factories/JournalFactory.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Journal::class, function (Faker $faker) {
|
||||
return [
|
||||
'currency' => 'USD',
|
||||
];
|
||||
});
|
||||
17
app/Database/factories/JournalTransactionsFactory.php
Normal file
17
app/Database/factories/JournalTransactionsFactory.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\JournalTransactions::class, function (Faker $faker) {
|
||||
return [
|
||||
'transaction_group' => \Ramsey\Uuid\Uuid::uuid4()->toString(),
|
||||
'journal_id' => function () {
|
||||
return factory(App\Models\Journal::class)->create()->id;
|
||||
},
|
||||
'credit' => $faker->numberBetween(100, 10000),
|
||||
'debit' => $faker->numberBetween(100, 10000),
|
||||
'currency' => 'USD',
|
||||
'memo' => $faker->sentence(6),
|
||||
'post_date' => \Carbon\Carbon::now(),
|
||||
];
|
||||
});
|
||||
@@ -1,15 +1,15 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Enums\NavaidType;
|
||||
use Faker\Generator as Faker;
|
||||
use \App\Models\Enums\NavaidType;
|
||||
|
||||
$factory->define(App\Models\Navdata::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => str_replace(' ', '', str_replace('.', '', $faker->unique()->text(5))),
|
||||
'name' => $faker->unique()->text(10),
|
||||
'id' => str_replace(' ', '', str_replace('.', '', $faker->unique()->text(5))),
|
||||
'name' => str_replace('.', '', $faker->unique()->word),
|
||||
'type' => $faker->randomElement([NavaidType::VOR, NavaidType::NDB]),
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'lat' => $faker->latitude,
|
||||
'lon' => $faker->longitude,
|
||||
'freq' => $faker->randomFloat(2, 100, 1000),
|
||||
];
|
||||
});
|
||||
|
||||
14
app/Database/factories/NewsFactory.php
Normal file
14
app/Database/factories/NewsFactory.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\News::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => null,
|
||||
'user_id' => function () {
|
||||
return factory(App\Models\User::class)->create()->id;
|
||||
},
|
||||
'subject' => $faker->text(),
|
||||
'body' => $faker->sentence,
|
||||
];
|
||||
});
|
||||
@@ -1,58 +1,68 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Enums\PirepSource;
|
||||
use App\Models\Enums\PirepState;
|
||||
use App\Models\Enums\PirepStatus;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Create a new PIREP
|
||||
*/
|
||||
$factory->define(App\Models\Pirep::class, function (Faker $faker) {
|
||||
|
||||
static $raw_data;
|
||||
$airline = factory(App\Models\Airline::class)->create();
|
||||
$flight = factory(App\Models\Flight::class)->create([
|
||||
'airline_id' => $airline->id,
|
||||
]);
|
||||
|
||||
return [
|
||||
'id' => null,
|
||||
'airline_id' => function () { # OVERRIDE THIS IF NEEDED
|
||||
return factory(App\Models\Airline::class)->create()->id;
|
||||
'id' => $faker->unique()->numberBetween(10, 10000000),
|
||||
'airline_id' => function () use ($airline) {
|
||||
return $airline->id;
|
||||
},
|
||||
'user_id' => function () { # OVERRIDE THIS IF NEEDED
|
||||
'user_id' => function () {
|
||||
return factory(App\Models\User::class)->create()->id;
|
||||
},
|
||||
'aircraft_id' => function () {
|
||||
return factory(App\Models\Aircraft::class)->create()->id;
|
||||
},
|
||||
'flight_number' => function () {
|
||||
return factory(App\Models\Flight::class)->create()->flight_number;
|
||||
'flight_id' => function () use ($flight) {
|
||||
return $flight->id;
|
||||
},
|
||||
'route_code' => function(array $pirep) {
|
||||
//return App\Models\Flight::where(['flight_number' => $pirep['flight_number']])->first()->route_code;
|
||||
'flight_number' => function () use ($flight) {
|
||||
return $flight->flight_number;
|
||||
},
|
||||
'route_leg' => function (array $pirep) {
|
||||
//return App\Models\Flight::where('flight_number', $pirep['flight_number'])->first()->route_leg;
|
||||
'route_code' => null,
|
||||
'route_leg' => null,
|
||||
'dpt_airport_id' => function () use ($flight) {
|
||||
return $flight->dpt_airport_id;
|
||||
},
|
||||
'dpt_airport_id' => function () {
|
||||
return factory(App\Models\Airport::class)->create()->id;
|
||||
'arr_airport_id' => function () use ($flight) {
|
||||
return $flight->arr_airport_id;
|
||||
},
|
||||
'arr_airport_id' => function () {
|
||||
return factory(App\Models\Airport::class)->create()->id;
|
||||
'level' => $faker->numberBetween(20, 400),
|
||||
'distance' => $faker->randomFloat(2, 0, 6000),
|
||||
'planned_distance' => $faker->randomFloat(2, 0, 6000),
|
||||
'flight_time' => $faker->numberBetween(60, 360),
|
||||
'planned_flight_time' => $faker->numberBetween(60, 360),
|
||||
'zfw' => $faker->randomFloat(2),
|
||||
'block_fuel' => $faker->randomFloat(2, 0, 1000),
|
||||
'fuel_used' => function (array $pirep) {
|
||||
return round($pirep['block_fuel'] * .9, 2); // 90% of the fuel loaded was used
|
||||
},
|
||||
'level' => $faker->numberBetween(20, 400),
|
||||
'distance' => $faker->randomFloat(2),
|
||||
'planned_distance' => $faker->randomFloat(2),
|
||||
'flight_time' => $faker->randomFloat(2),
|
||||
'planned_flight_time' => $faker->randomFloat(2),
|
||||
'zfw' => $faker->randomFloat(2),
|
||||
'block_fuel' => $faker->randomFloat(2),
|
||||
'fuel_used' => $faker->randomFloat(2),
|
||||
'route' => $faker->text(200),
|
||||
'notes' => $faker->text(200),
|
||||
'source' => $faker->randomElement([PirepSource::MANUAL, PirepSource::ACARS]),
|
||||
'source_name' => 'Test Factory',
|
||||
'state' => PirepState::PENDING,
|
||||
'status' => PirepStatus::SCHEDULED,
|
||||
'raw_data' => $raw_data ?: $raw_data = json_encode(['key' => 'value']),
|
||||
'created_at' => Carbon::now()->toDateTimeString(),
|
||||
'updated_at' => function(array $pirep) {
|
||||
'block_on_time' => Carbon::now('UTC'),
|
||||
'block_off_time' => function (array $pirep) {
|
||||
return $pirep['block_on_time']->subMinutes($pirep['flight_time']);
|
||||
},
|
||||
'route' => $faker->text(200),
|
||||
'notes' => $faker->text(200),
|
||||
'source' => $faker->randomElement([PirepSource::MANUAL, PirepSource::ACARS]),
|
||||
'source_name' => 'TestFactory',
|
||||
'state' => PirepState::PENDING,
|
||||
'status' => PirepStatus::SCHEDULED,
|
||||
'submitted_at' => Carbon::now('UTC')->toDateTimeString(),
|
||||
'created_at' => Carbon::now('UTC')->toDateTimeString(),
|
||||
'updated_at' => function (array $pirep) {
|
||||
return $pirep['created_at'];
|
||||
},
|
||||
];
|
||||
|
||||
@@ -11,11 +11,13 @@ use Faker\Generator as Faker;
|
||||
*/
|
||||
$factory->define(App\Models\Rank::class, function (Faker $faker) {
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 10000),
|
||||
'name' => $faker->unique()->text(50),
|
||||
'hours' => $faker->numberBetween(10, 50),
|
||||
'auto_approve_acars' => 0,
|
||||
'auto_approve_manual' => 0,
|
||||
'auto_promote' => 0,
|
||||
'id' => null,
|
||||
'name' => $faker->unique()->text(50),
|
||||
'hours' => $faker->numberBetween(10, 50),
|
||||
'acars_base_pay_rate' => $faker->numberBetween(10, 100),
|
||||
'manual_base_pay_rate' => $faker->numberBetween(10, 100),
|
||||
'auto_approve_acars' => 0,
|
||||
'auto_approve_manual' => 0,
|
||||
'auto_promote' => 0,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -4,9 +4,12 @@ use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\Subfleet::class, function (Faker $faker) {
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 10000),
|
||||
'airline_id' => 1,
|
||||
'name' => $faker->unique()->text(50),
|
||||
'type' => $faker->unique()->text(7),
|
||||
'id' => null,
|
||||
'airline_id' => function () {
|
||||
return factory(App\Models\Airline::class)->create()->id;
|
||||
},
|
||||
'name' => $faker->unique()->text(50),
|
||||
'type' => $faker->unique()->text(7),
|
||||
'ground_handling_multiplier' => $faker->numberBetween(50, 200),
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
use App\Models\Enums\UserState;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\User::class, function (Faker $faker)
|
||||
{
|
||||
$factory->define(App\Models\User::class, function (Faker $faker) {
|
||||
static $password;
|
||||
|
||||
return [
|
||||
#'id' => $faker->unique()->numberBetween(10, 10000),
|
||||
'name' => $faker->name,
|
||||
'email' => $faker->safeEmail,
|
||||
'password' => $password ?: $password = Hash::make('secret'),
|
||||
'api_key' => $faker->sha1,
|
||||
'id' => null,
|
||||
'pilot_id' => 0,
|
||||
'name' => $faker->name,
|
||||
'email' => $faker->safeEmail,
|
||||
'password' => $password ?: $password = Hash::make('secret'),
|
||||
'api_key' => $faker->sha1,
|
||||
'airline_id' => function () {
|
||||
return factory(App\Models\Airline::class)->create()->id;
|
||||
},
|
||||
'rank_id' => 1,
|
||||
'flights' => $faker->numberBetween(0, 1000),
|
||||
'flight_time' => $faker->numberBetween(0, 10000),
|
||||
'transfer_time' => $faker->numberBetween(0, 10000),
|
||||
'state' => UserState::ACTIVE,
|
||||
'rank_id' => 1,
|
||||
'flights' => $faker->numberBetween(0, 1000),
|
||||
'flight_time' => $faker->numberBetween(0, 10000),
|
||||
'transfer_time' => $faker->numberBetween(0, 10000),
|
||||
'state' => UserState::ACTIVE,
|
||||
'remember_token' => $faker->unique()->text(5),
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use App\Services\Installer\SeederService;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateSettingsTable extends Migration
|
||||
{
|
||||
private $seederSvc;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->seederSvc = app(SeederService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -14,229 +22,23 @@ class CreateSettingsTable extends Migration
|
||||
{
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
$table->string('id');
|
||||
$table->unsignedInteger('offset')->default(0);
|
||||
$table->unsignedInteger('order')->default(99);
|
||||
$table->string('key');
|
||||
$table->string('name');
|
||||
$table->string('value');
|
||||
$table->string('default')->nullable();
|
||||
$table->string('group')->nullable();
|
||||
$table->string('type')->nullable();
|
||||
$table->string('options')->nullable();
|
||||
$table->text('options')->nullable();
|
||||
$table->string('description')->nullable();
|
||||
|
||||
$table->primary('id');
|
||||
$table->index('key');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
$this->addCounterGroups([
|
||||
'general' => 1,
|
||||
'flights' => 20,
|
||||
'finances' => 40,
|
||||
'bids' => 60,
|
||||
'pireps' => 80,
|
||||
'pilots' => 100,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Initial default settings
|
||||
*/
|
||||
$settings = [
|
||||
[
|
||||
'id' => $this->formatSettingId('general.start_date'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Start Date',
|
||||
'group' => 'general',
|
||||
'value' => '',
|
||||
'type' => 'date',
|
||||
'description' => 'The date your VA started',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.admin_email'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Admin Email',
|
||||
'group' => 'general',
|
||||
'value' => '',
|
||||
'type' => 'text',
|
||||
'description' => 'Email where notices, etc are sent',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.currency'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Currency to Use',
|
||||
'group' => 'general',
|
||||
'value' => 'dollar',
|
||||
'type' => 'select',
|
||||
'options' => 'dollar,euro,gbp,yen,jpy,rupee,ruble',
|
||||
'description' => 'Currency to show in the interface',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.distance_unit'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Distance Units',
|
||||
'group' => 'general',
|
||||
'value' => 'nm',
|
||||
'type' => 'select',
|
||||
'options' => 'km,mi,nm',
|
||||
'description' => 'The distance unit to show',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.weight_unit'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Weight Units',
|
||||
'group' => 'general',
|
||||
'value' => 'kg',
|
||||
'type' => 'select',
|
||||
'options' => 'lbs, kg',
|
||||
'description' => 'The weight unit',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.speed_unit'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Speed Units',
|
||||
'group' => 'general',
|
||||
'value' => 'Km/H',
|
||||
'type' => 'select',
|
||||
'options' => 'Km/H,kts',
|
||||
'description' => 'The speed unit',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.altitude_unit'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Altitude Units',
|
||||
'group' => 'general',
|
||||
'value' => 'ft',
|
||||
'type' => 'select',
|
||||
'options' => 'ft,m',
|
||||
'description' => 'The altitude units',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('general.liquid_unit'),
|
||||
'order' => $this->getNextOrderNumber('general'),
|
||||
'name' => 'Liquid Units',
|
||||
'group' => 'general',
|
||||
'value' => 'lbs',
|
||||
'type' => 'select',
|
||||
'options' => 'liters,gal,kg,lbs',
|
||||
'description' => 'The liquid units',
|
||||
],
|
||||
|
||||
/**
|
||||
* BIDS
|
||||
*/
|
||||
|
||||
[
|
||||
'id' => $this->formatSettingId('bids.disable_flight_on_bid'),
|
||||
'order' => $this->getNextOrderNumber('bids'),
|
||||
'name' => 'Disable flight on bid',
|
||||
'group' => 'bids',
|
||||
'value' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'When a flight is bid on, no one else can bid on it',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('bids.allow_multiple_bids'),
|
||||
'order' => $this->getNextOrderNumber('bids'),
|
||||
'name' => 'Allow multiple bids',
|
||||
'group' => 'bids',
|
||||
'value' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Whether or not someone can bid on multiple flights',
|
||||
],
|
||||
|
||||
/**
|
||||
* FINANCES
|
||||
*/
|
||||
|
||||
/**
|
||||
* PIREPS
|
||||
*/
|
||||
|
||||
[
|
||||
'id' => $this->formatSettingId('pireps.duplicate_check_time'),
|
||||
'order' => $this->getNextOrderNumber('pireps'),
|
||||
'name' => 'PIREP duplicate time check',
|
||||
'group' => 'pireps',
|
||||
'value' => 10,
|
||||
'default' => 10,
|
||||
'type' => 'int',
|
||||
'description' => 'The time in minutes to check for a duplicate PIREP',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('pireps.hide_cancelled_pireps'),
|
||||
'order' => $this->getNextOrderNumber('pireps'),
|
||||
'name' => 'Hide Cancelled PIREPs',
|
||||
'group' => 'pireps',
|
||||
'value' => true,
|
||||
'default' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Hide any cancelled PIREPs in the front-end',
|
||||
],
|
||||
|
||||
[
|
||||
'id' => $this->formatSettingId('pireps.restrict_aircraft_to_rank'),
|
||||
'order' => $this->getNextOrderNumber('pireps'),
|
||||
'name' => 'Restrict Aircraft to Ranks',
|
||||
'group' => 'pireps',
|
||||
'value' => true,
|
||||
'default' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Aircraft that can be flown are restricted to a user\'s rank',
|
||||
],
|
||||
|
||||
|
||||
/**
|
||||
* PILOTS
|
||||
*/
|
||||
|
||||
[
|
||||
'id' => $this->formatSettingId('pilots.id_length'),
|
||||
'order' => $this->getNextOrderNumber('pilots'),
|
||||
'name' => 'Pilot ID Length',
|
||||
'group' => 'pilots',
|
||||
'value' => 4,
|
||||
'default' => 4,
|
||||
'type' => 'int',
|
||||
'description' => 'The length of a pilot\'s ID',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('pilot.auto_accept'),
|
||||
'order' => $this->getNextOrderNumber('pilots'),
|
||||
'name' => 'Auto Accept New Pilot',
|
||||
'group' => 'pilots',
|
||||
'value' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Automatically accept a pilot when they register',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('pilots.only_flights_from_current'),
|
||||
'order' => $this->getNextOrderNumber('pilots'),
|
||||
'name' => 'Flights from Current',
|
||||
'group' => 'pilots',
|
||||
'value' => false,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Only show/allow flights from their current location',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('pilot.auto_leave_days'),
|
||||
'order' => $this->getNextOrderNumber('pilots'),
|
||||
'name' => 'Pilot to ON LEAVE days',
|
||||
'group' => 'pilots',
|
||||
'value' => 30,
|
||||
'default' => 30,
|
||||
'type' => 'int',
|
||||
'description' => 'Automatically set a pilot to ON LEAVE status after N days of no activity',
|
||||
],
|
||||
[
|
||||
'id' => $this->formatSettingId('pilots.hide_inactive'),
|
||||
'order' => $this->getNextOrderNumber('pilots'),
|
||||
'name' => 'Hide Inactive Pilots',
|
||||
'group' => 'pilots',
|
||||
'value' => true,
|
||||
'type' => 'boolean',
|
||||
'description' => 'Don\'t show inactive pilots in the public view',
|
||||
],
|
||||
];
|
||||
|
||||
$this->addData('settings', $settings);
|
||||
$this->seederSvc->syncAllSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
@@ -24,14 +24,16 @@ class CreateUsersTable extends Migration
|
||||
$table->string('country', 2)->nullable();
|
||||
$table->string('home_airport_id', 5)->nullable();
|
||||
$table->string('curr_airport_id', 5)->nullable();
|
||||
$table->string('last_pirep_id', 12)->nullable();
|
||||
$table->string('last_pirep_id', \App\Models\Pirep::ID_MAX_LENGTH)->nullable();
|
||||
$table->unsignedBigInteger('flights')->default(0);
|
||||
$table->unsignedBigInteger('flight_time')->nullable()->default(0);
|
||||
$table->unsignedBigInteger('transfer_time')->nullable()->default(0);
|
||||
$table->decimal('balance', 19)->nullable();
|
||||
$table->string('avatar')->nullable();
|
||||
$table->string('timezone', 64)->nullable();
|
||||
$table->unsignedTinyInteger('status')->nullable()->default(0);
|
||||
$table->unsignedTinyInteger('state')->nullable()->default(0);
|
||||
$table->boolean('toc_accepted')->nullable();
|
||||
$table->boolean('opt_in')->nullable();
|
||||
$table->boolean('active')->nullable();
|
||||
$table->ipAddress('last_ip')->nullable();
|
||||
$table->rememberToken();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class RolesPermissionsTables extends Migration
|
||||
@@ -8,7 +8,7 @@ class RolesPermissionsTables extends Migration
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
@@ -67,28 +67,22 @@ class RolesPermissionsTables extends Migration
|
||||
$table->primary(['permission_id', 'role_id']);
|
||||
});
|
||||
|
||||
# create a default user/role
|
||||
// create a default user/role
|
||||
$roles = [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => 'admin',
|
||||
'id' => 1,
|
||||
'name' => 'admin',
|
||||
'display_name' => 'Administrators',
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'user',
|
||||
'display_name' => 'Pilot'
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
$this->addData('roles', $roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePasswordResetsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSessionsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateAirlinesTable extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use \App\Models\Enums\AircraftState;
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use App\Models\Enums\AircraftState;
|
||||
use App\Models\Enums\AircraftStatus;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateAircraftsTable extends Migration
|
||||
@@ -13,22 +13,21 @@ class CreateAircraftsTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('subfleet_id');
|
||||
$table->string('icao', 4)->nullable();
|
||||
$table->string('iata', 4)->nullable();
|
||||
$table->string('airport_id', 5)->nullable();
|
||||
$table->timestamp('landing_time')->nullable();
|
||||
$table->string('hex_code', 10)->nullable();
|
||||
$table->string('name', 50);
|
||||
$table->string('registration', 10)->nullable();
|
||||
$table->string('tail_number', 10)->nullable();
|
||||
$table->unsignedDecimal('zfw', 12)->nullable()->default(0);
|
||||
$table->string('hex_code', 10)->nullable();
|
||||
$table->unsignedDecimal('zfw')->nullable()->default(0);
|
||||
$table->unsignedBigInteger('flight_time')->nullable()->default(0);
|
||||
$table->boolean('active')->default(true);
|
||||
$table->char('status', 1)->default(AircraftStatus::ACTIVE);
|
||||
$table->unsignedTinyInteger('state')->default(AircraftState::PARKED);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique('registration');
|
||||
$table->index('airport_id');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateFaresTable extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -15,10 +14,10 @@ class CreateFaresTable extends Migration
|
||||
{
|
||||
Schema::create('fares', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('code', 50);
|
||||
$table->string('code', 50)->unique();
|
||||
$table->string('name', 50);
|
||||
$table->unsignedDecimal('price', 19)->nullable()->default(0.00);
|
||||
$table->unsignedDecimal('cost', 19)->nullable()->default(0.00);
|
||||
$table->unsignedDecimal('price')->nullable()->default(0.00);
|
||||
$table->unsignedDecimal('cost')->nullable()->default(0.00);
|
||||
$table->unsignedInteger('capacity')->nullable()->default(0);
|
||||
$table->string('notes')->nullable();
|
||||
$table->boolean('active')->default(true);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Contracts\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateAirportsTable extends Migration
|
||||
@@ -8,19 +8,24 @@ class CreateAirportsTable extends Migration
|
||||
public function up()
|
||||
{
|
||||
Schema::create('airports', function (Blueprint $table) {
|
||||
$table->string('id', 5)->primary();
|
||||
$table->string('iata', 5)->nullable();
|
||||
$table->string('icao', 5);
|
||||
$table->string('id', 4)->primary();
|
||||
$table->string('iata', 4)->nullable();
|
||||
$table->string('icao', 4);
|
||||
$table->string('name', 100);
|
||||
$table->string('location', 100)->nullable();
|
||||
$table->string('country', 64)->nullable();
|
||||
$table->string('tz', 64)->nullable();
|
||||
$table->string('timezone', 64)->nullable();
|
||||
$table->boolean('hub')->default(false);
|
||||
$table->unsignedDecimal('fuel_100ll_cost', 8)->nullable()->default(0);
|
||||
$table->unsignedDecimal('fuel_jeta_cost', 8)->nullable()->default(0);
|
||||
$table->unsignedDecimal('fuel_mogas_cost', 8)->nullable()->default(0);
|
||||
$table->float('lat', 7, 4)->nullable()->default(0.0);
|
||||
$table->float('lon', 7, 4)->nullable()->default(0.0);
|
||||
$table->unsignedDecimal('ground_handling_cost')->nullable()->default(0);
|
||||
$table->unsignedDecimal('fuel_100ll_cost')->nullable()->default(0);
|
||||
$table->unsignedDecimal('fuel_jeta_cost')->nullable()->default(0);
|
||||
$table->unsignedDecimal('fuel_mogas_cost')->nullable()->default(0);
|
||||
|
||||
$table->index('icao');
|
||||
$table->index('iata');
|
||||
$table->index('hub');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user