forked from kevinowino869/mitrobill
Compare commits
853 Commits
Author | SHA1 | Date | |
---|---|---|---|
5a2e75017e | |||
609a24df80 | |||
31dda69d3d | |||
d60b1827d9 | |||
1e43ac210a | |||
9bf80467a1 | |||
093ac7e336 | |||
a67681424e | |||
7799bf1aee | |||
3502be2c78 | |||
f6084f6ca4 | |||
123b74001a | |||
a39bbc3b34 | |||
a15f759dcb | |||
883eb1bbee | |||
8af46e5e51 | |||
1f1e529e3a | |||
bed81136a1 | |||
f322282c6d | |||
396ece50f4 | |||
681d0214c8 | |||
c7d9f8e8c6 | |||
4dd190a61d | |||
88bb3a29f1 | |||
5e8414aa61 | |||
01e832a955 | |||
ada655a074 | |||
3f3435157c | |||
ec6d6cf203 | |||
7026438acc | |||
8a6ee9490b | |||
89808f3291 | |||
8f6bc9f66e | |||
87ebabe1c0 | |||
bf95713512 | |||
0f19c80cfc | |||
b232ccddbf | |||
f4944866a4 | |||
61fafcd5cf | |||
0b2a9bac21 | |||
cbc66fa470 | |||
e2f2146f1e | |||
0dc50a68f5 | |||
690e5912c0 | |||
0e302a5171 | |||
45e2bb5a96 | |||
9aff4dbf26 | |||
0eb900ffd6 | |||
73e85a97ce | |||
da84015aab | |||
754b23b53f | |||
f997ecc702 | |||
5b7ffec115 | |||
1cbdf5a9b2 | |||
273b6d80c2 | |||
1a5a7124f7 | |||
4fe0e8d58c | |||
bbdf561b3b | |||
96fccecbcf | |||
0780438ca8 | |||
cfe0a14f31 | |||
b1e145f0dc | |||
357b7932e9 | |||
b3f6417bbe | |||
051a8de5f2 | |||
1a931ef617 | |||
c5907c194b | |||
1906b1aefd | |||
62c447da9b | |||
51b68b648c | |||
86407f731b | |||
d2d52d0ad0 | |||
c527f1cc7c | |||
47469df558 | |||
c5fd7c0249 | |||
1ea971d3f5 | |||
7d5e0c7a8e | |||
cf6f89b3f2 | |||
2dc50c3637 | |||
da0ca4f087 | |||
486c849eee | |||
c7a09c60cb | |||
fce910455a | |||
ade4e22454 | |||
487d31358d | |||
daf1bb7d67 | |||
7c547c967e | |||
2e61c89d89 | |||
27c736fa69 | |||
b3fd1d5a3e | |||
5d492def3c | |||
0dfa412be8 | |||
c6cb63a1c5 | |||
32418f05fb | |||
3c1d8dbb8a | |||
67a097fddf | |||
e03b250fb7 | |||
8a36746a0f | |||
fd920748be | |||
e32e0aba16 | |||
98589cd283 | |||
fd20ede7aa | |||
226ed41075 | |||
9ec090a621 | |||
c8d5861f2e | |||
92491e22ec | |||
f9e7a8dbb4 | |||
5559069aac | |||
d6144537c4 | |||
04742535ba | |||
f76753b247 | |||
e4f209030f | |||
5c54223454 | |||
13a2de2664 | |||
538cf4e675 | |||
9edb0b4d2f | |||
d0a7f2b991 | |||
f4c15c3475 | |||
50dd4b4839 | |||
1d7dca8ada | |||
694b4d7bac | |||
82dce56209 | |||
b2ac84900e | |||
16de814091 | |||
4ce4633999 | |||
5788c9c0a7 | |||
7acab4d50e | |||
79d0921ebe | |||
77d25738b1 | |||
b34b9064d0 | |||
13adfc8254 | |||
73b829b8c1 | |||
91e7caae80 | |||
40a39f0ced | |||
699ffc1302 | |||
5e2eaa5578 | |||
38f6738c45 | |||
63e564c9dd | |||
27a5d2d45a | |||
153da7c63b | |||
c9778e71b9 | |||
eb970b257a | |||
242dda2e99 | |||
5445aedcd1 | |||
3f77dcf129 | |||
357df8d986 | |||
16199b4c18 | |||
318b52905d | |||
581b765c28 | |||
c3355ad8f7 | |||
5bb724b9b3 | |||
e431f07a71 | |||
b5efe81637 | |||
c827c983ce | |||
a81ddd68dd | |||
9c06225cc2 | |||
6a5fd9d11a | |||
d20fea1cdf | |||
3bd8ebdc76 | |||
8dcd00bc6b | |||
56ddf65fdf | |||
a2347dd241 | |||
b316e4a242 | |||
2b7361cf6b | |||
5ccddf11be | |||
dbf1623ca6 | |||
e17f07f410 | |||
23bba0b189 | |||
167732094b | |||
9569847612 | |||
4c1f49ea81 | |||
b7fdc90aa7 | |||
fec7780f50 | |||
7d24b719b5 | |||
a34f1bb0fc | |||
2863d70214 | |||
949a3d27eb | |||
1b7f449d96 | |||
0295ab44e5 | |||
7f35e7fb68 | |||
b28b40280f | |||
35243cb9b0 | |||
de4c6c730f | |||
53b64548fc | |||
bf11fd2f2c | |||
e0f150633c | |||
06c68ccebd | |||
6db2f2bf0d | |||
32a64d944a | |||
1903dc6b45 | |||
27bd2590f2 | |||
8908f4bdc3 | |||
7fb08eb76f | |||
8a0c17b319 | |||
afbb39b1d9 | |||
7006ad8c40 | |||
99b30f747f | |||
1f1430fd21 | |||
93583afb65 | |||
9779d77f22 | |||
3dfb12d830 | |||
6e446192d8 | |||
51811bd753 | |||
db8affce1f | |||
c740820731 | |||
80e0dc6485 | |||
5552fb20d5 | |||
f08211a83a | |||
71d6024d62 | |||
73993c4f25 | |||
25be52fe9c | |||
5d79f9d842 | |||
70d8cd8e01 | |||
df7293e3d0 | |||
7614422bd8 | |||
5ff9c74f63 | |||
8fdbe0ec1d | |||
e4fb835f2c | |||
d69086d99b | |||
dc42a09685 | |||
08b2e16e73 | |||
8e41749cd4 | |||
383a1e55d7 | |||
3778499611 | |||
fda935b3a6 | |||
d5c2c72a74 | |||
0df7027851 | |||
00081d40e5 | |||
01c2808e43 | |||
e02bf9863f | |||
7f72b0c34a | |||
a04c3dd82b | |||
1a0b3ffaf3 | |||
3ddfc92b18 | |||
9de7a07de4 | |||
52f65ec143 | |||
e8a800bbd6 | |||
36162381cb | |||
d14599f720 | |||
244e552eb6 | |||
6bb9b001dc | |||
7c42ab5b89 | |||
717f29c95d | |||
ee52a2ec1e | |||
2b3d3a6796 | |||
859e0ce6af | |||
8c5ed98f09 | |||
8347a982c5 | |||
60188c736b | |||
ba729f44fc | |||
954a892f86 | |||
fe41b92a7c | |||
b835520ccf | |||
3adfd2f2c3 | |||
434d7d8cf9 | |||
c617bb9a4d | |||
853af04362 | |||
d8894ab296 | |||
0c2249daf9 | |||
e7f4c88648 | |||
da541595a4 | |||
495da312a8 | |||
71cc8290a3 | |||
575ef1c117 | |||
bcb39f114a | |||
544706d82e | |||
6f4f788d8f | |||
0f59250215 | |||
bcff2253ee | |||
676caec8ca | |||
9d6cd6756c | |||
b375460789 | |||
b7aee6f91c | |||
b4907ed661 | |||
44d091cae8 | |||
766c2c268e | |||
14f9559033 | |||
53885a6f7d | |||
46a83d4e30 | |||
b313f1de36 | |||
a6df867ca1 | |||
7339be29f8 | |||
8ae88adc17 | |||
c960baaf1f | |||
5e310cba29 | |||
eb1d804a4d | |||
6ffa396b05 | |||
cd5f9101f2 | |||
f8878ad8b6 | |||
dc55957a53 | |||
bdda199523 | |||
8086802bf6 | |||
53aa187d1f | |||
7685323bd6 | |||
1fe2dac580 | |||
0428d9620e | |||
ad862640cc | |||
a4e8ae8c5c | |||
d4c34afb8d | |||
0dc4d22da3 | |||
169a7afe67 | |||
67890881f3 | |||
3febb60253 | |||
005155e2a5 | |||
f8a15e4754 | |||
f0da633808 | |||
5f6b14ab7e | |||
3475a6086d | |||
49f194a7f2 | |||
b3744a5007 | |||
234e5e3967 | |||
97296abf06 | |||
a7232e2b92 | |||
7c0bdeea41 | |||
5566a7ebb5 | |||
de49a9992f | |||
0cf5483353 | |||
b15fdf1d6a | |||
ca98ca2223 | |||
5ccb8520d3 | |||
ff4e620b75 | |||
1b7e5c7510 | |||
084cc0e0fb | |||
25d9524f53 | |||
4308765bec | |||
70dbe59319 | |||
577ed31f57 | |||
064e4c80ed | |||
70bcff7679 | |||
47b729867d | |||
696b2e4789 | |||
0f0929db2a | |||
7267bd082a | |||
d5cba4b3c1 | |||
155b2959b5 | |||
a35137b7ab | |||
83dd564e53 | |||
8e8a52d807 | |||
5bc273a9dd | |||
f9fe261e55 | |||
0dc79cd5c4 | |||
b32e2901af | |||
f77d7051c1 | |||
60e1eacc59 | |||
82ffc15c03 | |||
6e5450d104 | |||
6458b792f6 | |||
6be0da383c | |||
534886f8f3 | |||
c9b9808112 | |||
e737ae9d29 | |||
78e3f2e8fb | |||
3eaa302128 | |||
9bc3ccc02b | |||
99e8b20bb3 | |||
bd30261e84 | |||
96365eef2a | |||
c08c069479 | |||
71d653f3d1 | |||
b1919555e5 | |||
2522f3112e | |||
ba63face92 | |||
8f78f5184e | |||
e9ae2e04ce | |||
56c69122e4 | |||
2198c00d52 | |||
695b3c7a6f | |||
f7cb6c196f | |||
5adb09efcf | |||
e70a6c4dae | |||
4f3647beae | |||
9016ecbb98 | |||
277ab87645 | |||
3a929c5418 | |||
2771eba0ee | |||
5b51af1b6e | |||
05eab22062 | |||
d4eaaad535 | |||
3407571474 | |||
da1341d971 | |||
e4e70c5104 | |||
fbde8b0056 | |||
9552783eee | |||
44f852ab2f | |||
3da0c356de | |||
d2db2bef79 | |||
44af731c4c | |||
0a9733b0b3 | |||
79c25a64d6 | |||
e4d3aff618 | |||
6462572fb8 | |||
a51462ef1a | |||
4ffbac878c | |||
3a2c55e0d8 | |||
229eae5c8f | |||
aa0432df38 | |||
8e3a16a123 | |||
aa1ef2c41c | |||
4567f82a06 | |||
ce61df9057 | |||
6a24c6c11e | |||
b1ad007db0 | |||
bfd014417b | |||
9b1adb15da | |||
686d2a188a | |||
1a65c04666 | |||
7e9f6123e8 | |||
f738c9b120 | |||
5f7f785d99 | |||
c0c54ce767 | |||
f81f3df700 | |||
3c6ef3bcf3 | |||
985ddda41f | |||
a31286d781 | |||
c2916da215 | |||
82569239e2 | |||
bc0b3abe92 | |||
f5d9649f97 | |||
095e8937a2 | |||
5f50d725f1 | |||
68de3a71b9 | |||
fe532a6238 | |||
05b681df47 | |||
723e99ebed | |||
13aabeea8e | |||
400672454c | |||
aa3e522bc9 | |||
b7fce955ac | |||
594fab1151 | |||
3aead7a98a | |||
9a1321f597 | |||
45bb3f04ee | |||
0d2b140bcf | |||
f736868819 | |||
84bc680f40 | |||
53512cfa58 | |||
d0e66d8651 | |||
c45ea74a29 | |||
22615eb278 | |||
ae550df078 | |||
cc74667451 | |||
0fec69df89 | |||
36b4a282ee | |||
cb5ffb4236 | |||
2328489a14 | |||
f8351e46f6 | |||
cf9a11ef94 | |||
80d4c904d0 | |||
9e63d7ce20 | |||
b517ef2b73 | |||
ea0c663278 | |||
299fd90949 | |||
c255a7be49 | |||
4f74aa0bff | |||
93d53cc6d8 | |||
40f452cff8 | |||
aa787af017 | |||
af753d3a52 | |||
d060e21032 | |||
f43a2dcd7a | |||
0b5bc1fe71 | |||
4f969c787a | |||
087ce1d0b6 | |||
d7d76dde94 | |||
7cbb874029 | |||
44fe6a0ff7 | |||
74ec6128ab | |||
899c27f1a7 | |||
f7a86666c2 | |||
a22e2e1b2c | |||
cc6babf04a | |||
9e7698f83d | |||
e1008ae61f | |||
ef0d19393f | |||
8e2a40d670 | |||
34482ff0d4 | |||
35ace619d2 | |||
6da6041cb8 | |||
463ee27116 | |||
fe930a1012 | |||
abd22418ce | |||
9099584d7c | |||
5a84e10b70 | |||
89786c64af | |||
e7ec68872b | |||
82d756567e | |||
9436a6e8f1 | |||
e8885e91ec | |||
8e96f1457a | |||
2a2e9c3bd4 | |||
b8e856518f | |||
4e19894152 | |||
414f9929e5 | |||
5bcf278733 | |||
453ea564cf | |||
a167d97e3c | |||
55349b40dd | |||
bac8819c31 | |||
aaeaa9305a | |||
f37987a4c6 | |||
393939fab4 | |||
0189234b56 | |||
8d4d88f702 | |||
5d79cb65ce | |||
1d08e8d204 | |||
afaafd6195 | |||
bd9989eaf2 | |||
ea814dcaf8 | |||
11ec4185e7 | |||
7963c2f388 | |||
9b418ed078 | |||
d31274b983 | |||
9772760146 | |||
7e8913f0b4 | |||
2cf0981030 | |||
ca26f8baa6 | |||
d99a51d40e | |||
20e212eaa6 | |||
00f65c6aab | |||
dcaa7f9cea | |||
1bbc7a30f0 | |||
e8526e294a | |||
554479b79b | |||
edfa98e6b2 | |||
079b308bf1 | |||
76ac9431b3 | |||
86b441f41f | |||
1a70e2232c | |||
e31aeca2dd | |||
502a0a2b0c | |||
e78a1ca15e | |||
b9c31a856e | |||
4889853e53 | |||
178dad8e03 | |||
50a3f0a175 | |||
2f85240689 | |||
9e917536c0 | |||
1d5341cdfe | |||
73e070b3ed | |||
d34f6919c7 | |||
1e8cf726c3 | |||
71f0fc47a6 | |||
c188a8a91d | |||
c57cdad9cf | |||
2385d5f4c0 | |||
7b2acec181 | |||
04bc749eae | |||
b2d9c13c51 | |||
9ca0b3907c | |||
9f2f739ba6 | |||
cde2706c04 | |||
0265304069 | |||
9955c89024 | |||
7d4ca685bd | |||
e95d5611f9 | |||
d6184f7be2 | |||
1d993795d2 | |||
0b84d54ef2 | |||
81e30f0c54 | |||
34af35f0e1 | |||
244f477f27 | |||
34f904ccc4 | |||
8c206ba1f8 | |||
be3db52578 | |||
342fbe25a8 | |||
55232ac4b3 | |||
7172cfbb79 | |||
0bb1f8ffa0 | |||
61ac04d62c | |||
f53e60161a | |||
49a3d363cb | |||
e15faf605d | |||
0617fd4cc8 | |||
803c85c6f4 | |||
f0f9daf72a | |||
d152124eea | |||
e54e5641e6 | |||
a265b6e766 | |||
e21b766a7a | |||
c4281f1d54 | |||
505bb1dd71 | |||
b0b687dd38 | |||
95620da151 | |||
26d14794e2 | |||
8bf5c71800 | |||
dc78167bcb | |||
57ce1c816c | |||
ca2df9c02e | |||
ae8815c668 | |||
0a66553112 | |||
be33c6ae01 | |||
ad14ef58ca | |||
e94d3cdb4a | |||
4b29fab73f | |||
267095d68b | |||
1c2f9ddca5 | |||
83efa89dfc | |||
3e0b8b66f8 | |||
31253fd14d | |||
a1ec9e8040 | |||
0d97d0d753 | |||
d4584e6288 | |||
2f9780cf62 | |||
04bb8dca9a | |||
8c5f4bd9dc | |||
c1d93f1fe2 | |||
8e9aeec517 | |||
02e1989745 | |||
14c4ab8fbc | |||
24e49e4eb9 | |||
75907d5c3f | |||
a96f808318 | |||
7643b24f31 | |||
1801b5b436 | |||
aeeb9a2b63 | |||
e36db6d16c | |||
ee7aa60979 | |||
34ea48fd7d | |||
1d4eff11ba | |||
c41fe7435f | |||
d0b60d5e7d | |||
c6346aabc3 | |||
49f3c1a141 | |||
e4c8be2c16 | |||
fa27ccf5ca | |||
5ae4dde522 | |||
b7d88e9b8d | |||
d83c2ec037 | |||
e908ade918 | |||
d11cd83089 | |||
df5e03a827 | |||
0d966a5e03 | |||
da985f27e1 | |||
a67943c75f | |||
cb3caef529 | |||
08c7de1559 | |||
b8a02bb837 | |||
ef6672d786 | |||
3c094e7674 | |||
f92e9612b5 | |||
5e43fe3882 | |||
cc2589e9f5 | |||
6c113b5b6d | |||
66f0390288 | |||
1e0036465f | |||
be0bbcb570 | |||
fdaa87d02c | |||
9f997ec68f | |||
147e0f5d92 | |||
7d9a4623b1 | |||
6dc957e34a | |||
92c6022c85 | |||
85bebebb3a | |||
1b56680a6d | |||
eb5d1f5819 | |||
1c8e2c0422 | |||
cf4f708f83 | |||
1c82378837 | |||
04321c9e4b | |||
887d0566bc | |||
b36e96b9fc | |||
5c30be70c0 | |||
03497cb289 | |||
5242b19f6f | |||
5070cd9ed7 | |||
74e806886c | |||
d8a91ebda9 | |||
edae267a39 | |||
eaa982c5c3 | |||
0eead7cea1 | |||
19ea56df3f | |||
c158d49965 | |||
73aa663b25 | |||
a4303a4804 | |||
d496d89f95 | |||
70eea6dd37 | |||
6740b0212d | |||
960d141246 | |||
7af2c57703 | |||
768e2f203d | |||
a06735faaa | |||
5de893d16d | |||
ebb41f114a | |||
02024fdcc7 | |||
e96a9677bc | |||
21f930dfa3 | |||
4f6339330f | |||
86bd2a8dd4 | |||
c548f8e307 | |||
8b26374000 | |||
30554983ec | |||
1c0cc75417 | |||
63c1d4ca76 | |||
3894a54b96 | |||
a1bae5c7a5 | |||
4d7db37edc | |||
fd58188771 | |||
e85ad38d1d | |||
fa5a42fc0c | |||
625254852d | |||
6b39863418 | |||
d52f751997 | |||
7564b8f244 | |||
522d05f53c | |||
765d2d91da | |||
f238bf7a76 | |||
62867c0559 | |||
cf3209b3e8 | |||
5cb1a901c3 | |||
676dcbe478 | |||
ef53835fbf | |||
e8104b87e6 | |||
baab016135 | |||
6f8ec3caeb | |||
b3bd0c31e4 | |||
b4a37a4722 | |||
68959b5a2e | |||
b9fc39a148 | |||
ced0d487e7 | |||
9fc4dfa94d | |||
afa0616487 | |||
0fae434c1b | |||
0fa78966ef | |||
5e080f18fe | |||
6765a6b17c | |||
3f7c17d9b1 | |||
4d7c2bd373 | |||
2b104d2ed7 | |||
6666fd0ed4 | |||
b8f15992d1 | |||
b7b23fc39a | |||
c7e1dc963f | |||
8adf41bf75 | |||
85ede07d77 | |||
3f5ea7251e | |||
af157cdff9 | |||
d39af7d404 | |||
c26f08e5c9 | |||
c1588d88c3 | |||
d19cdf3897 | |||
7fccf95eb0 | |||
630f20094a | |||
9ad9ba45b1 | |||
d830ba4e06 | |||
ce7d8859b0 | |||
bbed893759 | |||
70de538f38 | |||
3d127b6f54 | |||
51c594b8d6 | |||
b24ad24e89 | |||
f1a9ad6d63 | |||
e5ff8c5675 | |||
3c218d9ec9 | |||
cf04a50c35 | |||
d35c7080d9 | |||
9720822c79 | |||
dc4adbc0c6 | |||
6316992bc3 | |||
668c7af1e9 | |||
8c00496a5b | |||
da3ef535a2 | |||
bf71393fff | |||
a242d3b98b | |||
3b8a5ad2dc | |||
3ca43c69a8 | |||
cb0e77523d | |||
8ab1939dd9 | |||
a3c255e77a | |||
2a7563f43d | |||
95899b4eba | |||
5d6a06b6fa | |||
7a95d79315 | |||
096d3ea56d | |||
a09bfc01bf | |||
271dd2934a | |||
ce47ee1533 | |||
0214b6436d | |||
810c5ae827 | |||
bcdad02274 | |||
d138e1b36f | |||
7d2f69f96f | |||
46a4c5f24d | |||
509658be9c | |||
9f96da34b5 | |||
be507a013a | |||
150f9a5c41 | |||
e9daa2e5e7 | |||
fc1173c534 | |||
a632bac3a6 | |||
8358e8b885 | |||
01b3b66e3d | |||
1065bfc017 | |||
dec4258a6f | |||
f5042cc665 | |||
084ee83ec3 | |||
587437c93c | |||
1843ff222d | |||
de85d30a9e | |||
82904b9302 | |||
face1dfa57 | |||
7e5a718ba8 | |||
c2fffdab88 | |||
9578006e11 | |||
828ad7f880 | |||
ed4bd4861a | |||
b64e841bde | |||
efdb0fc6bc | |||
0b5c24239d | |||
a5971bfff3 | |||
aac8306d7b | |||
721ef32e12 | |||
67e383375e | |||
4434e7d217 | |||
fc6cd59ea0 | |||
608c9e5b6f | |||
d494df3321 | |||
9ec0148800 | |||
deb6cceeb9 | |||
210178be84 | |||
063ae834bc | |||
4c65248823 | |||
c417fe63e2 | |||
6ca5054fe8 | |||
0bcac10eec | |||
ada529ce97 | |||
8e55330bcb | |||
eca40e0faf | |||
8e1d608e5f | |||
50b4db1723 | |||
b3e97ecf6d | |||
a85e9ee95a | |||
fa154b007f | |||
3b9c5d16f8 | |||
dd7f9dc94e | |||
2a9b50e015 | |||
1c0ff671a5 | |||
bd48bb0591 | |||
278def959b | |||
5a47da013b | |||
282bf6190c | |||
2f1ee0cfbf | |||
5783ea05f9 | |||
5ca81ea92e | |||
6496f49df6 | |||
7d3afa091f | |||
cc68770f51 | |||
20f98ab066 | |||
1697f18986 | |||
c711f82bba | |||
2727d53d62 | |||
e68b5555ab | |||
4b6204391b | |||
570c93d4a4 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -46,9 +46,11 @@ system/devices/**
|
||||
!system/devices/Radius.php
|
||||
!system/devices/RadiusRest.php
|
||||
!system/devices/MikrotikPppoe.php
|
||||
!system/devices/MikrotikPppoeCustom.php
|
||||
!system/devices/MikrotikHotspot.php
|
||||
/.vs
|
||||
docker-compose.yml
|
||||
docs/**
|
||||
!docs/*.html
|
||||
!docs/*.md
|
||||
!docs/*.md
|
||||
.htaccess
|
@ -11,4 +11,17 @@
|
||||
<Files update.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
</Files>
|
||||
|
||||
<Files radius.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
|
||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
|
||||
RewriteRule ^(.*)$ index.php [QSA,L]
|
93
CHANGELOG.md
93
CHANGELOG.md
@ -2,6 +2,99 @@
|
||||
|
||||
# CHANGELOG
|
||||
|
||||
## 2024.10.23
|
||||
|
||||
- Custom Balance admin refill Requested by Javi Tech
|
||||
- Only Admin can edit Customer Requested by Fiberwan
|
||||
- Only Admin can show password Requested by Fiberwan
|
||||
|
||||
## 2024.10.18
|
||||
|
||||
- Single Session Admin Can be set in the Settings
|
||||
- Auto expired unpaid transaction
|
||||
- Registration Type
|
||||
- Can Login as User from Customer View
|
||||
- Can select customer register must using OTP or not
|
||||
- Add Meta.php for additional information
|
||||
|
||||
## 2024.10.15
|
||||
|
||||
- CSRF Security
|
||||
- Admin can only have 1 active session
|
||||
- Move Miscellaneous Settings to new page
|
||||
- Fix Customer Online
|
||||
- Count Shared user online for Radius REST
|
||||
- Fix Invoice Print
|
||||
|
||||
## 2024.10.7
|
||||
|
||||
- Show Customer is Online or not
|
||||
- Change Invoice Theme for printing
|
||||
- Rearange Customer View
|
||||
|
||||
## 2024.9.23
|
||||
|
||||
- Discount Price
|
||||
- Burst Preset
|
||||
|
||||
## 2024.9.20
|
||||
|
||||
- Forgot Password
|
||||
- Forgot Username
|
||||
- Public header template
|
||||
|
||||
## 2024.9.13
|
||||
|
||||
- Add Selling Mikrotik VPN By @agstrxyz
|
||||
- Theme Redesign by @Focuslinkstech
|
||||
- Fix That and this
|
||||
|
||||
|
||||
## 2024.8.28
|
||||
|
||||
- add Router Status Offline/Online by @Focuslinkstech
|
||||
- Show Router Offline in the Dashbord
|
||||
- Fix Translation by by @ahmadhusein17
|
||||
- Add Payment Info Page, to show to customer before buy
|
||||
- Voucher Template
|
||||
- Change Niceedit to summernote
|
||||
- Customer can change their language by @Focuslinkstech
|
||||
- Fix Voucher case sensitive
|
||||
- 3 Tabs Plugin Manager
|
||||
|
||||
## 2024.8.19
|
||||
|
||||
- New Page, Payment Info, To Inform Customer, which payment gateway is good
|
||||
- Move Customer UI to user-ui folder
|
||||
- Voucher Template
|
||||
- Change editor to summernote
|
||||
- Customer can change language
|
||||
|
||||
## 2024.8.6
|
||||
|
||||
- Fix QRCode Scanner
|
||||
- Simplify Chap verification password
|
||||
- Quota based Freeradius Rest
|
||||
- Fix Payment Gateway Audit
|
||||
|
||||
## 2024.8.6
|
||||
|
||||
- Fix Customer pppoe username
|
||||
|
||||
## 2024.8.5
|
||||
|
||||
- Add Customer Mail Inbox
|
||||
- Add pppoe customer and pppoe IP to make static username and IP
|
||||
- Add Sync button
|
||||
- Allow Mac Address Username
|
||||
- Router Maps
|
||||
|
||||
## 2024.8.1
|
||||
|
||||
- Show Bandwidth Plan in the customer dashboard
|
||||
- Add Audit Payment Gateway
|
||||
- Fix Plugin Manager
|
||||
|
||||
## 2024.7.23
|
||||
|
||||
- add Voucher Used Date
|
||||
|
10
README.md
10
README.md
@ -36,7 +36,7 @@ Most current web servers with PHP & MySQL installed will be capable of running P
|
||||
Minimum Requirements
|
||||
|
||||
- Linux or Windows OS
|
||||
- Minimum PHP Version 7.4
|
||||
- Minimum PHP Version 8.2
|
||||
- Both PDO & MySQLi Support
|
||||
- PHP-GD2 Image Library
|
||||
- PHP-CURL
|
||||
@ -98,5 +98,13 @@ a.n Ibnu Maksum
|
||||
|
||||
## SPONSORS
|
||||
|
||||
- [mixradius.com](https://mixradius.com/) Paid Services Billing Radius
|
||||
- [mlink.id](https://mlink.id)
|
||||
- [https://github.com/sonyinside](https://github.com/sonyinside)
|
||||
|
||||
## Thanks
|
||||
We appreciate all people who are participating in this project.
|
||||
|
||||
<a href="https://github.com/hotspotbilling/phpnuxbill/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hotspotbilling/phpnuxbill" />
|
||||
</a>
|
||||
|
@ -5,4 +5,4 @@
|
||||
**/
|
||||
|
||||
|
||||
header('location: ../index.php?_route=admin/');
|
||||
header('location: ../?_route=admin/');
|
@ -1,16 +1,23 @@
|
||||
<?php
|
||||
$db_host = "localhost"; # Database Host
|
||||
$db_port = ""; # Database Port. Keep it blank if you are un sure.
|
||||
$db_user = "root"; # Database Username
|
||||
$db_password = ""; # Database Password
|
||||
$db_name = "phpnuxbill"; # Database Name
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
|
||||
$host = $_SERVER['HTTP_HOST'];
|
||||
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ||
|
||||
(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? "https://" : "http://";
|
||||
|
||||
// Check if HTTP_HOST is set, otherwise use a default value or SERVER_NAME
|
||||
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
|
||||
|
||||
$baseDir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
|
||||
define('APP_URL', $protocol . $host . $baseDir);
|
||||
#Please include http and do not use trailing slash after the url. For example use in this format- http://www.example.com Or http://www.example.com/finance
|
||||
|
||||
|
||||
$_app_stage = 'Live'; # Do not change this
|
||||
|
||||
$db_host = "localhost"; # Database Host
|
||||
$db_port = ""; # Database Port. Keep it blank if you are un sure.
|
||||
$db_user = "root"; # Database Username
|
||||
$db_pass = ""; # Database Password
|
||||
$db_name = "phpnuxbill"; # Database Name
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
70
init.php
70
init.php
@ -42,12 +42,13 @@ spl_autoload_register('_autoloader');
|
||||
if (!file_exists($root_path . 'config.php')) {
|
||||
$root_path .= '..' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($root_path . 'config.php')) {
|
||||
r2('install');
|
||||
r2(getUrl('install'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($root_path . File::pathFixer('system/orm.php'))) {
|
||||
die($root_path . "orm.php file not found");
|
||||
echo $root_path . "orm.php file not found";
|
||||
die();
|
||||
}
|
||||
|
||||
$DEVICE_PATH = $root_path . File::pathFixer('system/devices');
|
||||
@ -59,7 +60,8 @@ $PAYMENTGATEWAY_PATH = $root_path . File::pathFixer('system/paymentgateway');
|
||||
$UI_PATH = 'ui';
|
||||
|
||||
if (!file_exists($UPLOAD_PATH . File::pathFixer('/notifications.default.json'))) {
|
||||
die($UPLOAD_PATH . File::pathFixer("/notifications.default.json file not found"));
|
||||
echo $UPLOAD_PATH . File::pathFixer("/notifications.default.json file not found");
|
||||
die();
|
||||
}
|
||||
|
||||
require_once $root_path . 'config.php';
|
||||
@ -67,10 +69,14 @@ require_once $root_path . File::pathFixer('system/orm.php');
|
||||
require_once $root_path . File::pathFixer('system/autoload/PEAR2/Autoload.php');
|
||||
include $root_path . File::pathFixer('system/autoload/Hookers.php');
|
||||
|
||||
if(!empty($db_password)){
|
||||
if ($db_password != null && ($db_pass == null || empty($db_pass))) {
|
||||
// compability for old version
|
||||
$db_pass = $db_password;
|
||||
}
|
||||
if ($db_pass != null) {
|
||||
// compability for old version
|
||||
$db_password = $db_pass;
|
||||
}
|
||||
ORM::configure("mysql:host=$db_host;dbname=$db_name");
|
||||
ORM::configure('username', $db_user);
|
||||
ORM::configure('password', $db_pass);
|
||||
@ -81,7 +87,7 @@ if ($_app_stage != 'Live') {
|
||||
if ($isApi) {
|
||||
define('U', APP_URL . '/system/api.php?r=');
|
||||
} else {
|
||||
define('U', APP_URL . '/index.php?_route=');
|
||||
define('U', APP_URL . '/?_route=');
|
||||
}
|
||||
|
||||
// notification message
|
||||
@ -115,7 +121,7 @@ if (empty($http_proxy) && !empty($config['http_proxy'])) {
|
||||
date_default_timezone_set($config['timezone']);
|
||||
|
||||
if ((!empty($radius_user) && $config['radius_enable']) || _post('radius_enable')) {
|
||||
if(!empty($radius_password)){
|
||||
if (!empty($radius_password)) {
|
||||
// compability for old version
|
||||
$radius_pass = $radius_password;
|
||||
}
|
||||
@ -127,20 +133,29 @@ if ((!empty($radius_user) && $config['radius_enable']) || _post('radius_enable')
|
||||
}
|
||||
|
||||
|
||||
// Check if the user has selected a language
|
||||
if (!empty($_SESSION['user_language'])) {
|
||||
$config['language'] = $_SESSION['user_language'];
|
||||
} else if (!empty($_COOKIE['user_language'])) {
|
||||
$config['language'] = $_COOKIE['user_language'];
|
||||
} else if (User::getID() > 0) {
|
||||
$lang = User::getAttribute("Language");
|
||||
if (!empty($lang)) {
|
||||
$config['language'] = $lang;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($config['language'])) {
|
||||
$config['language'] = 'english';
|
||||
}
|
||||
$lan_file = $root_path . File::pathFixer('system/lan/' . $config['language'] . '.json');
|
||||
if (file_exists($lan_file)) {
|
||||
$_L = json_decode(file_get_contents($lan_file), true);
|
||||
$_SESSION['Lang'] = $_L;
|
||||
} else {
|
||||
$_L['author'] = 'Auto Generated by iBNuX Script';
|
||||
$_SESSION['Lang'] = $_L;
|
||||
$_L['author'] = 'Auto Generated by PHPNuxBill Script';
|
||||
file_put_contents($lan_file, json_encode($_L));
|
||||
}
|
||||
|
||||
|
||||
function safedata($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
@ -181,7 +196,7 @@ function _auth($login = true)
|
||||
return true;
|
||||
} else {
|
||||
if ($login) {
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -194,7 +209,7 @@ function _admin($login = true)
|
||||
return true;
|
||||
} else {
|
||||
if ($login) {
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -218,8 +233,12 @@ function _log($description, $type = '', $userid = '0')
|
||||
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //to check ip from share internet
|
||||
{
|
||||
$d->ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} else {
|
||||
} else if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
$d->ip = $_SERVER["REMOTE_ADDR"];
|
||||
} else if (php_sapi_name() == 'cli') {
|
||||
$d->ip = 'CLI';
|
||||
} else {
|
||||
$d->ip = 'Unknown';
|
||||
}
|
||||
$d->save();
|
||||
}
|
||||
@ -242,6 +261,13 @@ function showResult($success, $message = '', $result = [], $meta = [])
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* make url canonical or standar
|
||||
*/
|
||||
function getUrl($url)
|
||||
{
|
||||
return Text::url($url);
|
||||
}
|
||||
|
||||
function generateUniqueNumericVouchers($totalVouchers, $length = 8)
|
||||
{
|
||||
@ -314,10 +340,10 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
|
||||
if (!isset($ui)) return;
|
||||
if (strlen($url) > 4) {
|
||||
if (substr($url, 0, 4) != "http") {
|
||||
$url = U . $url;
|
||||
$url = getUrl($url);
|
||||
}
|
||||
} else {
|
||||
$url = U . $url;
|
||||
$url = getUrl($url);
|
||||
}
|
||||
$ui->assign('text', $text);
|
||||
$ui->assign('type', $type);
|
||||
@ -329,14 +355,14 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
|
||||
|
||||
|
||||
if (!isset($api_secret)) {
|
||||
$api_secret = $db_password;
|
||||
$api_secret = $db_pass;
|
||||
}
|
||||
|
||||
function displayMaintenanceMessage(): void
|
||||
{
|
||||
global $config, $ui;
|
||||
$date = $config['maintenance_date'];
|
||||
if ($date){
|
||||
if ($date) {
|
||||
$ui->assign('date', $date);
|
||||
}
|
||||
http_response_code(503);
|
||||
@ -344,3 +370,13 @@ function displayMaintenanceMessage(): void
|
||||
$ui->display('maintenance.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
function isTableExist($table)
|
||||
{
|
||||
try {
|
||||
$record = ORM::forTable($table)->find_one();
|
||||
return $record !== false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,10 @@ CREATE TABLE `tbl_customers` (
|
||||
`id` int NOT NULL,
|
||||
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg',
|
||||
`pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
`pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
|
||||
`city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
@ -36,7 +39,7 @@ CREATE TABLE `tbl_customers` (
|
||||
`zip` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
|
||||
`email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
|
||||
`coordinates` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '6.465422, 3.406448' COMMENT 'Latitude and Longitude coordinates',
|
||||
`coordinates` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates',
|
||||
`account_type` enum('Business','Personal') COLLATE utf8mb4_general_ci DEFAULT 'Personal' COMMENT 'For selecting account type',
|
||||
`balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit',
|
||||
`service_type` enum('Hotspot','PPPoE','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Others' COMMENT 'For selecting user type',
|
||||
@ -69,14 +72,15 @@ DROP TABLE IF EXISTS `tbl_payment_gateway`;
|
||||
CREATE TABLE `tbl_payment_gateway` (
|
||||
`id` int NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user_id` int(11) NOT NULL DEFAULT 0,
|
||||
`gateway` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'xendit | midtrans',
|
||||
`gateway_trx_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`gateway_trx_id` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`plan_id` int NOT NULL,
|
||||
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`routers_id` int NOT NULL,
|
||||
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`pg_url_payment` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`pg_url_payment` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`payment_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`payment_channel` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`pg_request` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
|
||||
@ -135,6 +139,10 @@ CREATE TABLE `tbl_routers` (
|
||||
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`password` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`coordinates` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`status` ENUM('Online', 'Offline') DEFAULT 'Online',
|
||||
`last_seen` DATETIME,
|
||||
`coverage` VARCHAR(8) NOT NULL DEFAULT '0',
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
@ -143,6 +151,7 @@ CREATE TABLE `tbl_transactions` (
|
||||
`id` int NOT NULL,
|
||||
`invoice` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user_id` int(11) NOT NULL DEFAULT 0,
|
||||
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`recharged_on` date NOT NULL,
|
||||
@ -160,6 +169,7 @@ DROP TABLE IF EXISTS `tbl_users`;
|
||||
CREATE TABLE `tbl_users` (
|
||||
`id` int UNSIGNED NOT NULL,
|
||||
`root` int NOT NULL DEFAULT '0' COMMENT 'for sub account',
|
||||
`photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png',
|
||||
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
@ -170,7 +180,9 @@ CREATE TABLE `tbl_users` (
|
||||
`ward` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'kelurahan',
|
||||
`user_type` enum('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active',
|
||||
`data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data',
|
||||
`last_login` datetime DEFAULT NULL,
|
||||
`login_token` VARCHAR(40),
|
||||
`creationdate` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
@ -201,6 +213,7 @@ CREATE TABLE `tbl_voucher` (
|
||||
`code` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`status` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`used_date` DATETIME NULL DEFAULT NULL,
|
||||
`generated_by` int NOT NULL DEFAULT '0' COMMENT 'id admin'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
@ -217,11 +230,52 @@ CREATE TABLE `rad_acct` (
|
||||
`nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`acctsessiontime` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctinputoctets` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctoutputoctets` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `tbl_customers_inbox`;
|
||||
CREATE TABLE `tbl_customers_inbox` (
|
||||
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`customer_id` int NOT NULL,
|
||||
`date_created` datetime NOT NULL,
|
||||
`date_read` datetime DEFAULT NULL,
|
||||
`subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`body` TEXT NULL DEFAULT NULL,
|
||||
`from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',
|
||||
`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tbl_meta` (
|
||||
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name',
|
||||
`tbl_id` int NOT NULL COMMENT 'table value id',
|
||||
`name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`value` mediumtext COLLATE utf8mb4_general_ci,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tbl_coupons` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`code` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`type` ENUM('fixed', 'percent') NOT NULL,
|
||||
`value` DECIMAL(10,2) NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`max_usage` INT NOT NULL DEFAULT 1,
|
||||
`usage_count` INT NOT NULL DEFAULT 0,
|
||||
`status` ENUM('active', 'inactive') NOT NULL,
|
||||
`min_order_amount` DECIMAL(10,2) NOT NULL,
|
||||
`max_discount_amount` DECIMAL(10,2) NOT NULL,
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE `rad_acct`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
|
@ -42,20 +42,20 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dbhost">Database Host</label>
|
||||
<input type="text" class="form-control" id="dbhost" name="dbhost">
|
||||
<input type="text" class="form-control" id="dbhost" required name="dbhost">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dbuser">Database Username</label>
|
||||
<input type="text" class="form-control" id="dbuser" name="dbuser">
|
||||
<input type="text" class="form-control" id="dbuser" required name="dbuser">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dbpass">Database Password</label>
|
||||
<input type="text" class="form-control" id="dbpass" name="dbpass">
|
||||
<input type="text" class="form-control" id="dbpass" required name="dbpass">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="dbname">Database Name</label>
|
||||
<input type="text" class="form-control" id="dbname" name="dbname">
|
||||
<input type="text" class="form-control" id="dbname" required name="dbname">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
@ -9,14 +9,14 @@
|
||||
$appurl = $_POST['appurl'];
|
||||
$db_host = $_POST['dbhost'];
|
||||
$db_user = $_POST['dbuser'];
|
||||
$db_password = $_POST['dbpass'];
|
||||
$db_pass = $_POST['dbpass'];
|
||||
$db_name = $_POST['dbname'];
|
||||
$cn = '0';
|
||||
try {
|
||||
$dbh = new pdo(
|
||||
"mysql:host=$db_host;dbname=$db_name",
|
||||
"$db_user",
|
||||
"$db_password",
|
||||
"$db_pass",
|
||||
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
|
||||
);
|
||||
$cn = '1';
|
||||
@ -30,7 +30,7 @@ if ($cn == '1') {
|
||||
|
||||
$protocol = (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off" || $_SERVER["SERVER_PORT"] == 443) ? "https://" : "http://";
|
||||
$host = $_SERVER["HTTP_HOST"];
|
||||
$baseDir = rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/\\");
|
||||
$baseDir = rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/\\\\");
|
||||
define("APP_URL", $protocol . $host . $baseDir);
|
||||
|
||||
// Live, Dev, Demo
|
||||
@ -39,13 +39,13 @@ $_app_stage = "Live";
|
||||
// Database PHPNuxBill
|
||||
$db_host = "' . $db_host . '";
|
||||
$db_user = "' . $db_user . '";
|
||||
$db_pass = "' . $db_password . '";
|
||||
$db_pass = "' . $db_pass . '";
|
||||
$db_name = "' . $db_name . '";
|
||||
|
||||
// Database Radius
|
||||
$radius_host = "' . $db_host . '";
|
||||
$radius_user = "' . $db_user . '";
|
||||
$radius_pass = "' . $db_password . '";
|
||||
$radius_pass = "' . $db_pass . '";
|
||||
$radius_name = "' . $db_name . '";
|
||||
|
||||
if($_app_stage!="Live"){
|
||||
@ -61,7 +61,7 @@ if($_app_stage!="Live"){
|
||||
$input = '<?php
|
||||
$protocol = (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off" || $_SERVER["SERVER_PORT"] == 443) ? "https://" : "http://";
|
||||
$host = $_SERVER["HTTP_HOST"];
|
||||
$baseDir = rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/\\");
|
||||
$baseDir = rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/\\\\");
|
||||
define("APP_URL", $protocol . $host . $baseDir);
|
||||
|
||||
// Live, Dev, Demo
|
||||
@ -70,7 +70,7 @@ $_app_stage = "Live";
|
||||
// Database PHPNuxBill
|
||||
$db_host = "' . $db_host . '";
|
||||
$db_user = "' . $db_user . '";
|
||||
$db_pass = "' . $db_password . '";
|
||||
$db_pass = "' . $db_pass . '";
|
||||
$db_name = "' . $db_name . '";
|
||||
|
||||
if($_app_stage!="Live"){
|
||||
|
@ -26,7 +26,7 @@
|
||||
try{
|
||||
$dbh = new pdo( "mysql:host=$db_host;dbname=$db_name",
|
||||
"$db_user",
|
||||
"$db_password",
|
||||
"$db_pass",
|
||||
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
|
||||
|
||||
echo "CREATE TABLE `tbl_payment_gateway` (
|
||||
|
27
pages_template/vouchers/Default.html
Normal file
27
pages_template/vouchers/Default.html
Normal file
@ -0,0 +1,27 @@
|
||||
<table border="0" cellspacing="0" cellpadding="2">
|
||||
<tbody><tr>
|
||||
<td valign="middle">
|
||||
<center><strong style="font-size:38px">[[company_name]]</strong></center>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="1" bordercolor="#757575">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="4" width="1">[[qrcode]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:25px">
|
||||
[[price]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:20px">
|
||||
[[voucher_code]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:15px">
|
||||
[[plan]] - [[counter]]<br></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
24
pages_template/vouchers/Logo Header Center.html
Normal file
24
pages_template/vouchers/Logo Header Center.html
Normal file
@ -0,0 +1,24 @@
|
||||
<table border="0" cellspacing="0" cellpadding="2">
|
||||
<tbody><tr>
|
||||
<td valign="middle">
|
||||
<center><img src="system/uploads/logo.png"></center>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="1" bordercolor="#757575">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:25px">
|
||||
[[qrcode]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:20px">
|
||||
[[voucher_code]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:15px">
|
||||
[[plan]] [[price]]<br></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<center>[[company_name]]</center>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
28
pages_template/vouchers/Logo Header.html
Normal file
28
pages_template/vouchers/Logo Header.html
Normal file
@ -0,0 +1,28 @@
|
||||
<table border="0" cellspacing="0" cellpadding="2">
|
||||
<tbody><tr>
|
||||
<td valign="middle">
|
||||
<center><img src="system/uploads/logo.png"></center>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="1" bordercolor="#757575">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="4" width="1">[[qrcode]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:25px">
|
||||
[[price]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:20px">
|
||||
[[voucher_code]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="middle" align="center" style="font-size:15px">
|
||||
[[plan]] - [[counter]]<br></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<center>[[company_name]]</center>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
249
radius.php
249
radius.php
@ -38,16 +38,80 @@ try {
|
||||
case 'authenticate':
|
||||
$username = _req('username');
|
||||
$password = _req('password');
|
||||
if (empty($username) || empty($password)) {
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Reject",
|
||||
"reply:Reply-Message" => 'Login invalid'
|
||||
], 401);
|
||||
$CHAPassword = _req('CHAPassword');
|
||||
$CHAPchallenge = _req('CHAPchallenge');
|
||||
$isCHAP = false;
|
||||
if (!empty($CHAPassword)) {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else if (!empty($c['pppoe_password']) && Password::chap_verify($c['pppoe_password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['pppoe_password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else {
|
||||
// check if voucher
|
||||
if (Password::chap_verify($username, $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
// no password is voucher
|
||||
if (Password::chap_verify('', $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else if (!empty($c['pppoe_password']) && Password::chap_verify($c['pppoe_password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['pppoe_password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else {
|
||||
// check if voucher
|
||||
if (Password::chap_verify($username, $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
// no password is voucher
|
||||
if (Password::chap_verify('', $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($username) && empty($password)) {
|
||||
// Voucher with empty password
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else if (empty($username) || empty($password)) {
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Reject",
|
||||
"reply:Reply-Message" => 'Login invalid......'
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
if ($username == $password) {
|
||||
$d = ORM::for_table('tbl_voucher')->where('code', $username)->find_one();
|
||||
$username = Text::alphanumeric($username, "-_.,");
|
||||
$d = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$username'")->find_one();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
$d = ORM::for_table('tbl_customers')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
unset($d);
|
||||
@ -68,33 +132,118 @@ try {
|
||||
$username = _req('username');
|
||||
$password = _req('password');
|
||||
$isVoucher = ($username == $password);
|
||||
if (empty($username) || empty($password)) {
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Reject",
|
||||
"reply:Reply-Message" => 'Login invalid......'
|
||||
], 401);
|
||||
$CHAPassword = _req('CHAPassword');
|
||||
$CHAPchallenge = _req('CHAPchallenge');
|
||||
$isCHAP = false;
|
||||
if (!empty($CHAPassword)) {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else if (!empty($c['pppoe_password']) && Password::chap_verify($c['pppoe_password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['pppoe_password'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else {
|
||||
// check if voucher
|
||||
if (Password::chap_verify($username, $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
// no password is voucher
|
||||
if (Password::chap_verify('', $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('username')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
$username = $c['username'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else if (!empty($c['pppoe_password']) && Password::chap_verify($c['pppoe_password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['pppoe_password'];
|
||||
$username = $c['username'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else {
|
||||
// check if voucher
|
||||
if (Password::chap_verify($username, $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
// no password is voucher
|
||||
if (Password::chap_verify('', $CHAPassword, $CHAPchallenge)) {
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($username) && empty($password)) {
|
||||
// Voucher with empty password
|
||||
$isVoucher = true;
|
||||
$password = $username;
|
||||
} else if (empty($username) || empty($password)) {
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Reject",
|
||||
"reply:Reply-Message" => 'Login invalid......'
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
if (!$tur) {
|
||||
// if check if pppoe_username
|
||||
$c = ORM::for_table('tbl_customers')->select('username')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username'")->find_one();
|
||||
if($c){
|
||||
$username = $c['username'];
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
}
|
||||
}
|
||||
$tur = ORM::for_table('tbl_user_recharges')->where('username', $username)->find_one();
|
||||
if ($tur) {
|
||||
if (!$isVoucher) {
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->where('username', $username)->find_one();
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
if (!$isVoucher && !$isCHAP) {
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d) {
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d) {
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
show_radius_result(['Reply-Message' => 'Username or Password is wrong'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
process_radiust_rest($tur, $code);
|
||||
} else {
|
||||
if ($isVoucher) {
|
||||
$v = ORM::for_table('tbl_voucher')->where('code', $username)->where('routers', 'radius')->find_one();
|
||||
$username = Text::alphanumeric($username, "-_.,");
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$username' AND routers = 'radius'")->find_one();
|
||||
if ($v) {
|
||||
if ($v['status'] == 0) {
|
||||
if (Package::rechargeUser(0, $v['routers'], $v['id_plan'], "Voucher", $username)) {
|
||||
$v->status = "1";
|
||||
$v->used_date = date('Y-m-d H:i:s');
|
||||
$v->save();
|
||||
$tur = ORM::for_table('tbl_user_recharges')->where('username', $username)->find_one();
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
if ($tur) {
|
||||
process_radiust_rest($tur, $code);
|
||||
} else {
|
||||
@ -107,7 +256,7 @@ try {
|
||||
show_radius_result(['Reply-Message' => 'Voucher Expired...'], 401);
|
||||
}
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Voucher Expired..'], 401);
|
||||
show_radius_result(['Reply-Message' => 'Invalid Voucher..'], 401);
|
||||
}
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Internet Plan Expired..'], 401);
|
||||
@ -125,25 +274,51 @@ try {
|
||||
}
|
||||
header("HTTP/1.1 200 ok");
|
||||
$d = ORM::for_table('rad_acct')
|
||||
->where('username', $username)
|
||||
->where('macaddr', _post('macAddr'))
|
||||
->where('acctstatustype', _post('acctStatusType'))
|
||||
->whereRaw("BINARY username = '$username' AND macaddr = '"._post('macAddr')."' AND nasid = '"._post('nasid')."'")
|
||||
->findOne();
|
||||
if (!$d) {
|
||||
$d = ORM::for_table('rad_acct')->create();
|
||||
}
|
||||
$acctOutputOctets = _post('acctOutputOctets', 0);
|
||||
$acctInputOctets = _post('acctInputOctets', 0);
|
||||
if ($acctOutputOctets !== false && $acctInputOctets !== false) {
|
||||
$d->acctOutputOctets += intval($acctOutputOctets);
|
||||
$d->acctInputOctets += intval($acctInputOctets);
|
||||
} else {
|
||||
$d->acctOutputOctets = 0;
|
||||
$d->acctInputOctets = 0;
|
||||
}
|
||||
$d->acctsessionid = _post('acctSessionId');
|
||||
$d->username = $username;
|
||||
$d->realm = _post('realm');
|
||||
$d->nasipaddress = _post('nasip');
|
||||
$d->nasipaddress = _post('nasIpAddress');
|
||||
$d->acctsessiontime = intval(_post('acctSessionTime'));
|
||||
$d->nasid = _post('nasid');
|
||||
$d->nasportid = _post('nasPortId');
|
||||
$d->nasporttype = _post('nasPortType');
|
||||
$d->framedipaddress = _post('framedIPAddress');
|
||||
$d->acctstatustype = _post('acctStatusType');
|
||||
if(in_array(_post('acctStatusType'), ['Start', 'Stop'])){
|
||||
$d->acctstatustype = _post('acctStatusType');
|
||||
}
|
||||
$d->macaddr = _post('macAddr');
|
||||
$d->dateAdded = date('Y-m-d H:i:s');
|
||||
$d->save();
|
||||
// pastikan data akunting yang disimpan memang customer aktif phpnuxbill
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username' AND `status` = 'on' AND `routers` = 'radius'")->find_one();
|
||||
if($tur){
|
||||
$d->save();
|
||||
if (_post('acctStatusType') == 'Start') {
|
||||
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") {
|
||||
$totalUsage = $d['acctOutputOctets'] + $d['acctInputOctets'];
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage;
|
||||
if ($attrs['reply:Mikrotik-Total-Limit'] < 0) {
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = 0;
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You have exceeded your data limit.'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
process_radiust_rest($tur, 200);
|
||||
}
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Accept",
|
||||
"reply:Reply-Message" => 'Saved'
|
||||
@ -173,6 +348,16 @@ function process_radiust_rest($tur, $code)
|
||||
global $config;
|
||||
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
|
||||
// Count User Onlines
|
||||
$USRon = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY username = '".$tur['username']."' AND acctStatusType = 'Start'")
|
||||
->find_array();
|
||||
// get all the IP
|
||||
$ips = array_column($USRon, 'framedipaddress');
|
||||
// check if user reach shared_users limit but IP is not in the list active
|
||||
if (count($USRon) >= $plan['shared_users'] && $plan['type'] == 'Hotspot' && !in_array(_post('framedIPAddress'), $ips)) {
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You are already logged in - access denied ('.$USRon.')'], 401);
|
||||
}
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
@ -211,6 +396,15 @@ function process_radiust_rest($tur, $code)
|
||||
}
|
||||
|
||||
if ($plan['typebp'] == "Limited") {
|
||||
if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") {
|
||||
$raddact = ORM::for_table('rad_acct')->whereRaw("BINARY username = '$tur[username]'")->where('acctstatustype', 'Start')->find_one();
|
||||
$totalUsage = intval($raddact['acctOutputOctets']) + intval($raddact['acctInputOctets']);
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage;
|
||||
if ($attrs['reply:Mikrotik-Total-Limit'] < 0) {
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = 0;
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You have exceeded your data limit.'], 401);
|
||||
}
|
||||
}
|
||||
if ($plan['limit_type'] == "Time_Limit") {
|
||||
if ($plan['time_unit'] == 'Hrs')
|
||||
$timelimit = $plan['time_limit'] * 60 * 60;
|
||||
@ -259,5 +453,4 @@ function show_radius_result($array, $code = 200)
|
||||
die();
|
||||
}
|
||||
die(json_encode($array));
|
||||
die();
|
||||
}
|
||||
|
281
scan/index.html
281
scan/index.html
@ -1,281 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>QR Scanner</title>
|
||||
<style>
|
||||
video {
|
||||
width: 100% !important;
|
||||
height: auto !important
|
||||
}
|
||||
|
||||
#reload {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
background-color: #0336FF;
|
||||
color: #f3f4f5;
|
||||
border-radius: 3px;
|
||||
width: 150px;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #0336FF
|
||||
}
|
||||
|
||||
.progress {
|
||||
padding: 10px;
|
||||
margin-top: 5px
|
||||
}
|
||||
|
||||
#camera {
|
||||
position: relative;
|
||||
width: auto;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
#camera:after,
|
||||
#camera:before,
|
||||
#camera>:first-child:after,
|
||||
#camera>:first-child:before {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-color: red;
|
||||
border-style: solid;
|
||||
content: ' '
|
||||
}
|
||||
|
||||
#camera:before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-width: 5px 0 0 5px
|
||||
}
|
||||
|
||||
#camera:after {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-width: 5px 5px 0 0
|
||||
}
|
||||
|
||||
#camera>:first-child:before {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-width: 0 5px 5px 0
|
||||
}
|
||||
|
||||
#camera>:first-child:after {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-width: 0 0 5px 5px
|
||||
}
|
||||
|
||||
#camera-inside {
|
||||
padding: 10px;
|
||||
margin-bottom: -5px
|
||||
}
|
||||
|
||||
#hasil {
|
||||
font-size: 20px;
|
||||
font-weight: 600px;
|
||||
background-color: #76ff03;
|
||||
color: #202020
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="llqrcode.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<div id="main">
|
||||
<div id="mainbody">
|
||||
<div class="progress">
|
||||
<div id="hasil"></div>
|
||||
</div>
|
||||
<div id="camera">
|
||||
<div id="camera-inside"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div id="reload" onclick="location.reload();">Refresh Camera</div>
|
||||
<p><small>Point Camera to Barcode</small></p>
|
||||
<br>
|
||||
</center>
|
||||
<canvas style="display:none;" id="qr-canvas" width="800" height="600"></canvas>
|
||||
<script type="text/javascript">
|
||||
function getAllUrlParams(e) {
|
||||
var t = e ? e.split("?")[1] : window.location.search.slice(1),
|
||||
a = {};
|
||||
if (t)
|
||||
for (var n = (t = t.split("#")[0]).split("&"), o = 0; o < n.length; o++) {
|
||||
var i = n[o].split("="),
|
||||
r = void 0,
|
||||
d = i[0].replace(/\[\d*\]/, function (e) {
|
||||
return (r = e.slice(1, -1)), "";
|
||||
}),
|
||||
s = void 0 === i[1] || i[1];
|
||||
a[(d = d.toLowerCase())]
|
||||
? ("string" == typeof a[d] && (a[d] = [a[d]]),
|
||||
void 0 === r ? a[d].push(s) : (a[d][r] = s))
|
||||
: (a[d] = s);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
var gCtx = null,
|
||||
gCanvas = null,
|
||||
c = 0,
|
||||
stype = 0,
|
||||
gUM = !1,
|
||||
webkit = !1,
|
||||
moz = !1,
|
||||
v = null,
|
||||
imghtml =
|
||||
'<div id="qrfile"><canvas id="out-canvas" width="320" height="240"></canvas><div id="imghelp">drag and drop a QRCode here<br>or select a file<input type="file" onchange="handleFiles(this.files)"/></div></div>',
|
||||
vidhtml = '<video id="v" autoplay></video>';
|
||||
function dragenter(e) {
|
||||
e.stopPropagation(), e.preventDefault();
|
||||
}
|
||||
function dragover(e) {
|
||||
e.stopPropagation(), e.preventDefault();
|
||||
}
|
||||
function drop(e) {
|
||||
e.stopPropagation(), e.preventDefault();
|
||||
var t = e.dataTransfer,
|
||||
a = t.files;
|
||||
a.length > 0
|
||||
? handleFiles(a)
|
||||
: t.getData("URL") && qrcode.decode(t.getData("URL"));
|
||||
}
|
||||
function handleFiles(e) {
|
||||
for (var t = 0; t < e.length; t++) {
|
||||
var a = new FileReader();
|
||||
(a.onload =
|
||||
(e[t],
|
||||
function (e) {
|
||||
gCtx.clearRect(0, 0, gCanvas.width, gCanvas.height),
|
||||
qrcode.decode(e.target.result);
|
||||
})),
|
||||
a.readAsDataURL(e[t]);
|
||||
}
|
||||
}
|
||||
function initCanvas(e, t) {
|
||||
((gCanvas = document.getElementById("qr-canvas")).style.width = e + "px"),
|
||||
(gCanvas.style.height = t + "px"),
|
||||
(gCanvas.width = e),
|
||||
(gCanvas.height = t),
|
||||
(gCtx = gCanvas.getContext("2d")).clearRect(0, 0, e, t);
|
||||
}
|
||||
function captureToCanvas() {
|
||||
if (1 == stype && gUM)
|
||||
try {
|
||||
gCtx.drawImage(v, 0, 0);
|
||||
try {
|
||||
qrcode.decode();
|
||||
} catch (e) {
|
||||
console.log(e), setTimeout(captureToCanvas, 500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e), setTimeout(captureToCanvas, 500);
|
||||
}
|
||||
}
|
||||
function htmlEntities(e) {
|
||||
return String(e)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
function read(e) {
|
||||
(document.getElementById("hasil").innerHTML =
|
||||
e),
|
||||
(window.location = unescape(getAllUrlParams().back) + e)
|
||||
;
|
||||
}
|
||||
function isCanvasSupported() {
|
||||
var e = document.createElement("canvas");
|
||||
return !(!e.getContext || !e.getContext("2d"));
|
||||
}
|
||||
function success(e) {
|
||||
(v.srcObject = e), v.play(), (gUM = !0), setTimeout(captureToCanvas, 500);
|
||||
}
|
||||
function error(e) {
|
||||
gUM = !1;
|
||||
}
|
||||
function load() {
|
||||
isCanvasSupported() && window.File && window.FileReader
|
||||
? (initCanvas(800, 600),
|
||||
(qrcode.callback = read),
|
||||
(document.getElementById("mainbody").style.display = "inline"),
|
||||
setwebcam())
|
||||
: ((document.getElementById("mainbody").style.display = "inline"),
|
||||
(document.getElementById("mainbody").innerHTML =
|
||||
'<p id="mp1">QR code scanner for HTML5 capable browsers</p><br><br><p id="mp2">sorry your browser is not supported</p><br><br><p id="mp1">try <a href="http://www.mozilla.com/firefox"><img src="firefox.png"/></a> or <a href="http://chrome.google.com"><img src="chrome_logo.gif"/></a> or <a href="http://www.opera.com"><img src="Opera-logo.png"/></a></p>'));
|
||||
}
|
||||
function setwebcam() {
|
||||
var e = !0;
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
|
||||
try {
|
||||
navigator.mediaDevices.enumerateDevices().then(function (t) {
|
||||
t.forEach(function (t) {
|
||||
"videoinput" === t.kind &&
|
||||
t.label.toLowerCase().search("back") > -1 &&
|
||||
(e = {
|
||||
deviceId: { exact: t.deviceId },
|
||||
facingMode: "environment",
|
||||
}),
|
||||
console.log(t.kind + ": " + t.label + " id = " + t.deviceId);
|
||||
}),
|
||||
setwebcam2(e);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
else console.log("no navigator.mediaDevices.enumerateDevices"), setwebcam2(e);
|
||||
}
|
||||
function setwebcam2(e) {
|
||||
if ((console.log(e), 1 != stype)) {
|
||||
var t = navigator;
|
||||
(document.getElementById("camera-inside").innerHTML = vidhtml),
|
||||
(v = document.getElementById("v")),
|
||||
t.mediaDevices.getUserMedia
|
||||
? t.mediaDevices
|
||||
.getUserMedia({ video: e, audio: !1 })
|
||||
.then(function (e) {
|
||||
success(e);
|
||||
})
|
||||
.catch(function (e) {
|
||||
e(e);
|
||||
})
|
||||
: t.getUserMedia
|
||||
? ((webkit = !0),
|
||||
t.getUserMedia({ video: e, audio: !1 }, success, error))
|
||||
: t.webkitGetUserMedia &&
|
||||
((webkit = !0),
|
||||
t.webkitGetUserMedia({ video: e, audio: !1 }, success, error)),
|
||||
(stype = 1),
|
||||
setTimeout(captureToCanvas, 500);
|
||||
} else setTimeout(captureToCanvas, 500);
|
||||
}
|
||||
function setimg() {
|
||||
if (((document.getElementById("result").innerHTML = ""), 2 != stype)) {
|
||||
(document.getElementById("camera-inside").innerHTML = imghtml),
|
||||
(document.getElementById("qrimg").style.opacity = 1),
|
||||
(document.getElementById("webcamimg").style.opacity = 0.2);
|
||||
var e = document.getElementById("qrfile");
|
||||
e.addEventListener("dragenter", dragenter, !1),
|
||||
e.addEventListener("dragover", dragover, !1),
|
||||
e.addEventListener("drop", drop, !1),
|
||||
(stype = 2);
|
||||
}
|
||||
}
|
||||
|
||||
load();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
80
scan/index.php
Normal file
80
scan/index.php
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>QRCode Scanner</title>
|
||||
<style>
|
||||
button {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="qr-reader" style="width:100%; height:auto"></div>
|
||||
<div id="qr-reader-results"></div>
|
||||
<script src="qrcode.min.js"></script>
|
||||
<script>
|
||||
function docReady(fn) {
|
||||
// see if DOM is already available
|
||||
if (document.readyState === "complete" ||
|
||||
document.readyState === "interactive") {
|
||||
// call on next available tick
|
||||
setTimeout(fn, 1);
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", fn);
|
||||
}
|
||||
}
|
||||
|
||||
function getAllUrlParams(e) {
|
||||
var t = e ? e.split("?")[1] : window.location.search.slice(1),
|
||||
a = {};
|
||||
if (t)
|
||||
for (var n = (t = t.split("#")[0]).split("&"), o = 0; o < n.length; o++) {
|
||||
var i = n[o].split("="),
|
||||
r = void 0,
|
||||
d = i[0].replace(/\[\d*\]/, function (e) {
|
||||
return (r = e.slice(1, -1)), "";
|
||||
}),
|
||||
s = void 0 === i[1] || i[1];
|
||||
a[(d = d.toLowerCase())]
|
||||
? ("string" == typeof a[d] && (a[d] = [a[d]]),
|
||||
void 0 === r ? a[d].push(s) : (a[d][r] = s))
|
||||
: (a[d] = s);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
docReady(function() {
|
||||
var resultContainer = document.getElementById('qr-reader-results');
|
||||
var lastResult, countResults = 0;
|
||||
function onScanSuccess(decodedText, decodedResult) {
|
||||
if (decodedText !== lastResult) {
|
||||
++countResults;
|
||||
lastResult = decodedText;
|
||||
if(getAllUrlParams().back != undefined){
|
||||
window.location = unescape(getAllUrlParams().back) + escape(decodedText);
|
||||
}else{
|
||||
if(decodedText.startsWith('http')){
|
||||
window.location = decodedText;
|
||||
}else{
|
||||
alert(decodedText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var html5QrcodeScanner = new Html5QrcodeScanner(
|
||||
"qr-reader", {
|
||||
fps: 10,
|
||||
qrbox: 250
|
||||
});
|
||||
html5QrcodeScanner.render(onScanSuccess);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
1
scan/qrcode.min.js
vendored
Normal file
1
scan/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -11,39 +11,122 @@ class Admin
|
||||
|
||||
public static function getID()
|
||||
{
|
||||
global $db_password;
|
||||
if (isset($_SESSION['aid'])) {
|
||||
global $db_pass, $config, $isApi;
|
||||
|
||||
$enable_session_timeout = $config['enable_session_timeout'] == 1;
|
||||
$session_timeout_duration = $config['session_timeout_duration'] ? intval($config['session_timeout_duration'] * 60) : intval(60 * 60); // Convert minutes to seconds
|
||||
if ($isApi) {
|
||||
$enable_session_timeout = false;
|
||||
}
|
||||
if ($enable_session_timeout && !empty($_SESSION['aid']) && !empty($_SESSION['aid_expiration'])) {
|
||||
if ($_SESSION['aid_expiration'] > time()) {
|
||||
$isValid = self::validateToken($_SESSION['aid'], $_COOKIE['aid']);
|
||||
if (!$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.'), 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
// extend timeout duration
|
||||
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
|
||||
|
||||
return $_SESSION['aid'];
|
||||
} else {
|
||||
// Session expired, log out the user
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
} else if (!empty($_SESSION['aid'])) {
|
||||
$isValid = self::validateToken($_SESSION['aid'], $_COOKIE['aid']);
|
||||
if (!$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.') . '.'.$_SESSION['aid'], 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
return $_SESSION['aid'];
|
||||
} else if (isset($_COOKIE['aid'])) {
|
||||
// id.time.sha1
|
||||
}
|
||||
// Check if the cookie is set and valid
|
||||
elseif (isset($_COOKIE['aid'])) {
|
||||
$tmp = explode('.', $_COOKIE['aid']);
|
||||
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_password) == $tmp[2]) {
|
||||
if (time() - $tmp[1] < 86400 * 7) {
|
||||
$_SESSION['aid'] = $tmp[0];
|
||||
return $tmp[0];
|
||||
if (sha1("$tmp[0].$tmp[1].$db_pass") == $tmp[2]) {
|
||||
// Validate the token in the cookie
|
||||
$isValid = self::validateToken($tmp[0], $_COOKIE['aid']);
|
||||
if ($isApi) {
|
||||
// For now API need to always return true, next need to add revoke token API
|
||||
$isValid = true;
|
||||
}
|
||||
if (!empty($_COOKIE['aid']) && !$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.') . '..', 'danger', "admin");
|
||||
return 0;
|
||||
} else {
|
||||
if (time() - $tmp[1] < 86400 * 7) {
|
||||
$_SESSION['aid'] = $tmp[0];
|
||||
if ($enable_session_timeout) {
|
||||
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
|
||||
}
|
||||
return $tmp[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function setCookie($aid)
|
||||
{
|
||||
global $db_password;
|
||||
global $db_pass, $config;
|
||||
$enable_session_timeout = $config['enable_session_timeout'];
|
||||
$session_timeout_duration = intval($config['session_timeout_duration']) * 60; // Convert minutes to seconds
|
||||
|
||||
if (isset($aid)) {
|
||||
$time = time();
|
||||
$token = $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_password);
|
||||
setcookie('aid', $token, time() + 86400 * 7);
|
||||
$token = $aid . '.' . $time . '.' . sha1("$aid.$time.$db_pass");
|
||||
|
||||
// Detect the current protocol
|
||||
$isSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
// Set cookie with security flags
|
||||
setcookie('aid', $token, [
|
||||
'expires' => time() + 86400 * 7, // 7 days
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => $isSecure,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax', // or Strict
|
||||
]);
|
||||
|
||||
$_SESSION['aid'] = $aid;
|
||||
|
||||
if ($enable_session_timeout) {
|
||||
$_SESSION['aid_expiration'] = $time + $session_timeout_duration;
|
||||
}
|
||||
|
||||
self::upsertToken($aid, $token);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
public static function removeCookie()
|
||||
{
|
||||
global $_app_stage;
|
||||
if (isset($_COOKIE['aid'])) {
|
||||
setcookie('aid', '', time() - 86400);
|
||||
$isSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie('aid', '', [
|
||||
'expires' => time() - 3600,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => $isSecure,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
session_destroy();
|
||||
session_unset();
|
||||
session_start();
|
||||
unset($_COOKIE['aid'], $_SESSION['aid']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,4 +141,24 @@ class Admin
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function upsertToken($aid, $token)
|
||||
{
|
||||
$query = ORM::for_table('tbl_users')->findOne($aid);
|
||||
$query->login_token = sha1($token);
|
||||
$query->save();
|
||||
}
|
||||
|
||||
public static function validateToken($aid, $cookieToken)
|
||||
{
|
||||
global $config;
|
||||
$query = ORM::for_table('tbl_users')->select('login_token')->findOne($aid);
|
||||
if ($config['single_session'] != 'yes') {
|
||||
return true; // For multi-session, any token is valid
|
||||
}
|
||||
if (empty($query)) {
|
||||
return true;
|
||||
}
|
||||
return $query->login_token === sha1($cookieToken);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ class App{
|
||||
}
|
||||
|
||||
public static function getTokenValue($key){
|
||||
if(empty($key)){
|
||||
return "";
|
||||
}
|
||||
if(isset($_SESSION[$key])){
|
||||
return $_SESSION[$key];
|
||||
}else{
|
||||
@ -26,4 +29,23 @@ class App{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static function getVoucher(){
|
||||
return md5(microtime());
|
||||
}
|
||||
|
||||
public static function setVoucher($token, $value){
|
||||
$_SESSION[$token] = $value;
|
||||
}
|
||||
|
||||
public static function getVoucherValue($key){
|
||||
if(empty($key)){
|
||||
return "";
|
||||
}
|
||||
if(isset($_SESSION[$key])){
|
||||
return $_SESSION[$key];
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,13 +30,9 @@ class Balance
|
||||
public static function min($id_customer, $amount)
|
||||
{
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
|
||||
if ($c && $c['balance'] >= $amount) {
|
||||
$c->balance = $c['balance'] - $amount;
|
||||
$c->save();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$c->balance = $c['balance'] - $amount;
|
||||
$c->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function plusByPhone($phone_customer, $amount)
|
||||
|
55
system/autoload/Csrf.php
Normal file
55
system/autoload/Csrf.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
|
||||
class Csrf
|
||||
{
|
||||
private static $tokenExpiration = 1800; // 30 minutes
|
||||
|
||||
public static function generateToken($length = 16)
|
||||
{
|
||||
return bin2hex(random_bytes($length));
|
||||
}
|
||||
|
||||
public static function validateToken($token, $storedToken)
|
||||
{
|
||||
return hash_equals($token, $storedToken);
|
||||
}
|
||||
|
||||
public static function check($token)
|
||||
{
|
||||
global $config;
|
||||
if($config['csrf_enabled'] == 'yes') {
|
||||
if (isset($_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $token)) {
|
||||
$storedToken = $_SESSION['csrf_token'];
|
||||
$tokenTime = $_SESSION['csrf_token_time'];
|
||||
|
||||
if (time() - $tokenTime > self::$tokenExpiration) {
|
||||
self::clearToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::validateToken($token, $storedToken);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function generateAndStoreToken()
|
||||
{
|
||||
$token = self::generateToken();
|
||||
$_SESSION['csrf_token'] = $token;
|
||||
$_SESSION['csrf_token_time'] = time();
|
||||
return $token;
|
||||
}
|
||||
|
||||
public static function clearToken()
|
||||
{
|
||||
unset($_SESSION['csrf_token'], $_SESSION['csrf_token_time']);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
@ -93,6 +94,48 @@ class File
|
||||
return file_exists($dst_dir);
|
||||
}
|
||||
|
||||
public static function makeThumb($srcFile, $thumbFile, $thumbSize = 200)
|
||||
{
|
||||
/* Determine the File Type */
|
||||
$type = substr($srcFile, strrpos($srcFile, '.') + 1);
|
||||
$imgsize = getimagesize($srcFile);
|
||||
$oldW = $imgsize[0];
|
||||
$oldH = $imgsize[1];
|
||||
$mime = $imgsize['mime'];
|
||||
switch ($mime) {
|
||||
case 'image/gif':
|
||||
$src = imagecreatefromgif($srcFile);
|
||||
break;
|
||||
|
||||
case 'image/png':
|
||||
$src = imagecreatefrompng($srcFile);
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
$src = imagecreatefromjpeg($srcFile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
/* Calculate the New Image Dimensions */
|
||||
$limiting_dim = 0;
|
||||
if ($oldH > $oldW) {
|
||||
/* Portrait */
|
||||
$limiting_dim = $oldW;
|
||||
} else {
|
||||
/* Landscape */
|
||||
$limiting_dim = $oldH;
|
||||
}
|
||||
/* Create the New Image */
|
||||
$new = imagecreatetruecolor($thumbSize, $thumbSize);
|
||||
/* Transcribe the Source Image into the New (Square) Image */
|
||||
imagecopyresampled($new, $src, 0, 0, ($oldW - $limiting_dim) / 2, ($oldH - $limiting_dim) / 2, $thumbSize, $thumbSize, $limiting_dim, $limiting_dim);
|
||||
imagejpeg($new, $thumbFile, 100);
|
||||
imagedestroy($new);
|
||||
return file_exists($thumbFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* file path fixer
|
||||
|
@ -11,9 +11,7 @@ class Lang
|
||||
public static function T($key)
|
||||
{
|
||||
global $_L, $lan_file, $config;
|
||||
if(is_array($_SESSION['Lang'])){
|
||||
$_L = array_merge($_L, $_SESSION['Lang']);
|
||||
}
|
||||
|
||||
$key = preg_replace('/\s+/', ' ', $key);
|
||||
if (!empty($_L[$key])) {
|
||||
return $_L[$key];
|
||||
@ -29,15 +27,14 @@ class Lang
|
||||
if (empty($iso)) {
|
||||
return $val;
|
||||
}
|
||||
if (!empty($iso) && !empty($val)) {
|
||||
if (!empty($iso) && !empty($val) && $iso != 'en') {
|
||||
$temp = Lang::translate($val, $iso);
|
||||
if (!empty($temp)) {
|
||||
$val = $temp;
|
||||
}
|
||||
}
|
||||
$_L[$key] = $val;
|
||||
$_SESSION['Lang'][$key] = $val;
|
||||
file_put_contents($lan_file, json_encode($_SESSION['Lang'], JSON_PRETTY_PRINT));
|
||||
file_put_contents($lan_file, json_encode($_L, JSON_PRETTY_PRINT));
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
@ -124,20 +121,20 @@ class Lang
|
||||
}
|
||||
}
|
||||
$when = "";
|
||||
if(time()>strtotime($datetime)){
|
||||
if (time() > strtotime($datetime)) {
|
||||
$when = Lang::T('ago');
|
||||
}else{
|
||||
} else {
|
||||
$when = '';
|
||||
}
|
||||
if (!$full)
|
||||
$string = array_slice($string, 0, 1);
|
||||
if($string){
|
||||
if(empty($when)){
|
||||
return '<b>'. implode(', ', $string) .'</b>';
|
||||
}else{
|
||||
return implode(', ', $string) .' '. $when;
|
||||
if ($string) {
|
||||
if (empty($when)) {
|
||||
return '<b>' . implode(', ', $string) . '</b>';
|
||||
} else {
|
||||
return implode(', ', $string) . ' ' . $when;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return Lang::T('just now');
|
||||
}
|
||||
}
|
||||
@ -245,16 +242,18 @@ class Lang
|
||||
return $txt;
|
||||
}
|
||||
|
||||
public static function maskText($text){
|
||||
public static function maskText($text)
|
||||
{
|
||||
$len = strlen($text);
|
||||
if($len < 3){
|
||||
if ($len < 3) {
|
||||
return "***";
|
||||
}else if($len<5){
|
||||
return substr($text,0,1)."***".substr($text,-1,1);
|
||||
}else if($len<8){
|
||||
return substr($text,0,2)."***".substr($text,-2,2);
|
||||
}else{
|
||||
return substr($text,0,4)."******".substr($text,-3,3);
|
||||
} else if ($len < 5) {
|
||||
return substr($text, 0, 1) . "***" . substr($text, -1, 1);
|
||||
} else if ($len < 8) {
|
||||
return substr($text, 0, 2) . "***" . substr($text, -2, 2);
|
||||
} else {
|
||||
return substr($text, 0, 4) . "******" . substr($text, -3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,12 +17,15 @@ require $root_path . 'system/autoload/mail/SMTP.php';
|
||||
class Message
|
||||
{
|
||||
|
||||
public static function sendTelegram($txt)
|
||||
public static function sendTelegram($txt, $chat_id = null)
|
||||
{
|
||||
global $config;
|
||||
run_hook('send_telegram', [$txt]); #HOOK
|
||||
if (!empty($config['telegram_bot']) && !empty($config['telegram_target_id'])) {
|
||||
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
|
||||
run_hook('send_telegram', [$txt, $chat_id = null]); #HOOK
|
||||
if (!empty($config['telegram_bot'])) {
|
||||
if (empty($chat_id)) {
|
||||
$chat_id = $config['telegram_target_id'];
|
||||
}
|
||||
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $chat_id . '&text=' . urlencode($txt));
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +51,7 @@ class Message
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
self::sendSMS($config['sms_url'], $phone, $txt);
|
||||
self::MikrotikSendSMS($config['sms_url'], $phone, $txt);
|
||||
} catch (Exception $e) {
|
||||
// ignore, add to logs
|
||||
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
|
||||
@ -64,7 +67,7 @@ class Message
|
||||
|
||||
public static function MikrotikSendSMS($router_name, $to, $message)
|
||||
{
|
||||
global $_app_stage, $client_m;
|
||||
global $_app_stage, $client_m, $config;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
@ -73,7 +76,10 @@ class Message
|
||||
$iport = explode(":", $mikrotik['ip_address']);
|
||||
$client_m = new RouterOS\Client($iport[0], $mikrotik['username'], $mikrotik['password'], ($iport[1]) ? $iport[1] : null);
|
||||
}
|
||||
$smsRequest = new RouterOS\Request('/tool sms send');
|
||||
if (empty($config['mikrotik_sms_command'])) {
|
||||
$config['mikrotik_sms_command'] = "/tool sms send";
|
||||
}
|
||||
$smsRequest = new RouterOS\Request($config['mikrotik_sms_command']);
|
||||
$smsRequest
|
||||
->setArgument('phone-number', $to)
|
||||
->setArgument('message', $message);
|
||||
@ -96,7 +102,7 @@ class Message
|
||||
|
||||
public static function sendEmail($to, $subject, $body)
|
||||
{
|
||||
global $config, $PAGES_PATH, $_app_stage;
|
||||
global $config, $PAGES_PATH, $debug_mail;
|
||||
if (empty($body)) {
|
||||
return "";
|
||||
}
|
||||
@ -116,7 +122,7 @@ class Message
|
||||
} else {
|
||||
$mail = new PHPMailer();
|
||||
$mail->isSMTP();
|
||||
if ($_app_stage == 'Dev') {
|
||||
if (isset($debug_mail) && $debug_mail == 'Dev') {
|
||||
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
|
||||
}
|
||||
$mail->Host = $config['smtp_host'];
|
||||
@ -153,7 +159,9 @@ class Message
|
||||
$mail->isHTML(false);
|
||||
$mail->Body = $body;
|
||||
}
|
||||
$mail->send();
|
||||
if (!$mail->send()) {
|
||||
_log(Lang::T("Email not sent, Mailer Error: ") . $mail->ErrorInfo);
|
||||
}
|
||||
|
||||
//<p style="font-family: Helvetica, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">
|
||||
}
|
||||
@ -170,41 +178,86 @@ class Message
|
||||
$msg = str_replace('[[plan]]', $package, $msg);
|
||||
$msg = str_replace('[[package]]', $package, $msg);
|
||||
$msg = str_replace('[[price]]', Lang::moneyFormat($price), $msg);
|
||||
// Calculate bills and additional costs
|
||||
list($bills, $add_cost) = User::getBills($customer['id']);
|
||||
if ($add_cost > 0) {
|
||||
$note = "";
|
||||
|
||||
// Initialize note and total variables
|
||||
$note = "";
|
||||
$total = $price;
|
||||
|
||||
// Add bills to the note if there are any additional costs
|
||||
if ($add_cost != 0) {
|
||||
foreach ($bills as $k => $v) {
|
||||
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
|
||||
}
|
||||
$note .= "Total : " . Lang::moneyFormat($add_cost + $price) . "\n";
|
||||
$msg = str_replace('[[bills]]', $note, $msg);
|
||||
} else {
|
||||
$msg = str_replace('[[bills]]', '', $msg);
|
||||
$total += $add_cost;
|
||||
}
|
||||
|
||||
// Calculate tax
|
||||
$tax = 0;
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
|
||||
$tax_rate = ($tax_rate_setting === 'custom') ? $custom_tax_rate : $tax_rate_setting;
|
||||
$tax = Package::tax($price, $tax_rate);
|
||||
|
||||
if ($tax != 0) {
|
||||
$note .= "Tax : " . Lang::moneyFormat($tax) . "\n";
|
||||
$total += $tax;
|
||||
}
|
||||
}
|
||||
|
||||
// Add total to the note
|
||||
$note .= "Total : " . Lang::moneyFormat($total) . "\n";
|
||||
|
||||
// Replace placeholders in the message
|
||||
$msg = str_replace('[[bills]]', $note, $msg);
|
||||
|
||||
if ($ds) {
|
||||
$msg = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($ds['expiration'], $ds['time']), $msg);
|
||||
} else {
|
||||
$msg = str_replace('[[expired_date]]', "", $msg);
|
||||
}
|
||||
|
||||
if (strpos($msg, '[[payment_link]]') !== false) {
|
||||
// token only valid for 1 day, for security reason
|
||||
$token = User::generateToken($customer['id'], 1);
|
||||
if (!empty($token['token'])) {
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $customer['id'])
|
||||
->where('namebp', $package)
|
||||
->find_one();
|
||||
if ($tur) {
|
||||
$url = '?_route=home&recharge=' . $tur['id'] . '&uid=' . urlencode($token['token']);
|
||||
$msg = str_replace('[[payment_link]]', $url, $msg);
|
||||
}
|
||||
} else {
|
||||
$msg = str_replace('[[payment_link]]', '', $msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!empty($customer['phonenumber']) && strlen($customer['phonenumber']) > 5
|
||||
&& !empty($message) && in_array($via, ['sms', 'wa'])
|
||||
) {
|
||||
if ($via == 'sms') {
|
||||
echo Message::sendSMS($customer['phonenumber'], $msg);
|
||||
Message::sendSMS($customer['phonenumber'], $msg);
|
||||
} else if ($via == 'email') {
|
||||
self::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Internet Plan Reminder"), $msg);
|
||||
} else if ($via == 'wa') {
|
||||
echo Message::sendWhatsapp($customer['phonenumber'], $msg);
|
||||
Message::sendWhatsapp($customer['phonenumber'], $msg);
|
||||
}
|
||||
}
|
||||
return "$via: $msg";
|
||||
}
|
||||
|
||||
public static function sendBalanceNotification($cust, $balance, $balance_now, $message, $via)
|
||||
public static function sendBalanceNotification($cust, $target, $balance, $balance_now, $message, $via)
|
||||
{
|
||||
global $config;
|
||||
$msg = str_replace('[[name]]', $cust['fullname'] . ' (' . $cust['username'] . ')', $message);
|
||||
$msg = str_replace('[[name]]', $target['fullname'] . ' (' . $target['username'] . ')', $message);
|
||||
$msg = str_replace('[[current_balance]]', Lang::moneyFormat($balance_now), $msg);
|
||||
$msg = str_replace('[[balance]]', Lang::moneyFormat($balance), $msg);
|
||||
$phone = $cust['phonenumber'];
|
||||
@ -214,11 +267,12 @@ class Message
|
||||
) {
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($phone, $msg);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
} else if ($via == 'email') {
|
||||
self::sendEmail($cust['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Balance Notification"), $msg);
|
||||
} else if ($via == 'wa') {
|
||||
Message::sendWhatsapp($phone, $msg);
|
||||
}
|
||||
self::addToInbox($cust['id'], Lang::T('Balance Notification'), $msg);
|
||||
}
|
||||
return "$via: $msg";
|
||||
}
|
||||
@ -232,6 +286,7 @@ class Message
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $trx['invoice'], $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice);
|
||||
if (!empty($trx['note'])) {
|
||||
$textInvoice = str_replace('[[note]]', $trx['note'], $textInvoice);
|
||||
}
|
||||
@ -258,4 +313,16 @@ class Message
|
||||
Message::sendWhatsapp($cust['phonenumber'], $textInvoice);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function addToInbox($to_customer_id, $subject, $body, $from = 'System')
|
||||
{
|
||||
$v = ORM::for_table('tbl_customers_inbox')->create();
|
||||
$v->from = $from;
|
||||
$v->customer_id = $to_customer_id;
|
||||
$v->subject = $subject;
|
||||
$v->date_created = date('Y-m-d H:i:s');
|
||||
$v->body = nl2br($body);
|
||||
$v->save();
|
||||
}
|
||||
}
|
||||
|
118
system/autoload/Meta.php
Normal file
118
system/autoload/Meta.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
*
|
||||
* Meta is for save adtional information in database for every existing table
|
||||
*
|
||||
* * Good for Plugin, so plugin don't need to modify existing tables
|
||||
*
|
||||
* Example to put data
|
||||
* if plan need to add point value for loyalty poin
|
||||
* Meta::for("tbl_plans")->set(1, 'point', '24');
|
||||
* it means tbl_plans with id 1 have point value 24, customer will get 24 point for loyalty if buy plan with id 1
|
||||
* You need to create the logic for that, Meta only hold the data
|
||||
*
|
||||
* Example to get data
|
||||
* $point = Meta::for("tbl_plans")->get(1, 'point');
|
||||
* this will return the point value of plan with id 1
|
||||
*
|
||||
* to get all key value
|
||||
* $metas = Meta::for("tbl_plans")->getAll(1);
|
||||
*
|
||||
* to delete 1 data
|
||||
* Meta::for("tbl_plans")->delete(1, 'point');
|
||||
*
|
||||
* to delete all data
|
||||
* Meta::for("tbl_plans")->deleteAll(1);
|
||||
**/
|
||||
|
||||
|
||||
class Meta
|
||||
{
|
||||
protected $table = '';
|
||||
|
||||
protected function __construct($table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
public static function for($table)
|
||||
{
|
||||
return new self($table);
|
||||
}
|
||||
|
||||
public function get($id, $key)
|
||||
{
|
||||
// get the Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->find_one()['value'];
|
||||
}
|
||||
|
||||
public function getAll($id)
|
||||
{
|
||||
//get all key Value
|
||||
$metas = [];
|
||||
$result = ORM::for_table('tbl_meta')
|
||||
->select('name')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->find_array();
|
||||
foreach ($result as $value) {
|
||||
$metas[$value['name']] = $value['value'];
|
||||
}
|
||||
return $metas;
|
||||
}
|
||||
|
||||
public function set($id, $key, $value = '')
|
||||
{
|
||||
$meta = ORM::for_table('tbl_meta')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->find_one();
|
||||
if (!$meta) {
|
||||
$meta = ORM::for_table('tbl_meta')->create();
|
||||
$meta->tbl = $this->table;
|
||||
$meta->tbl_id = $id;
|
||||
$meta->name = $key;
|
||||
$meta->value = $value;
|
||||
$meta->save();
|
||||
$result = $meta->id();
|
||||
if ($result) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
$meta->value = $value;
|
||||
$meta->save();
|
||||
return $meta['id'];
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($id, $key = '')
|
||||
{
|
||||
// get the Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function deleteAll($id)
|
||||
{
|
||||
//get all key Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->delete_many();
|
||||
}
|
||||
}
|
@ -20,30 +20,33 @@ class Package
|
||||
*/
|
||||
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx, $_app_stage;
|
||||
$date_now = date("Y-m-d H:i:s");
|
||||
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx, $_app_stage, $isChangePlan;
|
||||
$date_only = date("Y-m-d");
|
||||
$time_only = date("H:i:s");
|
||||
$time = date("H:i:s");
|
||||
$inv = "";
|
||||
$isVoucher = false;
|
||||
$c = [];
|
||||
if ($trx && $trx['status'] == 2) {
|
||||
// if its already paid, return it
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id_customer == '' or $router_name == '' or $plan_id == '') {
|
||||
return false;
|
||||
}
|
||||
if(trim($gateway) == 'Voucher' && $id_customer == 0){
|
||||
if (trim($gateway) == 'Voucher' && $id_customer == 0) {
|
||||
$isVoucher = true;
|
||||
}
|
||||
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->find_one();
|
||||
|
||||
if(!$isVoucher){
|
||||
if (!$isVoucher) {
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
|
||||
if ($c['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($c['status']), 'danger', "");
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$c = [
|
||||
'fullname' => $gateway,
|
||||
'email' => '',
|
||||
@ -60,7 +63,7 @@ class Package
|
||||
} else {
|
||||
// Additional cost
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
if ($add_cost > 0 && $router_name != 'balance') {
|
||||
if ($add_cost != 0 && $router_name != 'balance') {
|
||||
foreach ($bills as $k => $v) {
|
||||
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
|
||||
}
|
||||
@ -71,10 +74,10 @@ class Package
|
||||
|
||||
if (!$p['enabled']) {
|
||||
if (!isset($admin) || !isset($admin['id']) || empty($admin['id'])) {
|
||||
r2(U . 'home', 'e', Lang::T('Plan Not found'));
|
||||
r2(getUrl('home'), 'e', Lang::T('Plan Not found'));
|
||||
}
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
r2(U . 'dashboard', 'e', Lang::T('Plan Not found'));
|
||||
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +85,7 @@ class Package
|
||||
// if customer has attribute Expired Date use it
|
||||
$day_exp = User::getAttribute("Expired Date", $c['id']);
|
||||
if (!$day_exp) {
|
||||
// if customer no attribute Expired Date use plan expired date
|
||||
// if customer no attribute Expired Date use plan expired date
|
||||
$day_exp = 20;
|
||||
if ($p['prepaid'] == 'no') {
|
||||
$day_exp = $p['expired_date'];
|
||||
@ -96,55 +99,11 @@ class Package
|
||||
|
||||
|
||||
if ($router_name == 'balance') {
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->plan_name = $p['name_plan'];
|
||||
$t->price = $p['price'];
|
||||
$t->recharged_on = $date_only;
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = $date_only;
|
||||
$t->time = $time;
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = $router_name;
|
||||
$t->type = "Balance";
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
return self::rechargeBalance($c, $p, $gateway, $channel);
|
||||
}
|
||||
|
||||
$balance_before = $c['balance'];
|
||||
Balance::plus($id_customer, $p['price']);
|
||||
$balance = $c['balance'] + $p['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat($date_now), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $p['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($p['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $c['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $c['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $c['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($c['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($c['phonenumber'], $textInvoice);
|
||||
}
|
||||
|
||||
return true;
|
||||
if ($router_name == 'Custom Balance') {
|
||||
return self::rechargeCustomBalance($c, $p, $gateway, $channel);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,9 +132,9 @@ class Package
|
||||
# because 1 customer can have 1 PPPOE and 1 Hotspot Plan in mikrotik
|
||||
//->where('prepaid', $p['prepaid'])
|
||||
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'));
|
||||
if($isVoucher){
|
||||
if ($isVoucher) {
|
||||
$query->where('username', $c['username']);
|
||||
}else{
|
||||
} else {
|
||||
$query->where('customer_id', $id_customer);
|
||||
}
|
||||
$b = $query->find_one();
|
||||
@ -185,17 +144,40 @@ class Package
|
||||
if ($p['validity_unit'] == 'Months') {
|
||||
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' month'));
|
||||
} else if ($p['validity_unit'] == 'Period') {
|
||||
$date_tmp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
|
||||
$dt1 = new DateTime("$date_only");
|
||||
$dt2 = new DateTime("$date_tmp");
|
||||
$diff = $dt2->diff($dt1);
|
||||
$sum = $diff->format("%a"); // => 453
|
||||
if ($sum >= 35 * $p['validity']) {
|
||||
$date_exp = date("Y-m-$day_exp", strtotime('+0 month'));
|
||||
} else {
|
||||
$date_exp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
|
||||
};
|
||||
$time = date("23:59:00");
|
||||
$current_date = new DateTime($date_only);
|
||||
$exp_date = clone $current_date;
|
||||
$exp_date->modify('first day of next month');
|
||||
$exp_date->setDate($exp_date->format('Y'), $exp_date->format('m'), $day_exp);
|
||||
|
||||
$min_days = 7 * $p['validity'];
|
||||
$max_days = 35 * $p['validity'];
|
||||
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
|
||||
// If less than min_days away, move to the next period
|
||||
while ($days_until_exp < $min_days) {
|
||||
$exp_date->modify('+1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// If more than max_days away, move to the previous period
|
||||
while ($days_until_exp > $max_days) {
|
||||
$exp_date->modify('-1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// Final check to ensure we're not less than min_days or in the past
|
||||
if ($days_until_exp < $min_days || $exp_date <= $current_date) {
|
||||
$exp_date->modify('+1 month');
|
||||
}
|
||||
|
||||
// Adjust for multiple periods
|
||||
if ($p['validity'] > 1) {
|
||||
$exp_date->modify('+' . ($p['validity'] - 1) . ' months');
|
||||
}
|
||||
|
||||
$date_exp = $exp_date->format('Y-m-d');
|
||||
$time = "23:59:59";
|
||||
} else if ($p['validity_unit'] == 'Days') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
|
||||
$date_exp = $datetime[0];
|
||||
@ -209,83 +191,115 @@ class Package
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
}
|
||||
$isChangePlan = false;
|
||||
|
||||
if ($b) {
|
||||
// plan exists
|
||||
if ($plan_id != $b['plan_id']) {
|
||||
$isChangePlan = true;
|
||||
}
|
||||
if ($config['extend_expiry'] != 'no') {
|
||||
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
|
||||
// if it same internet plan, expired will extend
|
||||
if ($p['validity_unit'] == 'Months') {
|
||||
$lastExpired = Lang::dateAndTimeFormat($b['expiration'], $b['time']);
|
||||
$isChangePlan = false;
|
||||
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on' && $config['extend_expiry'] == 'yes') {
|
||||
// if it same internet plan, expired will extend
|
||||
switch ($p['validity_unit']) {
|
||||
case 'Months':
|
||||
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
|
||||
$time = $b['time'];
|
||||
} else if ($p['validity_unit'] == 'Period') {
|
||||
break;
|
||||
case 'Period':
|
||||
$date_exp = date("Y-m-$day_exp", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
|
||||
$time = date("23:59:00");
|
||||
} else if ($p['validity_unit'] == 'Days') {
|
||||
break;
|
||||
case 'Days':
|
||||
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
|
||||
$time = $b['time'];
|
||||
} else if ($p['validity_unit'] == 'Hrs') {
|
||||
break;
|
||||
case 'Hrs':
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
} else if ($p['validity_unit'] == 'Mins') {
|
||||
break;
|
||||
case 'Mins':
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$isChangePlan = true;
|
||||
}
|
||||
|
||||
if ($isChangePlan || $b['status'] == 'off') {
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
//if ($b['status'] == 'on') {
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'Demo') {
|
||||
try {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
$b->customer_id = $id_customer;
|
||||
$b->username = $c['username'];
|
||||
$b->plan_id = $plan_id;
|
||||
$b->namebp = $p['name_plan'];
|
||||
$b->recharged_on = $date_only;
|
||||
$b->recharged_time = $time_only;
|
||||
$b->expiration = $date_exp;
|
||||
$b->time = $time;
|
||||
$b->status = "on";
|
||||
$b->method = "$gateway - $channel";
|
||||
$b->routers = $router_name;
|
||||
$b->type = $p['type'];
|
||||
if ($admin) {
|
||||
$b->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$b->admin_id = '0';
|
||||
// if contains 'mikrotik', 'hotspot', 'pppoe', 'radius' then recharge it
|
||||
if (Validator::containsKeyword($p['device'])) {
|
||||
$b->customer_id = $id_customer;
|
||||
$b->username = $c['username'];
|
||||
$b->plan_id = $plan_id;
|
||||
$b->namebp = $p['name_plan'];
|
||||
$b->recharged_on = $date_only;
|
||||
$b->recharged_time = $time_only;
|
||||
$b->expiration = $date_exp;
|
||||
$b->time = $time;
|
||||
$b->status = "on";
|
||||
$b->method = "$gateway - $channel";
|
||||
$b->routers = $router_name;
|
||||
$b->type = $p['type'];
|
||||
if ($admin) {
|
||||
$b->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$b->admin_id = '0';
|
||||
}
|
||||
$b->save();
|
||||
}
|
||||
$b->save();
|
||||
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->user_id = $id_customer;
|
||||
$t->plan_name = $p['name_plan'];
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
} else {
|
||||
$t->price = $add_inv + $add_cost;
|
||||
}
|
||||
if ($gateway == 'Voucher' && User::isUserVoucher($channel)) {
|
||||
//its already paid
|
||||
$t->price = 0;
|
||||
} else {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
} else {
|
||||
$t->price = $add_inv + $add_cost;
|
||||
}
|
||||
} else {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
}
|
||||
}
|
||||
$t->recharged_on = $date_only;
|
||||
$t->recharged_time = $time_only;
|
||||
@ -322,52 +336,83 @@ class Package
|
||||
"\nRouter: " . $router_name .
|
||||
"\nGateway: " . $gateway .
|
||||
"\nChannel: " . $channel .
|
||||
"\nLast Expired: $lastExpired" .
|
||||
"\nNew Expired: " . Lang::dateAndTimeFormat($date_exp, $time) .
|
||||
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
|
||||
"\nNote:\n" . $note);
|
||||
} else {
|
||||
// active plan not exists
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
if ($_app_stage != 'Demo') {
|
||||
try {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_user_recharges')->create();
|
||||
$d->customer_id = $id_customer;
|
||||
$d->username = $c['username'];
|
||||
$d->plan_id = $plan_id;
|
||||
$d->namebp = $p['name_plan'];
|
||||
$d->recharged_on = $date_only;
|
||||
$d->recharged_time = $time_only;
|
||||
$d->expiration = $date_exp;
|
||||
$d->time = $time;
|
||||
$d->status = "on";
|
||||
$d->method = "$gateway - $channel";
|
||||
$d->routers = $router_name;
|
||||
$d->type = $p['type'];
|
||||
if ($admin) {
|
||||
$d->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$d->admin_id = '0';
|
||||
// if contains 'mikrotik', 'hotspot', 'pppoe', 'radius' then recharge it
|
||||
if (Validator::containsKeyword($p['device'])) {
|
||||
$d = ORM::for_table('tbl_user_recharges')->create();
|
||||
$d->customer_id = $id_customer;
|
||||
$d->username = $c['username'];
|
||||
$d->plan_id = $plan_id;
|
||||
$d->namebp = $p['name_plan'];
|
||||
$d->recharged_on = $date_only;
|
||||
$d->recharged_time = $time_only;
|
||||
$d->expiration = $date_exp;
|
||||
$d->time = $time;
|
||||
$d->status = "on";
|
||||
$d->method = "$gateway - $channel";
|
||||
$d->routers = $router_name;
|
||||
$d->type = $p['type'];
|
||||
if ($admin) {
|
||||
$d->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$d->admin_id = '0';
|
||||
}
|
||||
$d->save();
|
||||
}
|
||||
$d->save();
|
||||
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->user_id = $id_customer;
|
||||
$t->plan_name = $p['name_plan'];
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// Postpaid price always zero for first time
|
||||
$note = '';
|
||||
$bills = [];
|
||||
if ($gateway == 'Voucher' && User::isUserVoucher($channel)) {
|
||||
$t->price = 0;
|
||||
// its already paid
|
||||
} else {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// Postpaid price always zero for first time
|
||||
$note = '';
|
||||
$bills = [];
|
||||
$t->price = 0;
|
||||
} else {
|
||||
$t->price = $p['price'] + $add_cost;
|
||||
}
|
||||
}
|
||||
$t->recharged_on = $date_only;
|
||||
$t->recharged_time = $time_only;
|
||||
@ -414,6 +459,7 @@ class Package
|
||||
"\nRouter: " . $router_name .
|
||||
"\nGateway: " . $gateway .
|
||||
"\nChannel: " . $channel .
|
||||
"\nExpired: " . Lang::dateAndTimeFormat($date_exp, $time) .
|
||||
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
|
||||
"\nNote:\n" . $note);
|
||||
}
|
||||
@ -429,6 +475,130 @@ class Package
|
||||
return $inv;
|
||||
}
|
||||
|
||||
public static function rechargeBalance($customer, $plan, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $admin, $config;
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $customer['username'];
|
||||
$t->user_id = $customer['id'];
|
||||
$t->plan_name = $plan['name_plan'];
|
||||
$t->price = $plan['price'];
|
||||
$t->recharged_on = date("Y-m-d");
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = date("Y-m-d");
|
||||
$t->time = date("H:i:s");
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = 'balance';
|
||||
$t->type = "Balance";
|
||||
$t->note = $note;
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
|
||||
$balance_before = $customer['balance'];
|
||||
Balance::plus($customer['id'], $plan['price']);
|
||||
$balance = $customer['balance'] + $plan['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $plan['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($plan['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $customer['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $customer['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $customer['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
Message::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv, $textInvoice);
|
||||
}
|
||||
return $t->id();
|
||||
}
|
||||
|
||||
public static function rechargeCustomBalance($customer, $plan, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $admin, $config;
|
||||
$plan = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $customer['username'])
|
||||
->where('routers', 'Custom Balance')
|
||||
->where('status', '1')
|
||||
->find_one();
|
||||
if (!$plan) {
|
||||
return false;
|
||||
}
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $customer['username'];
|
||||
$t->user_id = $customer['id'];
|
||||
$t->plan_name = 'Custom Balance';
|
||||
$t->price = $plan['price'];
|
||||
$t->recharged_on = date("Y-m-d");
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = date("Y-m-d");
|
||||
$t->time = date("H:i:s");
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = 'balance';
|
||||
$t->type = "Balance";
|
||||
$t->note = $note;
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
|
||||
$balance_before = $customer['balance'];
|
||||
Balance::plus($customer['id'], $plan['price']);
|
||||
$balance = $customer['balance'] + $plan['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $plan['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($plan['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $customer['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $customer['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $customer['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
Message::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv, $textInvoice);
|
||||
}
|
||||
return $t->id();
|
||||
}
|
||||
|
||||
public static function _raid()
|
||||
{
|
||||
return ORM::for_table('tbl_transactions')->max('id') + 1;
|
||||
@ -558,10 +728,10 @@ class Package
|
||||
public static function getDevice($plan)
|
||||
{
|
||||
global $DEVICE_PATH;
|
||||
if($plan === false){
|
||||
if ($plan === false) {
|
||||
return "none";
|
||||
}
|
||||
if(!isset($plan['device'])){
|
||||
if (!isset($plan['device'])) {
|
||||
return "none";
|
||||
}
|
||||
if (!empty($plan['device'])) {
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
class Paginator
|
||||
{
|
||||
public static function findMany($query, $search = [], $per_page = '10', $append_url = "")
|
||||
public static function findMany($query, $search = [], $per_page = '10', $append_url = "", $toArray = false)
|
||||
{
|
||||
global $routes, $ui;
|
||||
$adjacents = "2";
|
||||
$page = _get('p', 1);
|
||||
$page = (empty($page) ? 1 : $page);
|
||||
$url = U . implode('/', $routes);
|
||||
$url = getUrl(implode('/', $routes));
|
||||
if (count($search) > 0) {
|
||||
$url .= '&' . http_build_query($search);
|
||||
}
|
||||
@ -71,7 +71,11 @@ class Paginator
|
||||
if ($ui) {
|
||||
$ui->assign('paginator', $result);
|
||||
}
|
||||
return $query->offset($startpoint)->limit($per_page)->find_many();
|
||||
if($toArray){
|
||||
return $query->offset($startpoint)->limit($per_page)->find_array();
|
||||
}else{
|
||||
return $query->offset($startpoint)->limit($per_page)->find_many();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +83,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . implode('/', $routes);
|
||||
$url = getUrl(implode('/', $routes));
|
||||
$query = urlencode($query);
|
||||
$adjacents = "2";
|
||||
$page = (int)(empty(_get('p')) ? 1 : _get('p'));
|
||||
@ -165,7 +169,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
|
||||
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
|
||||
$adjacents = "2";
|
||||
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
|
||||
$pagination = "";
|
||||
@ -273,7 +277,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
|
||||
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
|
||||
$adjacents = "2";
|
||||
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
|
||||
$pagination = "";
|
||||
|
@ -32,4 +32,19 @@ class Password
|
||||
$pass = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#!123456789', 8)), 0, 8);
|
||||
return $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify CHAP password
|
||||
* @param string $realPassword
|
||||
* @param string $CHAPassword
|
||||
* @param string $CHAPChallenge
|
||||
* @return bool
|
||||
*/
|
||||
public static function chap_verify($realPassword, $CHAPassword, $CHAPChallenge){
|
||||
$CHAPassword = substr($CHAPassword, 2);
|
||||
$chapid = substr($CHAPassword, 0, 2);
|
||||
$result = hex2bin($chapid) . $realPassword . hex2bin(substr($CHAPChallenge, 2));
|
||||
$response = $chapid . md5($result);
|
||||
return ($response != $CHAPassword);
|
||||
}
|
||||
}
|
||||
|
@ -44,16 +44,17 @@ class Text
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function maskText($text){
|
||||
public static function maskText($text)
|
||||
{
|
||||
$len = strlen($text);
|
||||
if($len < 3){
|
||||
if ($len < 3) {
|
||||
return "***";
|
||||
}else if($len<5){
|
||||
return substr($text,0,1)."***".substr($text,-1,1);
|
||||
}else if($len<8){
|
||||
return substr($text,0,2)."***".substr($text,-2,2);
|
||||
}else{
|
||||
return substr($text,0,4)."******".substr($text,-3,3);
|
||||
} else if ($len < 5) {
|
||||
return substr($text, 0, 1) . "***" . substr($text, -1, 1);
|
||||
} else if ($len < 8) {
|
||||
return substr($text, 0, 2) . "***" . substr($text, -2, 2);
|
||||
} else {
|
||||
return substr($text, 0, 4) . "******" . substr($text, -3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,4 +62,67 @@ class Text
|
||||
{
|
||||
return preg_replace("/[^A-Za-z0-9]/", '_', $str);;
|
||||
}
|
||||
|
||||
public static function is_html($string)
|
||||
{
|
||||
return preg_match("/<[^<]+>/", $string, $m) != 0;
|
||||
}
|
||||
|
||||
public static function convertDataUnit($datalimit, $unit = 'MB')
|
||||
{
|
||||
$unit = strtoupper($unit);
|
||||
if ($unit == 'KB') {
|
||||
return $datalimit * 1024;
|
||||
} elseif ($unit == 'MB') {
|
||||
return $datalimit * 1048576;
|
||||
} elseif ($unit == 'GB') {
|
||||
return $datalimit * 1073741824;
|
||||
} elseif ($unit == 'TB') {
|
||||
return $datalimit * 1099511627776;
|
||||
} else {
|
||||
return $datalimit;
|
||||
}
|
||||
}
|
||||
|
||||
// echo Json array to text
|
||||
public static function jsonArray2text($array, $start = '', $result = '')
|
||||
{
|
||||
foreach ($array as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$result .= self::jsonArray2text($v, "$start$k.", '');
|
||||
} else {
|
||||
$result .= "$start$k = " . strval($v) . "\n";
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function jsonArray21Array($array){
|
||||
$text = self::jsonArray2text($array);
|
||||
$lines = explode("\n", $text);
|
||||
$result = [];
|
||||
foreach($lines as $line){
|
||||
$parts = explode(' = ', $line);
|
||||
if(count($parts) == 2){
|
||||
$result[trim($parts[0])] = trim($parts[1]);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function url(...$data){
|
||||
global $config;
|
||||
$url = implode("", $data);
|
||||
if ($config['url_canonical'] == 'yes') {
|
||||
$u = str_replace('?_route=', '', U);
|
||||
$pos = strpos($url, '&');
|
||||
if ($pos === false) {
|
||||
return $u . $url;
|
||||
} else {
|
||||
return $u . substr($url, 0, $pos) . '?' . substr($url, $pos + 1);
|
||||
}
|
||||
} else {
|
||||
return U . $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,13 @@ class User
|
||||
{
|
||||
public static function getID()
|
||||
{
|
||||
global $db_password;
|
||||
global $db_pass;
|
||||
if (isset($_SESSION['uid']) && !empty($_SESSION['uid'])) {
|
||||
return $_SESSION['uid'];
|
||||
} else if (isset($_COOKIE['uid'])) {
|
||||
// id.time.sha1
|
||||
$tmp = explode('.', $_COOKIE['uid']);
|
||||
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_password) == $tmp[2]) {
|
||||
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_pass) == $tmp[2]) {
|
||||
if (time() - $tmp[1] < 86400 * 30) {
|
||||
$_SESSION['uid'] = $tmp[0];
|
||||
return $tmp[0];
|
||||
@ -26,6 +26,15 @@ class User
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function getTawkToHash($email)
|
||||
{
|
||||
global $config;
|
||||
if (!empty($config['tawkto_api_key']) && !Empty($email)) {
|
||||
return hash_hmac('sha256', $email, $config['tawkto_api_key']);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getBills($id = 0)
|
||||
{
|
||||
if (!$id) {
|
||||
@ -123,7 +132,7 @@ class User
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function getAttribute($name, $id = 0)
|
||||
public static function getAttribute($name, $id = 0, $default = '')
|
||||
{
|
||||
if (!$id) {
|
||||
$id = User::getID();
|
||||
@ -135,7 +144,7 @@ class User
|
||||
if ($f) {
|
||||
return $f['field_value'];
|
||||
}
|
||||
return '';
|
||||
return $default;
|
||||
}
|
||||
|
||||
public static function getAttributes($endWith, $id = 0)
|
||||
@ -157,12 +166,31 @@ class User
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function generateToken($uid, $validDays = 30)
|
||||
{
|
||||
global $db_pass;
|
||||
if($validDays>=30){
|
||||
$time = time();
|
||||
}else{
|
||||
// for customer, deafult expired is 30 days
|
||||
$time = strtotime('+ '.(30 - $validDays).' days');
|
||||
}
|
||||
|
||||
return [
|
||||
'time' => $time,
|
||||
'token' => $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_pass)
|
||||
];
|
||||
}
|
||||
|
||||
public static function setCookie($uid)
|
||||
{
|
||||
global $db_password;
|
||||
global $db_pass;
|
||||
if (isset($uid)) {
|
||||
$time = time();
|
||||
setcookie('uid', $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_password), time() + 86400 * 30);
|
||||
$token = self::generateToken($uid);
|
||||
setcookie('uid', $token['token'], time() + 86400 * 30);
|
||||
return $token;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +206,7 @@ class User
|
||||
global $config;
|
||||
if ($config['maintenance_mode'] == true) {
|
||||
if ($config['maintenance_mode_logout'] == true) {
|
||||
r2(U . 'logout', 'd', '');
|
||||
r2(getUrl('logout'), 'd', '');
|
||||
} else {
|
||||
displayMaintenanceMessage();
|
||||
}
|
||||
@ -190,12 +218,32 @@ class User
|
||||
if ($d['status'] == 'Banned') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "logout");
|
||||
}
|
||||
if (empty($d['username'])) {
|
||||
r2(U . 'logout', 'd', '');
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function _infoByName($username)
|
||||
{
|
||||
global $config;
|
||||
if ($config['maintenance_mode'] == true) {
|
||||
if ($config['maintenance_mode_logout'] == true) {
|
||||
r2(getUrl('logout'), 'd', '');
|
||||
} else {
|
||||
displayMaintenanceMessage();
|
||||
}
|
||||
}
|
||||
$d = ORM::for_table('tbl_customers')->where("username", $username)->find_one();
|
||||
if ($d['status'] == 'Banned') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "logout");
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function isUserVoucher($kode)
|
||||
{
|
||||
$regex = '/^GC\d+C.{10}$/';
|
||||
return preg_match($regex, $kode);
|
||||
}
|
||||
|
||||
public static function _billing($id = 0)
|
||||
{
|
||||
if (!$id) {
|
||||
@ -204,15 +252,70 @@ class User
|
||||
$d = ORM::for_table('tbl_user_recharges')
|
||||
->select('tbl_user_recharges.id', 'id')
|
||||
->selects([
|
||||
'customer_id', 'username', 'plan_id', 'namebp', 'recharged_on', 'recharged_time', 'expiration', 'time',
|
||||
'status', 'method', 'plan_type',
|
||||
'customer_id',
|
||||
'username',
|
||||
'plan_id',
|
||||
'namebp',
|
||||
'recharged_on',
|
||||
'recharged_time',
|
||||
'expiration',
|
||||
'time',
|
||||
'status',
|
||||
'method',
|
||||
'plan_type',
|
||||
['tbl_user_recharges.routers', 'routers'],
|
||||
['tbl_user_recharges.type', 'type'],
|
||||
'admin_id', 'prepaid'
|
||||
'admin_id',
|
||||
'prepaid'
|
||||
])
|
||||
->left_outer_join('tbl_plans', ['tbl_plans.id', '=', 'tbl_user_recharges.plan_id'])
|
||||
->left_outer_join('tbl_bandwidth', ['tbl_bandwidth.id', '=', 'tbl_plans.id_bw'])
|
||||
->select('tbl_bandwidth.name_bw', 'name_bw')
|
||||
->select('tbl_plans.price', 'price')
|
||||
->where('customer_id', $id)
|
||||
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
|
||||
->find_many();
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function setFormCustomField($uid = 0){
|
||||
global $UPLOAD_PATH;
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
if(!file_exists($fieldPath)){
|
||||
return '';
|
||||
}
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
foreach($fields as $field){
|
||||
if(!empty(_post($field['name']))){
|
||||
self::setAttribute($field['name'], _post($field['name']), $uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getFormCustomField($ui, $register = false, $uid = 0){
|
||||
global $UPLOAD_PATH;
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
if(!file_exists($fieldPath)){
|
||||
return '';
|
||||
}
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
$attrs = [];
|
||||
if(!$register){
|
||||
$attrs = self::getAttributes('', $uid);
|
||||
$ui->assign('attrs', $attrs);
|
||||
}
|
||||
$html = '';
|
||||
$ui->assign('register', $register);
|
||||
foreach($fields as $field){
|
||||
if($register){
|
||||
if($field['register']){
|
||||
$ui->assign('field', $field);
|
||||
$html .= $ui->fetch('customer/custom_field.tpl');
|
||||
}
|
||||
}else{
|
||||
$ui->assign('field', $field);
|
||||
$html .= $ui->fetch('customer/custom_field.tpl');
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
@ -301,23 +301,30 @@ class Validator
|
||||
return (bool)in_array($format, $formats);
|
||||
}
|
||||
|
||||
public static function countRouterPlan($plans, $router){
|
||||
public static function countRouterPlan($plans, $router)
|
||||
{
|
||||
$n = 0;
|
||||
foreach ($plans as $plan){
|
||||
if($plan['routers'] == $router){
|
||||
foreach ($plans as $plan) {
|
||||
if ($plan['routers'] == $router) {
|
||||
$n++;
|
||||
}
|
||||
}
|
||||
return $n;
|
||||
}
|
||||
|
||||
public static function isRouterHasPlan($plans, $router){
|
||||
foreach ($plans as $plan){
|
||||
if($plan['routers'] == $router){
|
||||
public static function isRouterHasPlan($plans, $router)
|
||||
{
|
||||
foreach ($plans as $plan) {
|
||||
if ($plan['routers'] == $router) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function containsKeyword($string, $keywords = ['mikrotik', 'hotspot', 'pppoe', 'radius', 'dummy'])
|
||||
{
|
||||
$regex = '/' . implode('|', $keywords) . '/i';
|
||||
return preg_match($regex, strtolower($string));
|
||||
}
|
||||
}
|
||||
|
@ -43,9 +43,10 @@ $ui->setConfigDir(File::pathFixer($UI_PATH . '/conf/'));
|
||||
$ui->setCacheDir(File::pathFixer($UI_PATH . '/cache/'));
|
||||
$ui->assign('app_url', APP_URL);
|
||||
$ui->assign('_domain', str_replace('www.', '', parse_url(APP_URL, PHP_URL_HOST)));
|
||||
$ui->assign('_url', APP_URL . '/index.php?_route=');
|
||||
$ui->assign('_url', APP_URL . '/?_route=');
|
||||
$ui->assign('_path', __DIR__);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('user_language', $_SESSION['user_language']);
|
||||
$ui->assign('UPLOAD_PATH', str_replace($root_path, '', $UPLOAD_PATH));
|
||||
$ui->assign('CACHE_PATH', str_replace($root_path, '', $CACHE_PATH));
|
||||
$ui->assign('PAGES_PATH', str_replace($root_path, '', $PAGES_PATH));
|
||||
@ -66,16 +67,24 @@ if (isset($_SESSION['notify'])) {
|
||||
unset($_SESSION['ntype']);
|
||||
}
|
||||
|
||||
// Routing Engine
|
||||
$req = _get('_route');
|
||||
if(!isset($_GET['_route'])) {
|
||||
$req = ltrim(parse_url($_SERVER['REQUEST_URI'])['path'], '/');
|
||||
}else{
|
||||
// Routing Engine
|
||||
$req = _get('_route');
|
||||
}
|
||||
$routes = explode('/', $req);
|
||||
$ui->assign('_routes', $routes);
|
||||
$handler = $routes[0];
|
||||
if ($handler == '') {
|
||||
$handler = 'default';
|
||||
}
|
||||
$admin = Admin::_info();
|
||||
|
||||
try {
|
||||
if(!empty($_GET['uid'])){
|
||||
$_COOKIE['uid'] = $_GET['uid'];
|
||||
}
|
||||
$admin = Admin::_info();
|
||||
$sys_render = $root_path . File::pathFixer('system/controllers/' . $handler . '.php');
|
||||
if (file_exists($sys_render)) {
|
||||
$menus = array();
|
||||
@ -87,7 +96,7 @@ try {
|
||||
foreach ($menu_registered as $menu) {
|
||||
if ($menu['admin'] && _admin(false)) {
|
||||
if (count($menu['auth']) == 0 || in_array($admin['user_type'], $menu['auth'])) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . getUrl('plugin/' . $menu['function']) . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
@ -98,7 +107,7 @@ try {
|
||||
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
|
||||
}
|
||||
} else if (!$menu['admin'] && _auth(false)) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . getUrl('plugin/' . $menu['function']) . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
@ -115,7 +124,11 @@ try {
|
||||
unset($menus, $menu_registered);
|
||||
include($sys_render);
|
||||
} else {
|
||||
r2(U . 'dashboard', 'e', 'not found');
|
||||
// header 404
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
header("Content-Type: text/html; charset=utf-8");
|
||||
echo "404 Not Found";
|
||||
die();
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
@ -123,12 +136,12 @@ try {
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
if (empty($_SESSION['aid'])) {
|
||||
$ui->display('customer/error.tpl'); die();
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('error.tpl');
|
||||
die();
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
@ -136,11 +149,11 @@ try {
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
if (empty($_SESSION['aid'])) {
|
||||
$ui->display('customer/error.tpl'); die();
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('error.tpl');
|
||||
die();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"mpdf/mpdf": "^8.1",
|
||||
"smarty/smarty": "=4.5.3"
|
||||
"smarty/smarty": "=4.5.3",
|
||||
"yosiazwan/php-facedetection": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
44
system/composer.lock
generated
44
system/composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "a33a5e0440af423877195440decefd29",
|
||||
"content-hash": "a5f201dce3d594a500f2b9e9a8532e66",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mpdf/mpdf",
|
||||
@ -476,6 +476,48 @@
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.5.3"
|
||||
},
|
||||
"time": "2024-05-28T21:46:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "yosiazwan/php-facedetection",
|
||||
"version": "0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yosiazwan/php-facedetection.git",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yosiazwan/php-facedetection/zipball/b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"FaceDetector.php",
|
||||
"Exception/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maurice Svay",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to detect one face in images. A pure PHP port of an existing JS code from Karthik Tharavad.",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection",
|
||||
"support": {
|
||||
"source": "https://github.com/yosiazwan/php-facedetection/tree/0.1.0"
|
||||
},
|
||||
"time": "2016-01-26T22:10:00+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@ -18,11 +18,17 @@ switch ($action) {
|
||||
|
||||
case 'change-password':
|
||||
run_hook('customer_view_change_password'); #HOOK
|
||||
$ui->display('user-change-password.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('customer/change-password.tpl');
|
||||
break;
|
||||
|
||||
case 'change-password-post':
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
run_hook('customer_change_password'); #HOOK
|
||||
if ($password != '') {
|
||||
$d_pass = $user['password'];
|
||||
@ -30,14 +36,14 @@ switch ($action) {
|
||||
$cnpass = _post('cnpass');
|
||||
if ($password == $d_pass) {
|
||||
if (!Validator::Length($password, 36, 2)) {
|
||||
r2(U . 'accounts/change-password', 'e', 'New Password must be 2 to 35 character');
|
||||
r2(getUrl('accounts/change-password'), 'e', 'New Password must be 2 to 35 character');
|
||||
}
|
||||
if ($npass != $cnpass) {
|
||||
r2(U . 'accounts/change-password', 'e', 'Both Password should be same');
|
||||
r2(getUrl('accounts/change-password'), 'e', 'Both Password should be same');
|
||||
}
|
||||
$user->password = $npass;
|
||||
$turs = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->find_many();
|
||||
foreach($turs as $tur) {
|
||||
foreach ($turs as $tur) {
|
||||
// if has active plan, change the password to devices
|
||||
if ($tur['status'] == 'on') {
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
@ -58,125 +64,172 @@ switch ($action) {
|
||||
_log('[' . $user['username'] . ']: Password changed successfully', 'User', $user['id']);
|
||||
_alert(Lang::T('Password changed successfully, Please login again'), 'success', "login");
|
||||
} else {
|
||||
die($password);
|
||||
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'profile':
|
||||
$d = ORM::for_table('tbl_customers')->find_one($user['id']);
|
||||
if ($d) {
|
||||
run_hook('customer_view_edit_profile'); #HOOK
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('user-profile.tpl');
|
||||
} else {
|
||||
r2(U . 'home', 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
run_hook('customer_view_edit_profile'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, false, $user['id']));
|
||||
$ui->display('customer/profile.tpl');
|
||||
break;
|
||||
|
||||
case 'edit-profile-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$fullname = _post('fullname');
|
||||
$address = _post('address');
|
||||
$email = _post('email');
|
||||
$phonenumber = _post('phonenumber');
|
||||
run_hook('customer_edit_profile'); #HOOK
|
||||
$msg = '';
|
||||
if (Validator::Length($fullname, 31, 2) == false) {
|
||||
$msg .= 'Full Name should be between 3 to 30 characters' . '<br>';
|
||||
if (Validator::Length($fullname, 31, 1) == false) {
|
||||
$msg .= 'Full Name should be between 1 to 30 characters' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($phonenumber) == false) {
|
||||
$msg .= 'Phone Number must be a number' . '<br>';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_customers')->find_one($user['id']);
|
||||
if ($d) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
if (empty($msg)) {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($user['photo'] != '' && strpos($user['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $user['photo'])) {
|
||||
unlink($UPLOAD_PATH . $user['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $user['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $user['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
$d->fullname = $fullname;
|
||||
$d->address = $address;
|
||||
$d->email = $email;
|
||||
$d->phonenumber = $phonenumber;
|
||||
$d->save();
|
||||
$user->fullname = $fullname;
|
||||
$user->address = $address;
|
||||
if ($_c['allow_phone_otp'] != 'yes') {
|
||||
$user->phonenumber = $phonenumber;
|
||||
}
|
||||
if ($_c['allow_email_otp'] != 'yes') {
|
||||
$user->email = $email;
|
||||
}
|
||||
|
||||
User::setFormCustomField($user['id']);
|
||||
|
||||
$user->save();
|
||||
|
||||
_log('[' . $user['username'] . ']: ' . Lang::T('User Updated Successfully'), 'User', $user['id']);
|
||||
r2(U . 'accounts/profile', 's', Lang::T('User Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'accounts/profile', 'e', $msg);
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('User Updated Successfully'));
|
||||
}else{
|
||||
r2(getUrl('accounts/profile'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'phone-update':
|
||||
|
||||
$d = ORM::for_table('tbl_customers')->find_one($user['id']);
|
||||
if ($d) {
|
||||
//run_hook('customer_view_edit_profile'); #HOOK
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('new_phone', $_SESSION['new_phone']);
|
||||
$ui->display('user-phone-update.tpl');
|
||||
} else {
|
||||
r2(U . 'home', 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('new_phone', $_SESSION['new_phone']);
|
||||
$ui->display('customer/phone-update.tpl');
|
||||
break;
|
||||
|
||||
case 'phone-update-otp':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$phone = Lang::phoneFormat(_post('phone'));
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/sms/';
|
||||
$_SESSION['new_phone'] = $phone;
|
||||
// Validate the phone number format
|
||||
if (!preg_match('/^[0-9]{10,}$/', $phone)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
|
||||
if (!preg_match('/^[0-9]{10,}$/', $phone) || empty($phone)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
|
||||
}
|
||||
|
||||
if (empty($config['sms_url'])) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
}
|
||||
|
||||
if (!empty($config['sms_url'])) {
|
||||
if (!empty($phone)) {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->where('phonenumber', $phone)->find_one();
|
||||
if ($d) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('You cannot use your current phone number'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
touch($otpPath . 'index.html');
|
||||
}
|
||||
$otpFile = $otpPath . sha1($username . $db_password) . ".txt";
|
||||
$phoneFile = $otpPath . sha1($username . $db_password) . "_phone.txt";
|
||||
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('phonenumber', $phone)->find_one();
|
||||
if ($d) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Phone number already registered by another customer'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
touch($otpPath . 'index.html');
|
||||
}
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
$phoneFile = $otpPath . sha1($username . $db_pass) . "_phone.txt";
|
||||
|
||||
// expired 10 minutes
|
||||
if (file_exists($otpFile) && time() - filemtime($otpFile) < 1200) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Please wait ' . (1200 - (time() - filemtime($otpFile))) . ' seconds before sending another SMS'));
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpFile, $otp);
|
||||
file_put_contents($phoneFile, $phone);
|
||||
// send send OTP to user
|
||||
if ($config['phone_otp_type'] === 'sms') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
} elseif ($config['phone_otp_type'] === 'whatsapp') {
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
} elseif ($config['phone_otp_type'] === 'both') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
}
|
||||
//redirect after sending OTP
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code has been sent to your phone'));
|
||||
}
|
||||
// expired 10 minutes
|
||||
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another SMS'));
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpFile, $otp);
|
||||
file_put_contents($phoneFile, $phone);
|
||||
// send send OTP to user
|
||||
if ($config['phone_otp_type'] === 'sms') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
} elseif ($config['phone_otp_type'] === 'whatsapp') {
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
} elseif ($config['phone_otp_type'] === 'both') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
}
|
||||
//redirect after sending OTP
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code has been sent to your phone'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'phone-update-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$phone = Lang::phoneFormat(_post('phone'));
|
||||
$otp_code = _post('otp');
|
||||
$username = $user['username'];
|
||||
@ -184,59 +237,186 @@ switch ($action) {
|
||||
|
||||
// Validate the phone number format
|
||||
if (!preg_match('/^[0-9]{10,}$/', $phone)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
|
||||
}
|
||||
|
||||
if (empty($config['sms_url'])) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
}
|
||||
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
$phoneFile = $otpPath . sha1($username . $db_pass) . "_phone.txt";
|
||||
|
||||
// Check if OTP file exists
|
||||
if (!file_exists($otpFile)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please request OTP first'));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!empty($config['sms_url'])) {
|
||||
$otpFile = $otpPath . sha1($username . $db_password) . ".txt";
|
||||
$phoneFile = $otpPath . sha1($username . $db_password) . "_phone.txt";
|
||||
|
||||
// Check if OTP file exists
|
||||
if (!file_exists($otpFile)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Please request OTP first'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// expired 10 minutes
|
||||
if (time() - filemtime($otpFile) > 1200) {
|
||||
unlink($otpFile);
|
||||
unlink($phoneFile);
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code expired'));
|
||||
exit();
|
||||
} else {
|
||||
$code = file_get_contents($otpFile);
|
||||
|
||||
// Check if OTP code matches
|
||||
if ($code != $otp_code) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Wrong Verification code'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the phone number matches the one that requested the OTP
|
||||
$savedPhone = file_get_contents($phoneFile);
|
||||
if ($savedPhone !== $phone) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('The phone number does not match the one that requested the OTP'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// OTP verification successful, delete OTP and phone number files
|
||||
unlink($otpFile);
|
||||
unlink($phoneFile);
|
||||
}
|
||||
} else {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not available'));
|
||||
// expired 10 minutes
|
||||
if (time() - filemtime($otpFile) > 1200) {
|
||||
unlink($otpFile);
|
||||
unlink($phoneFile);
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code expired'));
|
||||
exit();
|
||||
} else {
|
||||
$code = file_get_contents($otpFile);
|
||||
|
||||
// Check if OTP code matches
|
||||
if ($code != $otp_code) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Wrong Verification code'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the phone number matches the one that requested the OTP
|
||||
$savedPhone = file_get_contents($phoneFile);
|
||||
if ($savedPhone !== $phone) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('The phone number does not match the one that requested the OTP'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// OTP verification successful, delete OTP and phone number files
|
||||
unlink($otpFile);
|
||||
unlink($phoneFile);
|
||||
}
|
||||
|
||||
// Update the phone number in the database
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($d) {
|
||||
$d->phonenumber = Lang::phoneFormat($phone);
|
||||
$d->save();
|
||||
$user->phonenumber = Lang::phoneFormat($phone);
|
||||
$user->save();
|
||||
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('Phone number updated successfully'));
|
||||
break;
|
||||
|
||||
case 'email-update':
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('new_email', $_SESSION['new_email']);
|
||||
$ui->display('customer/email-update.tpl');
|
||||
break;
|
||||
case 'email-update-otp':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$email = trim(_post('email'));
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/email/';
|
||||
$_SESSION['new_email'] = $email;
|
||||
// Validate the phone number format
|
||||
if (!Validator::Email($email)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
|
||||
}
|
||||
|
||||
r2(U . 'accounts/profile', 's', Lang::T('Phone number updated successfully'));
|
||||
if (empty($config['smtp_host'])) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('email', $email)->find_one();
|
||||
if ($d) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email already used by another Customer'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
touch($otpPath . 'index.html');
|
||||
}
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
$emailFile = $otpPath . sha1($username . $db_pass) . "_email.txt";
|
||||
|
||||
// expired 10 minutes
|
||||
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another Email'));
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpFile, $otp);
|
||||
file_put_contents($emailFile, $email);
|
||||
// send OTP to user
|
||||
$body = Lang::T("Hello") . ' ' . $user['fullname'] . ",\n\n" . Lang::T("Your Email Verification Code is:") . " $otp";
|
||||
Message::sendEmail($email, Lang::T('Change Email Verification Code'), $body);
|
||||
//redirect after sending OTP
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code has been sent to your email. Check Spam folder if not found.'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'email-update-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$email = trim(_post('email'));
|
||||
$otp_code = _post('otp');
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/email/';
|
||||
// Validate the phone number format
|
||||
if (!Validator::Email($email)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (empty($config['smtp_host'])) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
}
|
||||
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
$emailFile = $otpPath . sha1($username . $db_pass) . "_email.txt";
|
||||
|
||||
// Check if OTP file exists
|
||||
if (!file_exists($otpFile)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please request OTP first'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// expired 10 minutes
|
||||
if (time() - filemtime($otpFile) > 1200) {
|
||||
unlink($otpFile);
|
||||
unlink($emailFile);
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code expired'));
|
||||
exit();
|
||||
} else {
|
||||
$code = file_get_contents($otpFile);
|
||||
|
||||
// Check if OTP code matches
|
||||
if ($code != $otp_code) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Wrong Verification code'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the phone number matches the one that requested the OTP
|
||||
$savedEmail = file_get_contents($emailFile);
|
||||
if ($savedEmail !== $email) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('The Email Address does not match the one that requested the OTP'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// OTP verification successful, delete OTP and phone number files
|
||||
unlink($otpFile);
|
||||
unlink($emailFile);
|
||||
}
|
||||
|
||||
$user->email = $email;
|
||||
$user->save();
|
||||
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('Email Address updated successfully'));
|
||||
break;
|
||||
|
||||
case 'language-update-post':
|
||||
global $root_path;
|
||||
$selected_language = _req('lang', 'english');
|
||||
|
||||
$_SESSION['user_language'] = $selected_language;
|
||||
|
||||
$lan_file = $root_path . File::pathFixer('system/lan/' . $selected_language . '.json');
|
||||
|
||||
if (file_exists($lan_file)) {
|
||||
$_L = json_decode(file_get_contents($lan_file), true);
|
||||
} else {
|
||||
$_L['author'] = 'Auto Generated by iBNuX Script';
|
||||
file_put_contents($lan_file, json_encode($_L));
|
||||
}
|
||||
User::setAttribute("Language", $selected_language);
|
||||
r2($_SERVER['HTTP_REFERER'], 's', ucwords($selected_language));
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -5,8 +5,12 @@
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
if(Admin::getID()){
|
||||
r2(U.'dashboard', "s", Lang::T("You are already logged in"));
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
if (Admin::getID()) {
|
||||
r2(getUrl('dashboard'), "s", Lang::T("You are already logged in"));
|
||||
}
|
||||
|
||||
if (isset($routes['1'])) {
|
||||
@ -19,6 +23,11 @@ switch ($do) {
|
||||
case 'post':
|
||||
$username = _post('username');
|
||||
$password = _post('password');
|
||||
//csrf token
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_alert(Lang::T('Invalid or Expired CSRF Token') . ".", 'danger', "admin");
|
||||
}
|
||||
run_hook('admin_login'); #HOOK
|
||||
if ($username != '' and $password != '') {
|
||||
$d = ORM::for_table('tbl_users')->where('username', $username)->find_one();
|
||||
@ -32,26 +41,28 @@ switch ($do) {
|
||||
_log($username . ' ' . Lang::T('Login Successful'), $d['user_type'], $d['id']);
|
||||
if ($isApi) {
|
||||
if ($token) {
|
||||
showResult(true, Lang::T('Login Successful'), ['token' => "a.".$token]);
|
||||
showResult(true, Lang::T('Login Successful'), ['token' => "a." . $token]);
|
||||
} else {
|
||||
showResult(false, Lang::T('Invalid Username or Password'));
|
||||
}
|
||||
}
|
||||
_alert(Lang::T('Login Successful'),'success', "dashboard");
|
||||
_alert(Lang::T('Login Successful'), 'success', "dashboard");
|
||||
} else {
|
||||
_log($username . ' ' . Lang::T('Failed Login'), $d['user_type']);
|
||||
_alert(Lang::T('Invalid Username or Password').".",'danger', "admin");
|
||||
_alert(Lang::T('Invalid Username or Password') . ".", 'danger', "admin");
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Invalid Username or Password')."..",'danger', "admin");
|
||||
_alert(Lang::T('Invalid Username or Password') . "..", 'danger', "admin");
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Invalid Username or Password')."...",'danger', "admin");
|
||||
_alert(Lang::T('Invalid Username or Password') . "...", 'danger', "admin");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
run_hook('view_login'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin-login.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
@ -18,37 +19,83 @@ $ui->assign('_admin', $admin);
|
||||
switch ($action) {
|
||||
case 'pool':
|
||||
$routers = _get('routers');
|
||||
if(empty($routers)){
|
||||
if (empty($routers)) {
|
||||
$d = ORM::for_table('tbl_pool')->find_many();
|
||||
}else{
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_pool')->where('routers', $routers)->find_many();
|
||||
}
|
||||
$ui->assign('routers', $routers);
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('autoload-pool.tpl');
|
||||
break;
|
||||
|
||||
case 'bw_name':
|
||||
$bw = ORM::for_table('tbl_bandwidth')->select("name_bw")->find_one($routes['2']);
|
||||
echo $bw['name_bw'];
|
||||
die();
|
||||
case 'balance':
|
||||
$balance = ORM::for_table('tbl_customers')->select("balance")->find_one($routes['2'])['balance'];
|
||||
if ($routes['3'] == '1') {
|
||||
echo Lang::moneyFormat($balance);
|
||||
} else {
|
||||
echo $balance;
|
||||
}
|
||||
die();
|
||||
case 'server':
|
||||
$d = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
$ui->assign('d', $d);
|
||||
|
||||
$ui->display('autoload-server.tpl');
|
||||
break;
|
||||
|
||||
case 'pppoe_ip_used':
|
||||
if (!empty(_get('ip'))) {
|
||||
$cs = ORM::for_table('tbl_customers')
|
||||
->select("username")
|
||||
->where_not_equal('id', _get('id'))
|
||||
->where("pppoe_ip", _get('ip'))
|
||||
->findArray();
|
||||
if (count($cs) > 0) {
|
||||
$c = array_column($cs, 'username');
|
||||
die(Lang::T("IP has been used by") . ' : ' . implode(", ", $c));
|
||||
}
|
||||
}
|
||||
die();
|
||||
case 'pppoe_username_used':
|
||||
if (!empty(_get('u'))) {
|
||||
$cs = ORM::for_table('tbl_customers')
|
||||
->select("username")
|
||||
->where_not_equal('id', _get('id'))
|
||||
->where("pppoe_username", _get('u'))
|
||||
->findArray();
|
||||
if (count($cs) > 0) {
|
||||
$c = array_column($cs, 'username');
|
||||
die(Lang::T("Username has been used by") . ' : ' . implode(", ", $c));
|
||||
}
|
||||
}
|
||||
die();
|
||||
case 'plan':
|
||||
$server = _post('server');
|
||||
$jenis = _post('jenis');
|
||||
if(in_array($admin['user_type'], array('SuperAdmin', 'Admin'))){
|
||||
if($server=='radius'){
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
|
||||
}else{
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
|
||||
if (in_array($admin['user_type'], array('SuperAdmin', 'Admin'))) {
|
||||
switch ($server) {
|
||||
case 'radius':
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
case '':
|
||||
break;
|
||||
default:
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
if($server=='radius'){
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->where('enabled', '1')->find_many();
|
||||
}else{
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->where('enabled', '1')->find_many();
|
||||
} else {
|
||||
switch ($server) {
|
||||
case 'radius':
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
case '':
|
||||
break;
|
||||
default:
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
}
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
@ -56,15 +103,64 @@ switch ($action) {
|
||||
$ui->display('autoload.tpl');
|
||||
break;
|
||||
case 'customer_is_active':
|
||||
$d = ORM::for_table('tbl_user_recharges')->where('customer_id', $routes['2'])->findOne();
|
||||
if ($d) {
|
||||
if ($d['status'] == 'on') {
|
||||
die('<span class="label label-success" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">'.$d['namebp'].'</span>');
|
||||
} else {
|
||||
die('<span class="label label-danger" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">'.$d['namebp'].'</span>');
|
||||
if ($config['check_customer_online'] == 'yes') {
|
||||
$c = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->find_one($routes['3']);
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'Demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
try {
|
||||
//don't wait more than 5 seconds for response from device, otherwise we get timeout error.
|
||||
ini_set('default_socket_timeout', 5);
|
||||
if ((new $p['device'])->online_customer($c, $p['routers'])) {
|
||||
echo '<span style="color: green;" title="online">•</span>';
|
||||
}else{
|
||||
echo '<span style="color: yellow;" title="offline">•</span>';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo '<span style="color: red;" title="'.$e->getMessage().'">•</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'plan_is_active':
|
||||
$ds = ORM::for_table('tbl_user_recharges')->where('customer_id', $routes['2'])->find_array();
|
||||
if ($ds) {
|
||||
$ps = [];
|
||||
$c = ORM::for_table('tbl_customers')->find_one($routes['2']);
|
||||
foreach ($ds as $d) {
|
||||
if ($d['status'] == 'on') {
|
||||
if ($config['check_customer_online'] == 'yes') {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($d['plan_id']);
|
||||
$dvc = Package::getDevice($p);
|
||||
$status = "";
|
||||
if ($_app_stage != 'Demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
try {
|
||||
//don't wait more than 5 seconds for response from device, otherwise we get timeout error.
|
||||
ini_set('default_socket_timeout', 5);
|
||||
if ((new $p['device'])->online_customer($c, $p['routers'])) {
|
||||
$status = '<span style="color: green;" title="online">•</span>';
|
||||
}else{
|
||||
$status = '<span style="color: yellow;" title="offline">•</span>';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$status = '<span style="color: red;" title="'.$e->getMessage().'">•</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$ps[] = ('<span class="label label-primary m-1" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . ' ' . $status . '</span>');
|
||||
} else {
|
||||
$ps[] = ('<span class="label label-danger m-1" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . '</span>');
|
||||
}
|
||||
}
|
||||
echo implode("<br>", $ps);
|
||||
} else {
|
||||
die('<span class="label label-danger">•</span>');
|
||||
die('');
|
||||
}
|
||||
break;
|
||||
case 'customer_select2':
|
||||
|
@ -21,25 +21,63 @@ switch ($action) {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
|
||||
die('<a href="' . U . 'home&mikrotik=logout&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
|
||||
} else {
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
|
||||
die('<a href="' . U . 'home&mikrotik=login&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
|
||||
try {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
|
||||
die('<a href="' . getUrl('home&mikrotik=logout&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
|
||||
} else {
|
||||
die(Lang::T('-'));
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
|
||||
die('<a href="' . getUrl('home&mikrotik=login&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
|
||||
} else {
|
||||
die(Lang::T('-'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
die(Lang::T('-'));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
} catch (Exception $e) {
|
||||
die(Lang::T('Failed to connect to device'));
|
||||
}
|
||||
}
|
||||
die(Lang::T('-'));
|
||||
} else {
|
||||
die('--');
|
||||
}
|
||||
break;
|
||||
case 'bw_name':
|
||||
$bw = ORM::for_table('tbl_bandwidth')->select("name_bw")->find_one($routes['2']);
|
||||
echo $bw['name_bw'];
|
||||
die();
|
||||
case 'inbox_unread':
|
||||
$count = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->whereRaw('date_read is null')->count('id');
|
||||
if ($count > 0) {
|
||||
echo $count;
|
||||
}
|
||||
die();
|
||||
case 'inbox':
|
||||
$inboxs = ORM::for_table('tbl_customers_inbox')->selects(['id', 'subject', 'date_created'])->where('customer_id', $user['id'])->whereRaw('date_read is null')->order_by_desc('date_created')->limit(10)->find_many();
|
||||
foreach ($inboxs as $inbox) {
|
||||
echo '<li><a href="' . getUrl('mail/view/' . $inbox['id']) . '">' . $inbox['subject'] . '<br><sub class="text-muted">' . Lang::dateTimeFormat($inbox['date_created']) . '</sub></a></li>';
|
||||
}
|
||||
die();
|
||||
case 'language':
|
||||
$select = _get('select');
|
||||
$folders = [];
|
||||
$files = scandir('system/lan/');
|
||||
foreach ($files as $file) {
|
||||
if (is_file('system/lan/' . $file) && !in_array($file, ['index.html', 'country.json', '.DS_Store'])) {
|
||||
$file = str_replace(".json", "", $file);
|
||||
if(!empty($file)){
|
||||
echo '<li><a href="' . getUrl('accounts/language-update-post&lang=' . $file) . '">';
|
||||
if($select == $file){
|
||||
echo '<span class="glyphicon glyphicon-ok"></span> ';
|
||||
}
|
||||
echo ucwords($file) . '</a></li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
die();
|
||||
default:
|
||||
$ui->display('404.tpl');
|
||||
}
|
||||
|
@ -13,12 +13,12 @@ $action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
r2(U . "dashboard", 'e', Lang::T('You do not have permission to access this page'));
|
||||
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'list':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/bandwidth.js"></script>');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/bandwidth.js"></script>');
|
||||
run_hook('view_list_bandwidth'); #HOOK
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
@ -53,7 +53,7 @@ switch ($action) {
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('bandwidth-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'bandwidth/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('bandwidth/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -66,7 +66,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -123,9 +123,9 @@ switch ($action) {
|
||||
$d->burst = $burst;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'bandwidth/add', 'e', $msg);
|
||||
r2(getUrl('bandwidth/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -179,9 +179,9 @@ switch ($action) {
|
||||
$d->burst = $burst;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'bandwidth/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('bandwidth/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
315
system/controllers/coupons.php
Normal file
315
system/controllers/coupons.php
Normal file
@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
* Coupons Controller by https://t.me/focuslinkstech
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Coupons'));
|
||||
$ui->assign('_system_menu', 'crm');
|
||||
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
switch ($action) {
|
||||
|
||||
case 'add':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$ui->assign('_title', Lang::T('Add Coupon'));
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('coupons-add.tpl');
|
||||
break;
|
||||
|
||||
case 'add-post':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$code = Text::alphanumeric(_post('code', ''));
|
||||
$type = _post('type', '');
|
||||
$value = floatval(_post('value', ''));
|
||||
$description = _post('description', '');
|
||||
$max_usage = _post('max_usage', '0');
|
||||
$min_order_amount = _post('min_order_amount', '');
|
||||
$max_discount_amount = intval(_post('max_discount_amount', ''));
|
||||
$status = _post('status', 'active');
|
||||
$start_date = strtotime(_post('start_date', '0000-00-00'));
|
||||
$end_date = strtotime(_post('end_date', '0000-00-00'));
|
||||
|
||||
$error = [];
|
||||
if (empty($code)) {
|
||||
$error[] = Lang::T('Coupon Code is required');
|
||||
}
|
||||
if (empty($type)) {
|
||||
$error[] = Lang::T('Coupon Type is required');
|
||||
}
|
||||
if (empty($value)) {
|
||||
$error[] = Lang::T('Coupon Value is required');
|
||||
}
|
||||
if (empty($description)) {
|
||||
$error[] = Lang::T('Coupon Description is required');
|
||||
}
|
||||
if ($max_usage < 0) {
|
||||
$error[] = Lang::T('Coupon Maximum Usage must be greater than or equal to 0');
|
||||
}
|
||||
if (empty($min_order_amount)) {
|
||||
$error[] = Lang::T('Coupon Minimum Order Amount is required');
|
||||
}
|
||||
if (empty($max_discount_amount)) {
|
||||
$error[] = Lang::T('Coupon Maximum Discount Amount is required');
|
||||
}
|
||||
if (empty($status)) {
|
||||
$error[] = Lang::T('Coupon Status is required');
|
||||
}
|
||||
if (empty($start_date)) {
|
||||
$error[] = Lang::T('Coupon Start Date is required');
|
||||
}
|
||||
if (empty($end_date)) {
|
||||
$error[] = Lang::T('Coupon End Date is required');
|
||||
}
|
||||
|
||||
if (!empty($error)) {
|
||||
r2(getUrl('coupons/add'), 'e', implode('<br>', $error));
|
||||
exit;
|
||||
}
|
||||
|
||||
//check if coupon code already exists
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('code', $code)->find_one();
|
||||
if ($coupon) {
|
||||
r2(getUrl('coupons/add'), 'e', Lang::T('Coupon Code already exists'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$coupon = ORM::for_table('tbl_coupons')->create();
|
||||
$coupon->code = $code;
|
||||
$coupon->type = $type;
|
||||
$coupon->value = $value;
|
||||
$coupon->description = $description;
|
||||
$coupon->max_usage = $max_usage;
|
||||
$coupon->min_order_amount = $min_order_amount;
|
||||
$coupon->max_discount_amount = $max_discount_amount;
|
||||
$coupon->status = $status;
|
||||
$coupon->start_date = date('Y-m-d', $start_date);
|
||||
$coupon->end_date = date('Y-m-d', $end_date);
|
||||
$coupon->created_at = date('Y-m-d H:i:s');
|
||||
try {
|
||||
$coupon->save();
|
||||
r2(getUrl('coupons'), 's', Lang::T('Coupon has been added successfully'));
|
||||
} catch (Exception $e) {
|
||||
_log(Lang::T('Error adding coupon: ' . $e->getMessage()));
|
||||
r2(getUrl('coupons/add'), 'e', Lang::T('Error adding coupon: ' . $e->getMessage()));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$coupon_id = intval($routes['2']);
|
||||
if (empty($coupon_id)) {
|
||||
r2(getUrl('coupons'), 'e', Lang::T('Invalid Coupon ID'));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
|
||||
if (!$coupon) {
|
||||
r2(getUrl('coupons'), 'e', Lang::T('Coupon Not Found'));
|
||||
exit;
|
||||
}
|
||||
$ui->assign('coupon', $coupon);
|
||||
$ui->assign('_title', Lang::T('Edit Coupon: ' . $coupon['code']));
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('coupons-edit.tpl');
|
||||
break;
|
||||
|
||||
case 'edit-post':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
$code = Text::alphanumeric(_post('code', ''));
|
||||
$type = _post('type', '');
|
||||
$value = floatval(_post('value', ''));
|
||||
$description = _post('description', '');
|
||||
$max_usage = _post('max_usage', '');
|
||||
$min_order_amount = _post('min_order_amount', '');
|
||||
$max_discount_amount = intval(_post('max_discount_amount', ''));
|
||||
$status = _post('status', 'active');
|
||||
$start_date = strtotime(_post('start_date', '0000-00-00'));
|
||||
$end_date = strtotime(_post('end_date', '0000-00-00'));
|
||||
|
||||
$error = [];
|
||||
if (empty($code)) {
|
||||
$error[] = Lang::T('Coupon code is required');
|
||||
}
|
||||
if (empty($type)) {
|
||||
$error[] = Lang::T('Coupon type is required');
|
||||
}
|
||||
if (empty($value)) {
|
||||
$error[] = Lang::T('Coupon value is required');
|
||||
}
|
||||
if (empty($description)) {
|
||||
$error[] = Lang::T('Coupon description is required');
|
||||
}
|
||||
if ($max_usage < 0) {
|
||||
$error[] = Lang::T('Coupon Maximum Usage must be greater than or equal to 0');
|
||||
}
|
||||
if (empty($min_order_amount)) {
|
||||
$error[] = Lang::T('Coupon minimum order amount is required');
|
||||
}
|
||||
if (empty($max_discount_amount)) {
|
||||
$error[] = Lang::T('Coupon maximum discount amount is required');
|
||||
}
|
||||
if (empty($status)) {
|
||||
$error[] = Lang::T('Coupon status is required');
|
||||
}
|
||||
if (empty($start_date)) {
|
||||
$error[] = Lang::T('Coupon start date is required');
|
||||
}
|
||||
if (empty($end_date)) {
|
||||
$error[] = Lang::T('Coupon end date is required');
|
||||
}
|
||||
if (!empty($error)) {
|
||||
r2(getUrl('coupons/edit/') . $coupon_id, 'e', implode('<br>', $error));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
|
||||
$coupon->code = $code;
|
||||
$coupon->type = $type;
|
||||
$coupon->value = $value;
|
||||
$coupon->description = $description;
|
||||
$coupon->max_usage = $max_usage;
|
||||
$coupon->min_order_amount = $min_order_amount;
|
||||
$coupon->max_discount_amount = $max_discount_amount;
|
||||
$coupon->status = $status;
|
||||
$coupon->start_date = date('Y-m-d', $start_date);
|
||||
$coupon->end_date = date('Y-m-d', $end_date);
|
||||
$coupon->updated_at = date('Y-m-d H:i:s');
|
||||
try {
|
||||
$coupon->save();
|
||||
r2(getUrl('coupons'), 's', Lang::T('Coupon has been updated successfully'));
|
||||
} catch (Exception $e) {
|
||||
_log(Lang::T('Error updating coupon: ') . $e->getMessage());
|
||||
r2(getUrl('coupons/edit/') . $coupon_id, 'e', Lang::T('Error updating coupon: ') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$couponIds = json_decode($_POST['couponIds'], true);
|
||||
|
||||
if (is_array($couponIds) && !empty($couponIds)) {
|
||||
// Delete coupons from the database
|
||||
ORM::for_table('tbl_coupons')
|
||||
->where_in('id', $couponIds)
|
||||
->delete_many();
|
||||
|
||||
// Return success response
|
||||
echo json_encode(['status' => 'success', 'message' => Lang::T("Coupons Deleted Successfully.")]);
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid or missing coupon IDs.")]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid request method.")]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$couponId = $_GET['coupon_id'] ?? '';
|
||||
$csrf_token = $_GET['csrf_token'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
if (empty($couponId) || empty($csrf_token) || !Csrf::check($csrf_token) || empty($status)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Invalid request"));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('id', $couponId)->find_one();
|
||||
if (!$coupon) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not found."));
|
||||
exit;
|
||||
}
|
||||
$coupon->status = $status;
|
||||
$coupon->save();
|
||||
r2($_SERVER['HTTP_REFERER'], 's', Lang::T("Coupon status updated successfully."));
|
||||
} else {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Invalid request method"));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$ui->assign('_title', Lang::T('Coupons'));
|
||||
$ui->assign('_system_menu', 'crm');
|
||||
|
||||
$search = _post('search');
|
||||
$filter = _post('filter', 'none');
|
||||
|
||||
$couponsData = ORM::for_table('tbl_coupons')
|
||||
->table_alias('c')
|
||||
->select_many(
|
||||
'c.id',
|
||||
'c.code',
|
||||
'c.type',
|
||||
'c.value',
|
||||
'c.description',
|
||||
'c.max_usage',
|
||||
'c.usage_count',
|
||||
'c.status',
|
||||
'c.min_order_amount',
|
||||
'c.max_discount_amount',
|
||||
'c.start_date',
|
||||
'c.end_date',
|
||||
'c.created_at',
|
||||
'c.updated_at'
|
||||
);
|
||||
|
||||
// Apply filters
|
||||
if ($search != '') {
|
||||
$searchLike = "%$search%";
|
||||
$couponsData->whereRaw(
|
||||
"code LIKE ? OR type LIKE ? OR value LIKE ? OR max_usage LIKE ? OR usage_count LIKE ? OR status LIKE ? OR min_order_amount LIKE ? OR max_discount_amount LIKE ?",
|
||||
[$searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike]
|
||||
);
|
||||
}
|
||||
$couponsData->order_by_asc('c.id');
|
||||
$coupons = Paginator::findMany($couponsData, ['search' => $search], 5, '');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->assign('coupons', $coupons);
|
||||
$ui->display('coupons.tpl');
|
||||
break;
|
||||
}
|
@ -25,6 +25,10 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
$cs = ORM::for_table('tbl_customers')
|
||||
->select('tbl_customers.id', 'id')
|
||||
@ -153,6 +157,7 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
run_hook('view_add_customer'); #HOOK
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('customers-add.tpl');
|
||||
break;
|
||||
case 'recharge':
|
||||
@ -161,22 +166,39 @@ switch ($action) {
|
||||
}
|
||||
$id_customer = $routes['2'];
|
||||
$plan_id = $routes['3'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
|
||||
if ($b) {
|
||||
$gateway = 'Recharge';
|
||||
$channel = $admin['fullname'];
|
||||
$cust = User::_info($id_customer);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($b['plan_id']);
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
|
||||
if (!$cust) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost + $tax)) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -189,7 +211,12 @@ switch ($action) {
|
||||
if (count($usings) == 0) {
|
||||
$usings[] = Lang::T('Cash');
|
||||
}
|
||||
$abills = User::getAttributes("Bill");
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
$ui->assign('usings', $usings);
|
||||
$ui->assign('abills', $abills);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
$ui->assign('cust', $cust);
|
||||
@ -197,9 +224,10 @@ switch ($action) {
|
||||
$ui->assign('channel', $channel);
|
||||
$ui->assign('server', $b['routers']);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('recharge-confirm.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
}
|
||||
break;
|
||||
case 'deactivate':
|
||||
@ -208,6 +236,10 @@ switch ($action) {
|
||||
}
|
||||
$id_customer = $routes['2'];
|
||||
$plan_id = $routes['3'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
|
||||
if ($b) {
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->find_one();
|
||||
@ -229,13 +261,17 @@ switch ($action) {
|
||||
$b->save();
|
||||
_log('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for ' . $b['username'], 'User', $b['customer_id']);
|
||||
Message::sendTelegram('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for u' . $b['username']);
|
||||
r2(U . 'customers/view/' . $id_customer, 's', 'Success deactivate customer to Mikrotik');
|
||||
r2(getUrl('customers/view/') . $id_customer, 's', 'Success deactivate customer to Mikrotik');
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
break;
|
||||
case 'sync':
|
||||
$id_customer = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$bs = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->findMany();
|
||||
if ($bs) {
|
||||
$routers = [];
|
||||
@ -248,16 +284,37 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
}else{
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
|
||||
r2(getUrl('customers/view/') . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
break;
|
||||
case 'login':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$customer = ORM::for_table('tbl_customers')->find_one($id);
|
||||
if ($customer) {
|
||||
$_SESSION['uid'] = $id;
|
||||
User::setCookie($id);
|
||||
_alert("You are logging in as $customer[fullname],<br>don't logout just close tab.", 'info', "home", 10);
|
||||
}
|
||||
_alert(Lang::T('Customer not found'), 'danger', "customers");
|
||||
break;
|
||||
case 'viewu':
|
||||
$customer = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
|
||||
@ -268,8 +325,6 @@ switch ($action) {
|
||||
$customer = ORM::for_table('tbl_customers')->find_one($id);
|
||||
}
|
||||
if ($customer) {
|
||||
|
||||
|
||||
// Fetch the Customers Attributes values from the tbl_customer_custom_fields table
|
||||
$customFields = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $customer['id'])
|
||||
@ -278,28 +333,44 @@ switch ($action) {
|
||||
if (empty($v)) {
|
||||
$v = 'activation';
|
||||
}
|
||||
if ($v == 'order') {
|
||||
$v = 'order';
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$order = Paginator::findMany($query);
|
||||
$ui->assign('order', $order);
|
||||
} else if ($v == 'activation') {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
$ui->assign('activation', $activation);
|
||||
switch ($v) {
|
||||
case 'order':
|
||||
$v = 'order';
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('user_id', $customer['id'])->order_by_desc('id');
|
||||
$order = Paginator::findMany($query);
|
||||
|
||||
if (empty($order) || $order < 5) {
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$order = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('order', $order);
|
||||
break;
|
||||
case 'activation':
|
||||
$query = ORM::for_table('tbl_transactions')->where('user_id', $customer['id'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
|
||||
if (empty($activation) || $activation < 5) {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('activation', $activation);
|
||||
break;
|
||||
}
|
||||
$ui->assign('packages', User::_billing($customer['id']));
|
||||
$ui->assign('v', $v);
|
||||
$ui->assign('d', $customer);
|
||||
$ui->assign('customFields', $customFields);
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('customers-view.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'edit':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
@ -310,13 +381,31 @@ switch ($action) {
|
||||
->where('customer_id', $id)
|
||||
->find_many();
|
||||
if ($d) {
|
||||
if (isset($routes['3']) && $routes['3'] == 'deletePhoto') {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo']) && strpos($d['photo'], 'default') === false) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
$d->photo = '/user.default.jpg';
|
||||
$d->save();
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', 'You have successfully deleted the photo');
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', 'No photo found to delete');
|
||||
}
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('statuses', ORM::for_table('tbl_customers')->getEnum("status"));
|
||||
$ui->assign('customFields', $customFields);
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('customers-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -325,6 +414,10 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
run_hook('delete_customer'); #HOOK
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
if ($c) {
|
||||
@ -355,15 +448,22 @@ switch ($action) {
|
||||
$c->delete();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
r2(U . 'customers/list', 's', Lang::T('User deleted Successfully'));
|
||||
r2(getUrl('customers/list'), 's', Lang::T('User deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'add-post':
|
||||
$username = alphanumeric(_post('username'), "+_.@-");
|
||||
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = alphanumeric(_post('username'), ":+_.@-");
|
||||
$fullname = _post('fullname');
|
||||
$password = trim(_post('password'));
|
||||
$pppoe_username = trim(_post('pppoe_username'));
|
||||
$pppoe_password = trim(_post('pppoe_password'));
|
||||
$pppoe_ip = trim(_post('pppoe_ip'));
|
||||
$email = _post('email');
|
||||
$address = _post('address');
|
||||
$phonenumber = _post('phonenumber');
|
||||
@ -399,7 +499,9 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_customers')->create();
|
||||
$d->username = $username;
|
||||
$d->password = $password;
|
||||
$d->pppoe_username = $pppoe_username;
|
||||
$d->pppoe_password = $pppoe_password;
|
||||
$d->pppoe_ip = $pppoe_ip;
|
||||
$d->email = $email;
|
||||
$d->account_type = $account_type;
|
||||
$d->fullname = $fullname;
|
||||
@ -432,18 +534,66 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/list', 's', Lang::T('Account Created Successfully'));
|
||||
|
||||
// Send welcome message
|
||||
if (isset($_POST['send_welcome_message']) && $_POST['send_welcome_message'] == true) {
|
||||
$welcomeMessage = Lang::getNotifText('welcome_message');
|
||||
$welcomeMessage = str_replace('[[company]]', $config['CompanyName'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[name]]', $d['fullname'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[username]]', $d['username'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[password]]', $d['password'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[url]]', APP_URL . '/?_route=login', $welcomeMessage);
|
||||
|
||||
$emailSubject = "Welcome to " . $config['CompanyName'];
|
||||
|
||||
$channels = [
|
||||
'sms' => [
|
||||
'enabled' => isset($_POST['sms']),
|
||||
'method' => 'sendSMS',
|
||||
'args' => [$d['phonenumber'], $welcomeMessage]
|
||||
],
|
||||
'whatsapp' => [
|
||||
'enabled' => isset($_POST['wa']),
|
||||
'method' => 'sendWhatsapp',
|
||||
'args' => [$d['phonenumber'], $welcomeMessage]
|
||||
],
|
||||
'email' => [
|
||||
'enabled' => isset($_POST['mail']),
|
||||
'method' => 'Message::sendEmail',
|
||||
'args' => [$d['email'], $emailSubject, $welcomeMessage, $d['email']]
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($channels as $channel => $message) {
|
||||
if ($message['enabled']) {
|
||||
try {
|
||||
call_user_func_array($message['method'], $message['args']);
|
||||
} catch (Exception $e) {
|
||||
// Log the error and handle the failure
|
||||
_log("Failed to send welcome message via $channel: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(getUrl('customers/list'), 's', Lang::T('Account Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'customers/add', 'e', $msg);
|
||||
r2(getUrl('customers/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit-post':
|
||||
$username = alphanumeric(_post('username'), "+_.@-");
|
||||
$id = _post('id');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/edit/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = alphanumeric(_post('username'), ":+_.@-");
|
||||
$fullname = _post('fullname');
|
||||
$account_type = _post('account_type');
|
||||
$password = trim(_post('password'));
|
||||
$pppoe_username = trim(_post('pppoe_username'));
|
||||
$pppoe_password = trim(_post('pppoe_password'));
|
||||
$pppoe_ip = trim(_post('pppoe_ip'));
|
||||
$email = _post('email');
|
||||
$address = _post('address');
|
||||
$phonenumber = Lang::phoneFormat(_post('phonenumber'));
|
||||
@ -464,7 +614,6 @@ switch ($action) {
|
||||
$msg .= 'Full Name should be between 2 to 25 characters' . '<br>';
|
||||
}
|
||||
|
||||
$id = _post('id');
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
|
||||
if (!$c) {
|
||||
@ -477,33 +626,100 @@ switch ($action) {
|
||||
->find_many();
|
||||
|
||||
$oldusername = $c['username'];
|
||||
$oldPppoePassword = $c['password'];
|
||||
$oldPassPassword = $c['pppoe_password'];
|
||||
$oldPppoeUsername = $c['pppoe_username'];
|
||||
$oldPppoePassword = $c['pppoe_password'];
|
||||
$oldPppoeIp = $c['pppoe_ip'];
|
||||
$oldPassPassword = $c['password'];
|
||||
$userDiff = false;
|
||||
$pppoeDiff = false;
|
||||
$passDiff = false;
|
||||
$pppoeIpDiff = false;
|
||||
if ($oldusername != $username) {
|
||||
$cx = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($cx) {
|
||||
$msg .= Lang::T('Account already exist') . '<br>';
|
||||
if (ORM::for_table('tbl_customers')->where('username', $username)->find_one()) {
|
||||
$msg .= Lang::T('Username already used by another customer') . '<br>';
|
||||
}
|
||||
if (ORM::for_table('tbl_customers')->where('pppoe_username', $username)->find_one()) {
|
||||
$msg .= Lang::T('Username already used by another pppoe username customer') . '<br>';
|
||||
}
|
||||
$userDiff = true;
|
||||
}
|
||||
if ($oldPppoePassword != $pppoe_password) {
|
||||
if ($oldPppoeUsername != $pppoe_username) {
|
||||
// if(!empty($pppoe_username)){
|
||||
// if(ORM::for_table('tbl_customers')->where('pppoe_username', $pppoe_username)->find_one()){
|
||||
// $msg.= Lang::T('PPPoE Username already used by another customer') . '<br>';
|
||||
// }
|
||||
// if(ORM::for_table('tbl_customers')->where('username', $pppoe_username)->find_one()){
|
||||
// $msg.= Lang::T('PPPoE Username already used by another customer') . '<br>';
|
||||
// }
|
||||
// }
|
||||
$pppoeDiff = true;
|
||||
}
|
||||
|
||||
if ($oldPppoeIp != $pppoe_ip) {
|
||||
$pppoeIpDiff = true;
|
||||
}
|
||||
if ($password != '' && $oldPassPassword != $password) {
|
||||
$passDiff = true;
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($c['photo'] != '' && strpos($c['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $c['photo'])) {
|
||||
unlink($UPLOAD_PATH . $c['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $c['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $c['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$c->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
if ($userDiff) {
|
||||
$c->username = $username;
|
||||
}
|
||||
if ($password != '') {
|
||||
$c->password = $password;
|
||||
}
|
||||
$c->pppoe_username = $pppoe_username;
|
||||
$c->pppoe_password = $pppoe_password;
|
||||
$c->pppoe_ip = $pppoe_ip;
|
||||
$c->fullname = $fullname;
|
||||
$c->email = $email;
|
||||
$c->account_type = $account_type;
|
||||
@ -564,11 +780,9 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($userDiff || $pppoeDiff || $passDiff) {
|
||||
if ($userDiff || $pppoeDiff || $pppoeIpDiff || $passDiff) {
|
||||
$turs = ORM::for_table('tbl_user_recharges')->where('customer_id', $c['id'])->findMany();
|
||||
foreach ($turs as $tur) {
|
||||
$tur->username = $username;
|
||||
$tur->save();
|
||||
$p = ORM::for_table('tbl_plans')->find_one($tur['plan_id']);
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
@ -579,26 +793,40 @@ switch ($action) {
|
||||
if ($userDiff) {
|
||||
(new $p['device'])->change_username($p, $oldusername, $username);
|
||||
}
|
||||
if ($pppoeDiff && $tur['type'] == 'PPPOE') {
|
||||
if (empty($oldPppoeUsername) && !empty($pppoe_username)) {
|
||||
// admin just add pppoe username
|
||||
(new $p['device'])->change_username($p, $username, $pppoe_username);
|
||||
} else if (empty($pppoe_username) && !empty($oldPppoeUsername)) {
|
||||
// admin want to use customer username
|
||||
(new $p['device'])->change_username($p, $oldPppoeUsername, $username);
|
||||
} else {
|
||||
// regular change pppoe username
|
||||
(new $p['device'])->change_username($p, $oldPppoeUsername, $pppoe_username);
|
||||
}
|
||||
}
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
$tur->username = $username;
|
||||
$tur->save();
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id, 's', 'User Updated Successfully');
|
||||
r2(getUrl('customers/view/') . $id, 's', 'User Updated Successfully');
|
||||
} else {
|
||||
r2(U . 'customers/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('customers/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
run_hook('list_customers'); #HOOK
|
||||
$search = _post('search');
|
||||
$order = _post('order', 'username');
|
||||
$filter = _post('filter', 'Active');
|
||||
$orderby = _post('orderby', 'asc');
|
||||
$search = _req('search');
|
||||
$order = _req('order', 'username');
|
||||
$filter = _req('filter', 'Active');
|
||||
$orderby = _req('orderby', 'asc');
|
||||
$order_pos = [
|
||||
'username' => 0,
|
||||
'created_at' => 8,
|
||||
@ -606,6 +834,8 @@ switch ($action) {
|
||||
'status' => 7
|
||||
];
|
||||
|
||||
$append_url = "&order=" . urlencode($order) . "&filter=" . urlencode($filter) . "&orderby=" . urlencode($orderby);
|
||||
|
||||
if ($search != '') {
|
||||
$query = ORM::for_table('tbl_customers')
|
||||
->whereRaw("username LIKE '%$search%' OR fullname LIKE '%$search%' OR address LIKE '%$search%' " .
|
||||
@ -614,13 +844,21 @@ switch ($action) {
|
||||
$query = ORM::for_table('tbl_customers');
|
||||
$query->where("status", $filter);
|
||||
}
|
||||
if ($orderby == 'asc') {
|
||||
$query->order_by_asc($order);
|
||||
if ($order == 'lastname') {
|
||||
$query->order_by_expr("SUBSTR(fullname, INSTR(fullname, ' ')) $orderby");
|
||||
} else {
|
||||
$query->order_by_desc($order);
|
||||
if ($orderby == 'asc') {
|
||||
$query->order_by_asc($order);
|
||||
} else {
|
||||
$query->order_by_desc($order);
|
||||
}
|
||||
}
|
||||
$d = $query->findMany();
|
||||
if (_post('export', '') == 'csv') {
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$d = $query->findMany();
|
||||
$h = false;
|
||||
set_time_limit(-1);
|
||||
header('Pragma: public');
|
||||
@ -661,7 +899,7 @@ switch ($action) {
|
||||
fclose($fp);
|
||||
die();
|
||||
}
|
||||
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
|
||||
$d = Paginator::findMany($query, ['search' => $search], 30, $append_url);
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('statuses', ORM::for_table('tbl_customers')->getEnum("status"));
|
||||
$ui->assign('filter', $filter);
|
||||
@ -669,6 +907,7 @@ switch ($action) {
|
||||
$ui->assign('order', $order);
|
||||
$ui->assign('order_pos', $order_pos[$order]);
|
||||
$ui->assign('orderby', $orderby);
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('customers.tpl');
|
||||
break;
|
||||
}
|
||||
|
53
system/controllers/customfield.php
Normal file
53
system/controllers/customfield.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Custom Fields'));
|
||||
$ui->assign('_system_menu', 'settings');
|
||||
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
|
||||
switch ($action) {
|
||||
case 'save':
|
||||
print_r($_POST);
|
||||
$datas = [];
|
||||
$count = count($_POST['name']);
|
||||
for($n=0;$n<$count;$n++){
|
||||
if(!empty($_POST['name'][$n])){
|
||||
$datas[] = [
|
||||
'order' => $_POST['order'][$n],
|
||||
'name' => Text::alphanumeric(strtolower(str_replace(" ", "_", $_POST['name'][$n])), "_"),
|
||||
'type' => $_POST['type'][$n],
|
||||
'placeholder' => $_POST['placeholder'][$n],
|
||||
'value' => $_POST['value'][$n],
|
||||
'register' => $_POST['register'][$n],
|
||||
'required' => $_POST['required'][$n]
|
||||
];
|
||||
}
|
||||
}
|
||||
if(count($datas)>1){
|
||||
usort($datas, function ($item1, $item2) {
|
||||
return $item1['order'] <=> $item2['order'];
|
||||
});
|
||||
}
|
||||
if(file_put_contents($fieldPath, json_encode($datas))){
|
||||
r2(getUrl('customfield'), 's', 'Successfully saved custom fields!');
|
||||
}else{
|
||||
r2(getUrl('customfield'), 'e', 'Failed to save custom fields!');
|
||||
}
|
||||
default:
|
||||
$fields = [];
|
||||
if(file_exists($fieldPath)){
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
}
|
||||
$ui->assign('fields', $fields);
|
||||
$ui->display('customfield.tpl');
|
||||
break;
|
||||
}
|
@ -17,7 +17,7 @@ if (isset($_GET['refresh'])) {
|
||||
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
}
|
||||
r2(U . 'dashboard', 's', 'Data Refreshed');
|
||||
r2(getUrl('dashboard'), 's', 'Data Refreshed');
|
||||
}
|
||||
|
||||
$reset_day = $config['reset_day'];
|
||||
@ -55,6 +55,11 @@ if ($imonth == '') {
|
||||
}
|
||||
$ui->assign('imonth', $imonth);
|
||||
|
||||
if ($config['enable_balance'] == 'yes'){
|
||||
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
|
||||
$ui->assign('cb', $cb);
|
||||
}
|
||||
|
||||
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
|
||||
if (empty($u_act)) {
|
||||
$u_act = '0';
|
||||
@ -204,6 +209,17 @@ if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
|
||||
file_put_contents($cacheMSfile, json_encode($monthlySales));
|
||||
}
|
||||
|
||||
if ($config['router_check']) {
|
||||
$routeroffs = ORM::for_table('tbl_routers')->selects(['id', 'name', 'last_seen'])->where('status', 'Offline')->where('enabled', '1')->order_by_desc('name')->find_array();
|
||||
$ui->assign('routeroffs', $routeroffs);
|
||||
}
|
||||
|
||||
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
|
||||
if (file_exists($timestampFile)) {
|
||||
$lastRunTime = file_get_contents($timestampFile);
|
||||
$ui->assign('run_date', date('Y-m-d h:i:s A', $lastRunTime));
|
||||
}
|
||||
|
||||
// Assign the monthly sales data to Smarty
|
||||
$ui->assign('start_date', $start_date);
|
||||
$ui->assign('current_date', $current_date);
|
||||
|
@ -5,9 +5,9 @@
|
||||
**/
|
||||
|
||||
if(Admin::getID()){
|
||||
r2(U.'dashboard');
|
||||
r2(getUrl('dashboard'));
|
||||
}if(User::getID()){
|
||||
r2(U.'home');
|
||||
r2(getUrl('home'));
|
||||
}else{
|
||||
r2(U.'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
|
169
system/controllers/forgot.php
Normal file
169
system/controllers/forgot.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
$step = _req('step', 0);
|
||||
$otpPath = $CACHE_PATH . File::pathFixer('/forgot/');
|
||||
|
||||
if ($step == '-1') {
|
||||
$_COOKIE['forgot_username'] = '';
|
||||
setcookie('forgot_username', '', time() - 3600, '/');
|
||||
$step = 0;
|
||||
}
|
||||
|
||||
if (!empty($_COOKIE['forgot_username']) && in_array($step, [0, 1])) {
|
||||
$step = 1;
|
||||
$_POST['username'] = $_COOKIE['forgot_username'];
|
||||
}
|
||||
|
||||
if ($step == 1) {
|
||||
$username = _post('username');
|
||||
if (!empty($username)) {
|
||||
$ui->assign('username', $username);
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
}
|
||||
setcookie('forgot_username', $username, time() + 3600, '/');
|
||||
$user = ORM::for_table('tbl_customers')->selects(['phonenumber', 'email'])->where('username', $username)->find_one();
|
||||
if ($user) {
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) < 600) {
|
||||
$sec = time() - filemtime($otpPath);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Verification Code already Sent to Your Phone/Email/Whatsapp, please wait")." $sec seconds.");
|
||||
} else {
|
||||
$via = $config['user_notification_reminder'];
|
||||
if ($via == 'email') {
|
||||
$via = 'sms';
|
||||
}
|
||||
$otp = mt_rand(100000, 999999);
|
||||
file_put_contents($otpPath, $otp);
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($user['phonenumber'], $config['CompanyName'] . " C0de: $otp");
|
||||
} else {
|
||||
Message::sendWhatsapp($user['phonenumber'], $config['CompanyName'] . " C0de: $otp");
|
||||
}
|
||||
Message::sendEmail(
|
||||
$user['email'],
|
||||
$config['CompanyName'] . Lang::T("Your Verification Code") . ' : ' . $otp,
|
||||
Lang::T("Your Verification Code") . ' : <b>' . $otp . '</b>'
|
||||
);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("If your Username is found, Verification Code has been Sent to Your Phone/Email/Whatsapp"));
|
||||
}
|
||||
} else {
|
||||
// Username not found
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("If your Username is found, Verification Code has been Sent to Your Phone/Email/Whatsapp") . ".");
|
||||
}
|
||||
} else {
|
||||
$step = 0;
|
||||
}
|
||||
} else if ($step == 2) {
|
||||
$username = _post('username');
|
||||
$otp_code = _post('otp_code');
|
||||
if (!empty($username) && !empty($otp_code)) {
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) <= 600) {
|
||||
$otp = file_get_contents($otpPath);
|
||||
if ($otp == $otp_code) {
|
||||
$pass = mt_rand(10000, 99999);
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
$user->password = $pass;
|
||||
$user->save();
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('passsword', $pass);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Verification Code Valid"));
|
||||
if (file_exists($otpPath)) {
|
||||
unlink($otpPath);
|
||||
}
|
||||
setcookie('forgot_username', '', time() - 3600, '/');
|
||||
} else {
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else {
|
||||
if (file_exists($otpPath)) {
|
||||
unlink($otpPath);
|
||||
}
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else {
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else if ($step == 7) {
|
||||
$find = _post('find');
|
||||
$step = 6;
|
||||
if (!empty($find)) {
|
||||
$via = $config['user_notification_reminder'];
|
||||
if ($via == 'email') {
|
||||
$via = 'sms';
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
}
|
||||
$otpPath .= sha1($find . $db_pass) . ".txt";
|
||||
$users = ORM::for_table('tbl_customers')->selects(['username', 'phonenumber', 'email'])->where('phonenumber', $find)->find_array();
|
||||
if ($users) {
|
||||
// prevent flooding only can request every 10 minutes
|
||||
if (!file_exists($otpPath) || (file_exists($otpPath) && time() - filemtime($otpPath) >= 600)) {
|
||||
$usernames = implode(", ", array_column($users, 'username'));
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($find, Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
} else {
|
||||
Message::sendWhatsapp($find, Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
}
|
||||
file_put_contents($otpPath, time());
|
||||
}
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Usernames have been sent to your phone/Whatsapp") . " $find");
|
||||
$step = 0;
|
||||
} else {
|
||||
$users = ORM::for_table('tbl_customers')->selects(['username', 'phonenumber', 'email'])->where('email', $find)->find_array();
|
||||
if ($users) {
|
||||
// prevent flooding only can request every 10 minutes
|
||||
if (!file_exists($otpPath) || (file_exists($otpPath) && time() - filemtime($otpPath) >= 600)) {
|
||||
$usernames = implode(", ", array_column($users, 'username'));
|
||||
$phones = [];
|
||||
foreach ($users as $user) {
|
||||
if (!in_array($user['phonenumber'], $phones)) {
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($user['phonenumber'], Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
} else {
|
||||
Message::sendWhatsapp($user['phonenumber'], Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
}
|
||||
$phones[] = $user['phonenumber'];
|
||||
}
|
||||
}
|
||||
Message::sendEmail(
|
||||
$user['email'],
|
||||
Lang::T("Your username for") . ' ' . $config['CompanyName'],
|
||||
Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames
|
||||
);
|
||||
file_put_contents($otpPath, time());
|
||||
}
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Usernames have been sent to your phone/Whatsapp/Email"));
|
||||
$step = 0;
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', Lang::T("No data found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete old files
|
||||
$pth = $CACHE_PATH . File::pathFixer('/forgot/');
|
||||
$fs = scandir($pth);
|
||||
foreach ($fs as $file) {
|
||||
if(is_file($pth.$file) && time() - filemtime($pth.$file) > 3600) {
|
||||
unlink($pth.$file);
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('step', $step);
|
||||
$ui->assign('_title', Lang::T('Forgot Password'));
|
||||
$ui->display('customer/forgot.tpl');
|
@ -23,18 +23,18 @@ if (_post('send') == 'balance') {
|
||||
}
|
||||
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
|
||||
if (!$target) {
|
||||
r2(U . 'home', 'd', Lang::T('Username not found'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Username not found'));
|
||||
}
|
||||
$username = _post('username');
|
||||
$balance = _post('balance');
|
||||
if ($user['balance'] < $balance) {
|
||||
r2(U . 'home', 'd', Lang::T('insufficient balance'));
|
||||
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
|
||||
}
|
||||
if (!empty($config['minimum_transfer']) && intval($balance) < intval($config['minimum_transfer'])) {
|
||||
r2(U . 'home', 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
|
||||
r2(getUrl('home'), 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
|
||||
}
|
||||
if ($user['username'] == $target['username']) {
|
||||
r2(U . 'home', 'd', Lang::T('Cannot send to yourself'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Cannot send to yourself'));
|
||||
}
|
||||
if (Balance::transfer($user['id'], $username, $balance)) {
|
||||
//sender
|
||||
@ -71,13 +71,14 @@ if (_post('send') == 'balance') {
|
||||
$d->pg_url_payment = 'balance';
|
||||
$d->status = 2;
|
||||
$d->save();
|
||||
Message::sendBalanceNotification($user, $balance, ($user['balance'] - $balance), Lang::getNotifText('balance_send'), $config['user_notification_payment']);
|
||||
Message::sendBalanceNotification($target, $balance, ($target['balance'] + $balance), Lang::getNotifText('balance_received'), $config['user_notification_payment']);
|
||||
//
|
||||
Message::sendBalanceNotification($user, $target, $balance, ($user['balance'] - $balance), Lang::getNotifText('balance_send'), $config['user_notification_payment']);
|
||||
Message::sendBalanceNotification($target, $user, $balance, ($target['balance'] + $balance), Lang::getNotifText('balance_received'), $config['user_notification_payment']);
|
||||
Message::sendTelegram("#u$user[username] send balance to #u$target[username] \n" . Lang::moneyFormat($balance));
|
||||
r2(U . 'home', 's', Lang::T('Sending balance success'));
|
||||
r2(getUrl('home'), 's', Lang::T('Sending balance success'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'home', 'd', Lang::T('Failed, balance is not available'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Failed, balance is not available'));
|
||||
}
|
||||
} else if (_post('send') == 'plan') {
|
||||
if ($user['status'] != 'Active') {
|
||||
@ -89,20 +90,53 @@ if (_post('send') == 'balance') {
|
||||
foreach ($actives as $active) {
|
||||
$router = ORM::for_table('tbl_routers')->where('name', $active['routers'])->find_one();
|
||||
if ($router) {
|
||||
r2(U . "order/send/$router[id]/$active[plan_id]&u=" . trim(_post('username')), 's', Lang::T('Review package before recharge'));
|
||||
r2(getUrl('order/send/$router[id]/$active[plan_id]&u=') . trim(_post('username')), 's', Lang::T('Review package before recharge'));
|
||||
}
|
||||
}
|
||||
r2(U . 'home', 'w', Lang::T('Your friend do not have active package'));
|
||||
r2(getUrl('home'), 'w', Lang::T('Your friend do not have active package'));
|
||||
}
|
||||
$_bill = User::_billing();
|
||||
$ui->assign('_bills', $_bill);
|
||||
|
||||
$ui->assign('_bills', User::_billing());
|
||||
// Sync plan to router
|
||||
if (isset($_GET['sync']) && !empty($_GET['sync'])) {
|
||||
foreach ($_bill as $tur) {
|
||||
if ($tur['status'] == 'on') {
|
||||
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
|
||||
if ($p) {
|
||||
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
|
||||
if ($c) {
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
}else{
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
$log .= "DONE : $ptur[namebp], $tur[type], $tur[routers]<br>";
|
||||
} else {
|
||||
$log .= "Customer NOT FOUND : $tur[namebp], $tur[type], $tur[routers]<br>";
|
||||
}
|
||||
} else {
|
||||
$log .= "PLAN NOT FOUND : $tur[namebp], $tur[type], $tur[routers]<br>";
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(getUrl('home'), 's', $log);
|
||||
}
|
||||
|
||||
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (!empty(App::getTokenValue(_get('stoken')))) {
|
||||
r2(U . "voucher/invoice/");
|
||||
r2(getUrl('voucher/invoice/'));
|
||||
die();
|
||||
}
|
||||
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['recharge'])->where('username', $user['username'])->findOne();
|
||||
@ -113,29 +147,17 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
$routers = ORM::for_table('tbl_routers')->where('name', $bill['routers'])->find_one();
|
||||
$router = $routers['id'];
|
||||
}
|
||||
if ($config['enable_balance'] == 'yes') {
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
}
|
||||
if ($user['balance'] > $plan['price']) {
|
||||
r2(U . "order/pay/$router/$bill[plan_id]&stoken=" . _get('stoken'), 'e', 'Order Plan');
|
||||
} else {
|
||||
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
|
||||
}
|
||||
} else {
|
||||
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
|
||||
}
|
||||
r2(getUrl('order/gateway/$router/$bill[plan_id]'));
|
||||
}
|
||||
} else if (!empty(_get('extend'))) {
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (!$config['extend_expired']) {
|
||||
r2(U . 'home', 'e', "cannot extend");
|
||||
r2(getUrl('home'), 'e', "cannot extend");
|
||||
}
|
||||
if (!empty(App::getTokenValue(_get('stoken')))) {
|
||||
r2(U . 'home', 'e', "You already extend");
|
||||
r2(getUrl('home'), 'e', "You already extend");
|
||||
}
|
||||
$id = _get('extend');
|
||||
$tur = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->where('id', $id)->find_one();
|
||||
@ -150,7 +172,7 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
// is already extend
|
||||
$last = file_get_contents($path);
|
||||
if ($last == $m) {
|
||||
r2(U . 'home', 'e', "You already extend for this month");
|
||||
r2(getUrl('home'), 'e', "You already extend for this month");
|
||||
}
|
||||
}
|
||||
if ($tur['status'] != 'on') {
|
||||
@ -159,6 +181,8 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
global $isChangePlan;
|
||||
$isChangePlan = true;
|
||||
(new $p['device'])->add_customer($user, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -178,12 +202,12 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
"\nLocation: " . $p['routers'] .
|
||||
"\nCustomer: " . $user['fullname'] .
|
||||
"\nNew Expired: " . Lang::dateAndTimeFormat($expiration, $tur['time']));
|
||||
r2(U . 'home', 's', "Extend until $expiration");
|
||||
r2(getUrl('home'), 's', "Extend until $expiration");
|
||||
} else {
|
||||
r2(U . 'home', 'e', "Plan is not expired");
|
||||
r2(getUrl('home'), 'e', "Plan is not expired");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'home', 'e', "Plan Not Found or Not Active");
|
||||
r2(getUrl('home'), 'e', "Plan Not Found or Not Active");
|
||||
}
|
||||
} else if (isset($_GET['deactivate']) && !empty($_GET['deactivate'])) {
|
||||
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['deactivate'])->where('username', $user['username'])->findOne();
|
||||
@ -204,9 +228,9 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
$bill->save();
|
||||
_log('User ' . $bill['username'] . ' Deactivate ' . $bill['namebp'], 'Customer', $bill['customer_id']);
|
||||
Message::sendTelegram('User u' . $bill['username'] . ' Deactivate ' . $bill['namebp']);
|
||||
r2(U . 'home', 's', 'Success deactivate ' . $bill['namebp']);
|
||||
r2(getUrl('home'), 's', 'Success deactivate ' . $bill['namebp']);
|
||||
} else {
|
||||
r2(U . 'home', 'e', 'No Active Plan');
|
||||
r2(getUrl('home'), 'e', 'No Active Plan');
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,10 +245,10 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && $_c['hs_auth_m
|
||||
require_once $dvc;
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
(new $p['device'])->connect_customer($user, $_SESSION['nux-ip'], $_SESSION['nux-mac'], $bill['routers']);
|
||||
r2(U . 'home', 's', Lang::T('Login Request successfully'));
|
||||
r2(getUrl('home'), 's', Lang::T('Login Request successfully'));
|
||||
} else if ($_GET['mikrotik'] == 'logout') {
|
||||
(new $p['device'])->disconnect_customer($user, $bill['routers']);
|
||||
r2(U . 'home', 's', Lang::T('Logout Request successfully'));
|
||||
r2(getUrl('home'), 's', Lang::T('Logout Request successfully'));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -233,7 +257,7 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && $_c['hs_auth_m
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSION['nux-hostname']) && $_c['hs_auth_method'] == 'hchap')) {
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff')|| $_SERVER['SERVER_PORT'] == 443)?'https':'http').'://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff') || $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$ui->assign('nux_mac', $_SESSION['nux-mac']);
|
||||
$ui->assign('nux_ip', $_SESSION['nux-ip']);
|
||||
$keys = explode('-', $_SESSION['nux-key']);
|
||||
@ -244,23 +268,23 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
|
||||
$ui->assign('hchap', $_GET['hchap']);
|
||||
$ui->assign('logged', $_GET['logged']);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home&logged=1', 's', $msg);
|
||||
} else if($getmsg){
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home', 's', $msg);
|
||||
}
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if ($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home&logged=1'), 's', $msg);
|
||||
} else if ($getmsg) {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home'), 's', $msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSION['nux-hostname']) && $_c['hs_auth_method'] == 'hchap')) {
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff')|| $_SERVER['SERVER_PORT'] == 443)?'https':'http').'://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff') || $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$ui->assign('nux_mac', $_SESSION['nux-mac']);
|
||||
$ui->assign('nux_ip', $_SESSION['nux-ip']);
|
||||
$keys = explode('-', $_SESSION['nux-key']);
|
||||
@ -271,29 +295,61 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
|
||||
$ui->assign('hchap', $_GET['hchap']);
|
||||
$ui->assign('logged', $_GET['logged']);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home&logged=1', 's', $msg);
|
||||
} else if($getmsg){
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home', 's', $msg);
|
||||
}
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if ($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home&logged=1'), 's', $msg);
|
||||
} else if ($getmsg) {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home'), 's', $msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('unpaid', ORM::for_table('tbl_payment_gateway')
|
||||
$tcf = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $user['id'])
|
||||
->find_many();
|
||||
$vpn = ORM::for_table('tbl_port_pool')
|
||||
->find_one();
|
||||
$ui->assign('cf', $tcf);
|
||||
$ui->assign('vpn', $vpn);
|
||||
|
||||
$unpaid = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one());
|
||||
->find_one();
|
||||
|
||||
// check expired payments
|
||||
if ($unpaid) {
|
||||
try {
|
||||
if (strtotime($unpaid['expired_date']) < time()) {
|
||||
$unpaid->status = 4;
|
||||
$unpaid->save();
|
||||
$unpaid = [];
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
try {
|
||||
if (strtotime($unpaid['created_date'], "+24 HOUR") < time()) {
|
||||
$unpaid->status = 4;
|
||||
$unpaid->save();
|
||||
$unpaid = [];
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('unpaid', $unpaid);
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-"));
|
||||
|
||||
$abills = User::getAttributes("Bill");
|
||||
$ui->assign('abills', $abills);
|
||||
|
||||
run_hook('view_customer_dashboard'); #HOOK
|
||||
$ui->display('user-dashboard.tpl');
|
||||
$ui->display('customer/dashboard.tpl');
|
||||
|
@ -11,7 +11,7 @@ if ($maintenance_mode == true) {
|
||||
}
|
||||
|
||||
if (User::getID()) {
|
||||
r2(U . 'home');
|
||||
r2(getUrl('home'));
|
||||
}
|
||||
|
||||
if (isset($routes['1'])) {
|
||||
@ -24,6 +24,11 @@ switch ($do) {
|
||||
case 'post':
|
||||
$username = _post('username');
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
run_hook('customer_login'); #HOOK
|
||||
if ($username != '' and $password != '') {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
@ -34,30 +39,42 @@ switch ($do) {
|
||||
}
|
||||
if (Password::_uverify($password, $d_pass) == true) {
|
||||
$_SESSION['uid'] = $d['id'];
|
||||
User::setCookie($d['id']);
|
||||
$token = User::setCookie($d['id']);
|
||||
$d->last_login = date('Y-m-d H:i:s');
|
||||
$d->save();
|
||||
_log($username . ' ' . Lang::T('Login Successful'), 'User', $d['id']);
|
||||
if ($isApi) {
|
||||
if ($token) {
|
||||
showResult(true, Lang::T('Login Successful'), ['token' => "u." . $token]);
|
||||
} else {
|
||||
showResult(false, Lang::T('Invalid Username or Password'));
|
||||
}
|
||||
}
|
||||
_alert(Lang::T('Login Successful'), 'success', "home");
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
_log($username . ' ' . Lang::T('Failed Login'), 'User');
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'activation':
|
||||
if (!empty(_post('voucher_only'))) {
|
||||
$voucher = _post('voucher_only');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
$voucher = Text::alphanumeric(_post('voucher_only'), "-_.,");
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('username', $voucher)
|
||||
->where('customer_id', '0') // Voucher Only will make customer ID as 0
|
||||
@ -86,7 +103,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -95,13 +112,13 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
|
||||
}
|
||||
} else {
|
||||
$v = ORM::for_table('tbl_voucher')->where('code', $voucher)->find_one();
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$voucher'")->find_one();
|
||||
if (!$v) {
|
||||
_alert(Lang::T('Voucher invalid'), 'danger', "login");
|
||||
}
|
||||
@ -131,7 +148,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -140,7 +157,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
|
||||
@ -156,9 +173,9 @@ switch ($do) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$voucher = _post('voucher');
|
||||
$voucher = Text::alphanumeric(_post('voucher'), "-_.,");
|
||||
$username = _post('username');
|
||||
$v1 = ORM::for_table('tbl_voucher')->where('code', $voucher)->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$voucher'")->find_one();
|
||||
if ($v1) {
|
||||
// voucher exists, check customer exists or not
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
@ -173,11 +190,11 @@ switch ($do) {
|
||||
if ($d->save()) {
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one($d->id());
|
||||
if (!$user) {
|
||||
r2(U . 'login', 'e', Lang::T('Voucher activation failed'));
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed'));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Login Successful'), 'success', "dashboard");
|
||||
r2(U . 'login', 'e', Lang::T('Voucher activation failed') . '.');
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed') . '.');
|
||||
}
|
||||
}
|
||||
if ($v1['status'] == 0) {
|
||||
@ -205,7 +222,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -214,26 +231,26 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
// if failed to recharge, restore old password
|
||||
$user->password = $oldPass;
|
||||
$user->save();
|
||||
r2(U . 'login', 'e', Lang::T("Failed to activate voucher"));
|
||||
r2(getUrl('login'), 'e', Lang::T("Failed to activate voucher"));
|
||||
}
|
||||
} else {
|
||||
// used voucher
|
||||
@ -252,7 +269,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -261,39 +278,80 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// voucher used by other customer
|
||||
r2(U . 'login', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
}
|
||||
default:
|
||||
run_hook('customer_view_login'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
if ($config['disable_registration'] == 'yes') {
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Activation'));
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-"));
|
||||
$ui->display('user-login-noreg.tpl');
|
||||
$ui->display('customer/login-noreg.tpl');
|
||||
} else {
|
||||
$ui->display('user-login.tpl');
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Login'));
|
||||
switch ($config['login_page_type']) {
|
||||
case 'custom':
|
||||
$ui->display('customer/login-custom-' . $config['login_Page_template'] . '.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('customer/login.tpl');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
run_hook('customer_logout'); #HOOK
|
||||
if (session_status() == PHP_SESSION_NONE) session_start();
|
||||
Admin::removeCookie();
|
||||
User::removeCookie();
|
||||
session_destroy();
|
||||
_alert(Lang::T('Logout Successful'),'warning', "login");
|
||||
_alert(Lang::T('Logout Successful'), 'warning', "login");
|
||||
|
@ -85,7 +85,7 @@ switch ($action) {
|
||||
$keep = _post('keep');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM tbl_logs WHERE UNIX_TIMESTAMP(date) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
|
||||
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
|
||||
r2(getUrl('logs/list/'), 's', "Delete logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id');
|
||||
@ -104,7 +104,7 @@ switch ($action) {
|
||||
$keep = _post('keep');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM radpostauth WHERE UNIX_TIMESTAMP(authdate) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))", [], 'radius');
|
||||
r2(U . "logs/radius/", 's', "Delete logs older than $keep days");
|
||||
r2(getUrl('logs/radius/'), 's', "Delete logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id');
|
||||
@ -121,5 +121,5 @@ switch ($action) {
|
||||
|
||||
|
||||
default:
|
||||
r2(U . 'logs/list/', 's', '');
|
||||
r2(getUrl('logs/list/'), 's', '');
|
||||
}
|
||||
|
61
system/controllers/mail.php
Normal file
61
system/controllers/mail.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
_auth();
|
||||
$action = $routes['1'];
|
||||
$user = User::_info();
|
||||
$ui->assign('_user', $user);
|
||||
|
||||
switch ($action) {
|
||||
case 'view':
|
||||
$mail = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->find_one($routes['2']);
|
||||
if(!$mail){
|
||||
r2(getUrl('mail'), 'e', Lang::T('Message Not Found'));
|
||||
}
|
||||
if($mail['date_read'] == null){
|
||||
$mail->date_read = date('Y-m-d H:i:s');
|
||||
$mail->save();
|
||||
}
|
||||
$next = ORM::for_table('tbl_customers_inbox')->select("id")->where('customer_id', $user['id'])->where_gt("id", $routes['2'])->order_by_asc("id")->find_one();
|
||||
$prev = ORM::for_table('tbl_customers_inbox')->select("id")->where('customer_id', $user['id'])->where_lt("id", $routes['2'])->order_by_desc("id")->find_one();
|
||||
|
||||
$ui->assign('next', $next['id']);
|
||||
$ui->assign('prev', $prev['id']);
|
||||
$ui->assign('mail', $mail);
|
||||
$ui->assign('tipe', 'view');
|
||||
$ui->assign('_system_menu', 'inbox');
|
||||
$ui->assign('_title', Lang::T('Inbox'));
|
||||
$ui->display('customer/inbox.tpl');
|
||||
break;
|
||||
case 'delete':
|
||||
if($routes['2']){
|
||||
if(ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->where('id', $routes['2'])->find_one()->delete()){
|
||||
r2(getUrl('mail'), 's', Lang::T('Mail Deleted Successfully'));
|
||||
}else{
|
||||
r2(getUrl('home'), 'e', Lang::T('Failed to Delete Message'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
$q = _req('q');
|
||||
$limit = 40;
|
||||
$p = (int) _req('p', 0);
|
||||
$offset = $p * $limit;
|
||||
$query = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->order_by_desc('date_created');
|
||||
$query->limit($limit)->offset($offset);
|
||||
if(!empty($q)){
|
||||
$query->whereRaw("(subject like '%$q%' or body like '%$q%')");
|
||||
}
|
||||
$mails = $query->find_array();
|
||||
$ui->assign('tipe', '');
|
||||
$ui->assign('q', $q);
|
||||
$ui->assign('p', $p);
|
||||
$ui->assign('mails', $mails);
|
||||
$ui->assign('_system_menu', 'inbox');
|
||||
$ui->assign('_title', Lang::T('Inbox'));
|
||||
$ui->display('customer/inbox.tpl');
|
||||
}
|
@ -49,6 +49,6 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'map/customer', 'e', 'action not defined');
|
||||
r2(getUrl('map/customer'), 'e', 'action not defined');
|
||||
break;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
ajax: {
|
||||
url: function(params) {
|
||||
if(params.term != undefined){
|
||||
return './index.php?_route=autoload/customer_select2&s='+params.term;
|
||||
return './?_route=autoload/customer_select2&s='+params.term;
|
||||
}else{
|
||||
return './index.php?_route=autoload/customer_select2';
|
||||
return './?_route=autoload/customer_select2';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,7 @@ EOT;
|
||||
|
||||
// Check if fields are empty
|
||||
if ($id_customer == '' or $message == '' or $via == '') {
|
||||
r2(U . 'message/send', 'e', Lang::T('All field is required'));
|
||||
r2(getUrl('message/send'), 'e', Lang::T('All field is required'));
|
||||
} else {
|
||||
// Get customer details from the database
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id_customer);
|
||||
@ -84,9 +84,9 @@ EOT;
|
||||
}
|
||||
|
||||
if (isset($smsSent) || isset($waSent)) {
|
||||
r2(U . 'message/send', 's', Lang::T('Message Sent Successfully'));
|
||||
r2(getUrl('message/send'), 's', Lang::T('Message Sent Successfully'));
|
||||
} else {
|
||||
r2(U . 'message/send', 'e', Lang::T('Failed to send message'));
|
||||
r2(getUrl('message/send'), 'e', Lang::T('Failed to send message'));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -114,7 +114,7 @@ EOT;
|
||||
if (_req('send') == 'now') {
|
||||
// Check if fields are empty
|
||||
if ($group == '' || $message == '' || $via == '') {
|
||||
r2(U . 'message/send_bulk', 'e', Lang::T('All fields are required'));
|
||||
r2(getUrl('message/send_bulk'), 'e', Lang::T('All fields are required'));
|
||||
} else {
|
||||
// Get customer details from the database based on the selected group
|
||||
if ($group == 'all') {
|
||||
@ -234,5 +234,5 @@ EOT;
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'message/send_sms', 'e', 'action not defined');
|
||||
r2(getUrl('message/send_sms'), 'e', 'action not defined');
|
||||
}
|
||||
|
@ -15,30 +15,36 @@ switch ($action) {
|
||||
$ui->assign('_system_menu', 'voucher');
|
||||
$ui->assign('_title', Lang::T('Order Voucher'));
|
||||
run_hook('customer_view_order'); #HOOK
|
||||
$ui->display('user-order.tpl');
|
||||
$ui->display('customer/order.tpl');
|
||||
break;
|
||||
case 'history':
|
||||
$ui->assign('_system_menu', 'history');
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('username', $user['username'])->order_by_desc('id');
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('user_id', $user['id'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
|
||||
if (empty($order) || $order < 5) {
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('username', $user['username'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', Lang::T('Order History'));
|
||||
run_hook('customer_view_order_history'); #HOOK
|
||||
$ui->display('user-orderHistory.tpl');
|
||||
$ui->display('customer/orderHistory.tpl');
|
||||
break;
|
||||
case 'balance':
|
||||
if (strpos($user['email'], '@') === false) {
|
||||
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$ui->assign('_title', 'Top Up');
|
||||
$ui->assign('_system_menu', 'balance');
|
||||
$plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->where('prepaid', 'yes')->find_many();
|
||||
$ui->assign('plans_balance', $plans_balance);
|
||||
$ui->display('user-orderBalance.tpl');
|
||||
$ui->display('customer/orderBalance.tpl');
|
||||
break;
|
||||
case 'package':
|
||||
if (strpos($user['email'], '@') === false) {
|
||||
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$ui->assign('_title', 'Order Plan');
|
||||
$ui->assign('_system_menu', 'package');
|
||||
@ -48,32 +54,86 @@ switch ($action) {
|
||||
}
|
||||
if (!empty($_SESSION['nux-router'])) {
|
||||
if ($_SESSION['nux-router'] == 'radius') {
|
||||
$radius_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
|
||||
$radius_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
|
||||
$radius_pppoe = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where('is_radius', 1)
|
||||
->where('type', 'PPPOE')
|
||||
->where('prepaid', 'yes')->find_many();
|
||||
$radius_hotspot = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where('is_radius', 1)
|
||||
->where('type', 'Hotspot')
|
||||
->where('prepaid', 'yes')->find_many();
|
||||
} else {
|
||||
$routers = ORM::for_table('tbl_routers')->where('id', $_SESSION['nux-router'])->find_many();
|
||||
$rs = [];
|
||||
foreach ($routers as $r) {
|
||||
$rs[] = $r['name'];
|
||||
}
|
||||
$plans_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
|
||||
$plans_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
|
||||
$plans_pppoe = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where_in('routers', $rs)
|
||||
->where('is_radius', 0)
|
||||
->where('type', 'PPPOE')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
$plans_hotspot = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where_in('routers', $rs)
|
||||
->where('is_radius', 0)
|
||||
->where('type', 'Hotspot')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
}
|
||||
} else {
|
||||
$radius_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
|
||||
$radius_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
|
||||
$radius_pppoe = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where('is_radius', 1)
|
||||
->where('type', 'PPPOE')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
$radius_hotspot = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where('is_radius', 1)
|
||||
->where('type', 'Hotspot')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
|
||||
$routers = ORM::for_table('tbl_routers')->find_many();
|
||||
$plans_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 0)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
|
||||
$plans_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
|
||||
$plans_pppoe = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')
|
||||
->where('is_radius', 0)
|
||||
->where('type', 'PPPOE')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
$plans_hotspot = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')->where('is_radius', 0)
|
||||
->where('type', 'Hotspot')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
$plans_vpn = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')->where('is_radius', 0)
|
||||
->where('type', 'VPN')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
}
|
||||
$ui->assign('routers', $routers);
|
||||
$ui->assign('radius_pppoe', $radius_pppoe);
|
||||
$ui->assign('radius_hotspot', $radius_hotspot);
|
||||
$ui->assign('plans_pppoe', $plans_pppoe);
|
||||
$ui->assign('plans_hotspot', $plans_hotspot);
|
||||
$ui->assign('plans_vpn', $plans_vpn);
|
||||
run_hook('customer_view_order_plan'); #HOOK
|
||||
$ui->display('user-orderPlan.tpl');
|
||||
$ui->display('customer/orderPlan.tpl');
|
||||
break;
|
||||
case 'unpaid':
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
@ -84,12 +144,12 @@ switch ($action) {
|
||||
r_find_unpaid'); #HOOK
|
||||
if ($d) {
|
||||
if (empty($d['pg_url_payment'])) {
|
||||
r2(U . "order/buy/" . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
r2(getUrl('order/buy/') . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
} else {
|
||||
r2(U . "order/view/" . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
|
||||
r2(getUrl('order/view/') . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
|
||||
}
|
||||
} else {
|
||||
r2(U . "order/package/", 's', Lang::T("You have no unpaid transaction"));
|
||||
r2(getUrl('order/package/'), 's', Lang::T("You have no unpaid transaction"));
|
||||
}
|
||||
break;
|
||||
case 'view':
|
||||
@ -100,15 +160,15 @@ switch ($action) {
|
||||
run_hook('customer_view_payment'); #HOOK
|
||||
// jika tidak ditemukan, berarti punya orang lain
|
||||
if (empty($trx)) {
|
||||
r2(U . "order/package", 'w', Lang::T("Payment not found"));
|
||||
r2(getUrl('order/package'), 'w', Lang::T("Payment not found"));
|
||||
}
|
||||
// jika url kosong, balikin ke buy, kecuali cancel
|
||||
if (empty($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
|
||||
r2(U . "order/buy/" . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
if ($trx['status'] == 1 && empty($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
|
||||
r2(getUrl('order/buy/') . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
}
|
||||
if ($routes['3'] == 'check') {
|
||||
if (!file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php')) {
|
||||
r2(U . 'order/view/' . $trxid, 'e', Lang::T("No Payment Gateway Available"));
|
||||
r2(getUrl('order/view/') . $trxid, 'e', Lang::T("No Payment Gateway Available"));
|
||||
}
|
||||
run_hook('customer_check_payment_status'); #HOOK
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php';
|
||||
@ -125,7 +185,7 @@ switch ($action) {
|
||||
->find_one($trxid);
|
||||
}
|
||||
if (empty($trx)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Transaction Not found"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Transaction Not found"));
|
||||
}
|
||||
|
||||
$router = ORM::for_table('tbl_routers')->where('name', $trx['routers'])->find_one();
|
||||
@ -138,28 +198,26 @@ switch ($action) {
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('bandw', $bandw);
|
||||
$ui->assign('_title', 'TRX #' . $trxid);
|
||||
$ui->display('user-orderView.tpl');
|
||||
$ui->display('customer/orderView.tpl');
|
||||
break;
|
||||
case 'pay':
|
||||
if ($config['enable_balance'] != 'yes') {
|
||||
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
|
||||
}
|
||||
if (!empty(App::getTokenValue($_GET['stoken']))) {
|
||||
r2(U . "voucher/invoice/");
|
||||
r2(getUrl('voucher/invoice/'));
|
||||
die();
|
||||
}
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
|
||||
if (empty($plan)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($routes[3]);
|
||||
if (!$plan) {
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
}
|
||||
if ($routes['2'] == 'radius') {
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$router_name = 'radius';
|
||||
$router = 'radius';
|
||||
} else {
|
||||
$router_name = $plan['routers'];
|
||||
}
|
||||
@ -183,27 +241,27 @@ switch ($action) {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
|
||||
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price'] + $tax) {
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
if ($plan && $plan['enabled'] && $user['balance'] >= $total_cost) {
|
||||
if (Package::rechargeUser($user['id'], $router_name, $plan['id'], 'Customer', 'Balance')) {
|
||||
// if success, then get the balance
|
||||
Balance::min($user['id'], $plan['price'] + $add_cost + $tax);
|
||||
Balance::min($user['id'], $total_cost);
|
||||
App::setToken($_GET['stoken'], "success");
|
||||
r2(U . "voucher/invoice/", 's', Lang::T("Success to buy package"));
|
||||
r2(getUrl('voucher/invoice/'), 's', Lang::T("Success to buy package"));
|
||||
} else {
|
||||
r2(U . "order/package", 'e', Lang::T("Failed to buy package"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Failed to buy package"));
|
||||
Message::sendTelegram("Buy Package with Balance Failed\n\n#u$c[username] #buy \n" . $plan['name_plan'] .
|
||||
"\nRouter: " . $router_name .
|
||||
"\nPrice: " . $plan['price'] + $tax);
|
||||
"\nPrice: " . $total_cost);
|
||||
}
|
||||
} else {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
r2(getUrl('order/gateway/$routes[2]/$routes[3]'), 'e', Lang::T("Insufficient balance"));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'send':
|
||||
if ($config['enable_balance'] != 'yes') {
|
||||
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
|
||||
}
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
@ -212,12 +270,13 @@ switch ($action) {
|
||||
$ui->assign('_system_menu', 'package');
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
|
||||
if (empty($plan)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
r2(getUrl('home'), 'e', 'Plan is not exists');
|
||||
}
|
||||
if ($routes['2'] == 'radius') {
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$routes['2'] = 0;
|
||||
$router_name = 'radius';
|
||||
} else {
|
||||
$router_name = $plan['routers'];
|
||||
@ -253,13 +312,13 @@ switch ($action) {
|
||||
}
|
||||
|
||||
if (!$target) {
|
||||
r2(U . 'home', 'd', Lang::T('Username not found'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Username not found'));
|
||||
}
|
||||
if ($user['balance'] < $plan['price']) {
|
||||
r2(U . 'home', 'd', Lang::T('insufficient balance'));
|
||||
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
|
||||
}
|
||||
if ($user['username'] == $target['username']) {
|
||||
r2(U . "order/pay/$routes[2]/$routes[3]", 's', '^_^ v');
|
||||
r2(getUrl('order/pay/$routes[2]/$routes[3]'), 's', '^_^ v');
|
||||
}
|
||||
$active = ORM::for_table('tbl_user_recharges')
|
||||
->where('username', _post('username'))
|
||||
@ -267,7 +326,7 @@ switch ($action) {
|
||||
->find_one();
|
||||
|
||||
if ($active && $active['plan_id'] != $plan['id']) {
|
||||
r2(U . "order/package", 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
|
||||
}
|
||||
$result = Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['username'], 'Balance');
|
||||
if (!empty($result)) {
|
||||
@ -276,6 +335,7 @@ switch ($action) {
|
||||
//sender
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $target['username'];
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
@ -295,6 +355,7 @@ switch ($action) {
|
||||
//receiver
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $target['username'];
|
||||
$d->user_id = $target['id'];
|
||||
$d->gateway = $user['username'];
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
@ -310,7 +371,7 @@ switch ($action) {
|
||||
$d->trx_invoice = $result;
|
||||
$d->status = 2;
|
||||
$d->save();
|
||||
r2(U . "order/view/$trx_id", 's', Lang::T("Success to send package"));
|
||||
r2(getUrl('order/view/$trx_id'), 's', Lang::T("Success to send package"));
|
||||
} else {
|
||||
$errorMessage = "Send Package with Balance Failed\n\n#u$user[username] #send \n" . $plan['name_plan'] .
|
||||
"\nRouter: " . $router_name .
|
||||
@ -320,7 +381,7 @@ switch ($action) {
|
||||
$errorMessage .= "\nTax: " . $tax;
|
||||
}
|
||||
|
||||
r2(U . "order/package", 'e', Lang::T("Failed to Send package"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Failed to Send package"));
|
||||
Message::sendTelegram($errorMessage);
|
||||
}
|
||||
}
|
||||
@ -328,13 +389,13 @@ switch ($action) {
|
||||
$ui->assign('router', $router_name);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('tax', $tax);
|
||||
$ui->display('user-sendPlan.tpl');
|
||||
$ui->display('customer/sendPlan.tpl');
|
||||
break;
|
||||
case 'gateway':
|
||||
$ui->assign('_title', Lang::T('Select Payment Gateway'));
|
||||
$ui->assign('_system_menu', 'package');
|
||||
if (strpos($user['email'], '@') === false) {
|
||||
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
@ -345,34 +406,139 @@ switch ($action) {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
$add_cost = 0;
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
|
||||
if($config['enable_coupons']){
|
||||
if (!isset($_SESSION['coupon_attempts'])) {
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
}
|
||||
|
||||
if ($_SESSION['coupon_attempts'] >= 5) {
|
||||
$timeout = 10 * 60; // 10 minutes in seconds
|
||||
$time_diff = time() - $_SESSION['last_attempt_time'];
|
||||
|
||||
if ($time_diff >= $timeout) {
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
} else {
|
||||
$remaining_time = ceil(($timeout - $time_diff) / 60);
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Too many invalid attempts. Please try again after $remaining_time minutes."));
|
||||
}
|
||||
}
|
||||
|
||||
if (_post('coupon')) {
|
||||
if ($plan['routers'] === 'balance') {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not available for Balance"));
|
||||
}
|
||||
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('code', _post('coupon'))->find_one();
|
||||
|
||||
if (!$coupon) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not found"));
|
||||
}
|
||||
|
||||
if ($coupon['status'] != 'active') {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon is not active"));
|
||||
}
|
||||
|
||||
// Reset attempts after a successful coupon validation
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
|
||||
$today = date('Y-m-d');
|
||||
if ($today < $coupon['start_date'] || $today > $coupon['end_date']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon is not valid for today"));
|
||||
}
|
||||
|
||||
if ($coupon['max_usage'] > 0 && $coupon['usage_count'] >= $coupon['max_usage']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon usage limit reached"));
|
||||
}
|
||||
|
||||
if ($plan['price'] < $coupon['min_order_amount']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("The order amount does not meet the minimum requirement for this coupon"));
|
||||
}
|
||||
|
||||
// Calculate discount value
|
||||
$discount = 0;
|
||||
switch ($coupon['type']) {
|
||||
case 'percent':
|
||||
$discount = ($coupon['value'] / 100) * $plan['price'];
|
||||
if ($discount > $coupon['max_discount_amount']) {
|
||||
$discount = $coupon['max_discount_amount'];
|
||||
}
|
||||
break;
|
||||
case 'fixed':
|
||||
$discount = $coupon['value'];
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure discount does not exceed the plan price
|
||||
if ($discount >= $plan['price']) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Discount value exceeds the plan price"));
|
||||
}
|
||||
|
||||
$plan['price'] -= $discount;
|
||||
$coupon->usage_count = $coupon['usage_count'] + 1;
|
||||
$coupon->save();
|
||||
|
||||
$ui->assign('discount', $discount);
|
||||
$ui->assign('notify', Lang::T("Coupon applied successfully. You saved " . Lang::moneyFormat($discount)));
|
||||
$ui->assign('notify_t', 's');
|
||||
}
|
||||
}
|
||||
|
||||
$tax = Package::tax($plan['price'] + $add_cost, $tax_rate);
|
||||
$pgs = array_values(explode(',', $config['payment_gateway']));
|
||||
if (count($pgs) == 0) {
|
||||
sendTelegram("Payment Gateway not set, please set it in Settings");
|
||||
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
|
||||
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
|
||||
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
|
||||
}
|
||||
if (count($pgs) > 1) {
|
||||
if (count($pgs) > 0) {
|
||||
$ui->assign('pgs', $pgs);
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
|
||||
if (_post('custom') == '1') {
|
||||
if (_post('amount') > 0) {
|
||||
$ui->assign('custom', '1');
|
||||
$ui->assign('amount', _post('amount'));
|
||||
} else {
|
||||
r2(getUrl('order/balance'), 'e', Lang::T("Please enter amount"));
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('route2', $routes[2]);
|
||||
$ui->assign('route3', $routes[3]);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->display('user-selectGateway.tpl');
|
||||
$ui->display('customer/selectGateway.tpl');
|
||||
break;
|
||||
} else {
|
||||
if (empty($pgs[0])) {
|
||||
sendTelegram("Payment Gateway not set, please set it in Settings");
|
||||
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
|
||||
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
|
||||
} else {
|
||||
$_POST['gateway'] = $pgs[0];
|
||||
}
|
||||
sendTelegram("Payment Gateway not set, please set it in Settings");
|
||||
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
|
||||
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
|
||||
}
|
||||
case 'buy':
|
||||
$gateway = _post('gateway');
|
||||
$discount = _post('discount') ?: 0;
|
||||
if ($gateway == 'balance') {
|
||||
unset($_SESSION['gateway']);
|
||||
r2(getUrl('order/pay/') . $routes[2] . '/' . $routes[3]);
|
||||
}
|
||||
if (empty($gateway) && !empty($_SESSION['gateway'])) {
|
||||
$gateway = $_SESSION['gateway'];
|
||||
} else if (!empty($gateway)) {
|
||||
@ -382,112 +548,156 @@ switch ($action) {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (empty($gateway)) {
|
||||
r2(U . 'order/gateway/' . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
|
||||
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
|
||||
}
|
||||
run_hook('customer_buy_plan'); #HOOK
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $gateway . '.php';
|
||||
call_user_func($gateway . '_validate_config');
|
||||
|
||||
if ($routes['2'] == 'radius') {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'radius';
|
||||
} else if ($routes['2'] > 0) {
|
||||
$router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']);
|
||||
} else {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'balance';
|
||||
}
|
||||
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
|
||||
if (empty($router) || empty($plan)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
if ($d['pg_url_payment']) {
|
||||
r2(U . "order/view/" . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
|
||||
} else {
|
||||
if ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
switch (_post('custom')) {
|
||||
case '1':
|
||||
$amount = _post('amount');
|
||||
$amount = (float) $amount;
|
||||
|
||||
if ($amount <= 0) {
|
||||
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please enter amount"));
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
if ($d['pg_url_payment']) {
|
||||
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
|
||||
} else {
|
||||
if ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = 0;
|
||||
$d->plan_name = 'Custom';
|
||||
$d->routers_id = '0';
|
||||
$d->routers = 'Custom Balance';
|
||||
$d->price = $amount;
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
$id = $d->id;
|
||||
break;
|
||||
|
||||
default:
|
||||
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'radius';
|
||||
} else if ($routes['2'] > 0) {
|
||||
$router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']);
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'balance';
|
||||
}
|
||||
if (empty($router) || empty($plan)) {
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
if ($d['pg_url_payment']) {
|
||||
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
|
||||
} else {
|
||||
if ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$add_cost = 0;
|
||||
$tax = 0;
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
}
|
||||
// Tax calculation stop
|
||||
if (empty($id)) {
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = $plan['price'] + $add_cost + $tax - $discount;
|
||||
} else {
|
||||
$d->price = $add_inv + $add_cost + $tax - $discount;
|
||||
}
|
||||
} else {
|
||||
$d->price = $plan['price'] + $add_cost + $tax - $discount;
|
||||
}
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
$id = $d->id();
|
||||
} else {
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax - $discount);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax - $discount);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax - $discount);
|
||||
}
|
||||
//$d->price = ($plan['price'] + $add_cost);
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$add_cost = 0;
|
||||
$tax = 0;
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
}
|
||||
// Tax calculation stop
|
||||
if (empty($id)) {
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
}
|
||||
//$d->price = ($plan['price'] + $add_cost);
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
$id = $d->id();
|
||||
} else {
|
||||
$d->username = $user['username'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
}
|
||||
//$d->price = ($plan['price'] + $add_cost);
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
break;
|
||||
}
|
||||
if (!$id) {
|
||||
r2(U . "order/package/" . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
|
||||
r2(getUrl('order/package/') . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
|
||||
} else {
|
||||
call_user_func($gateway . '_create_transaction', $d, $user);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r2(U . "order/package/", 's', '');
|
||||
r2(getUrl('order/package/'), 's', '');
|
||||
}
|
||||
|
@ -16,6 +16,6 @@ if(file_exists(__DIR__."/../../pages/".str_replace(".","",$action).".html")){
|
||||
$ui->assign("PageFile",$action);
|
||||
$ui->assign("pageHeader",$action);
|
||||
run_hook('customer_view_page'); #HOOK
|
||||
$ui->display('user-pages.tpl');
|
||||
$ui->display('customer/pages.tpl');
|
||||
}else
|
||||
$ui->display('404.tpl');
|
||||
$ui->display('customer/404.tpl');
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
@ -11,61 +12,76 @@ $ui->assign('_system_menu', 'pages');
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if(strpos($action,"-reset")!==false){
|
||||
if (strpos($action, "-reset") !== false) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$action = str_replace("-reset","",$action);
|
||||
$path = "pages/".str_replace(".","",$action).".html";
|
||||
$temp = "pages_template/".str_replace(".","",$action).".html";
|
||||
if(file_exists($temp)){
|
||||
if(!copy($temp, $path)){
|
||||
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/'.$action.'.html'));
|
||||
$action = str_replace("-reset", "", $action);
|
||||
$path = "$PAGES_PATH/" . str_replace(".", "", $action) . ".html";
|
||||
$temp = "pages_template/" . str_replace(".", "", $action) . ".html";
|
||||
if (file_exists($temp)) {
|
||||
if (!copy($temp, $path)) {
|
||||
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/' . $action . '.html'));
|
||||
}
|
||||
}else{
|
||||
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/'.$action.'.html'));
|
||||
} else {
|
||||
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/' . $action . '.html'));
|
||||
}
|
||||
r2(U . 'pages/'.$action);
|
||||
}else if(strpos($action,"-post")===false){
|
||||
r2(getUrl('pages/') . $action);
|
||||
} else if (strpos($action, "-post") === false) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$path = "pages/".str_replace(".","",$action).".html";
|
||||
$path = "$PAGES_PATH/" . str_replace(".", "", $action) . ".html";
|
||||
$ui->assign("action", $action);
|
||||
//echo $path;
|
||||
run_hook('view_edit_pages'); #HOOK
|
||||
if(!file_exists($path)){
|
||||
$temp = "pages_template/".str_replace(".","",$action).".html";
|
||||
if(file_exists($temp)){
|
||||
if(!copy($temp, $path)){
|
||||
if (!file_exists($path)) {
|
||||
$temp = "pages_template/" . str_replace(".", "", $action) . ".html";
|
||||
if (file_exists($temp)) {
|
||||
if (!copy($temp, $path)) {
|
||||
touch($path);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
touch($path);
|
||||
}
|
||||
}
|
||||
if(file_exists($path)){
|
||||
if (file_exists($path)) {
|
||||
if ($action == 'Voucher') {
|
||||
if (!file_exists("$PAGES_PATH/vouchers/")) {
|
||||
mkdir("$PAGES_PATH/vouchers/");
|
||||
if (file_exists("pages_template/vouchers/")) {
|
||||
File::copyFolder("pages_template/vouchers/", "$PAGES_PATH/vouchers/");
|
||||
}
|
||||
}
|
||||
$ui->assign("vouchers", scandir("$PAGES_PATH/vouchers/"));
|
||||
}
|
||||
$html = file_get_contents($path);
|
||||
$ui->assign("htmls",str_replace(["<div","</div>"],"",$html));
|
||||
$ui->assign("writeable",is_writable($path));
|
||||
$ui->assign("pageHeader",str_replace('_', ' ', $action));
|
||||
$ui->assign("PageFile",$action);
|
||||
$ui->assign("htmls", str_replace(["<div", "</div>"], "", $html));
|
||||
$ui->assign("writeable", is_writable($path));
|
||||
$ui->assign("pageHeader", str_replace('_', ' ', $action));
|
||||
$ui->assign("PageFile", $action);
|
||||
$ui->display('page-edit.tpl');
|
||||
}else
|
||||
} else
|
||||
$ui->display('a404.tpl');
|
||||
}else{
|
||||
} else {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$action = str_replace("-post","",$action);
|
||||
$path = "pages/".str_replace(".","",$action).".html";
|
||||
if(file_exists($path)){
|
||||
$action = str_replace("-post", "", $action);
|
||||
$path = "$PAGES_PATH/" . str_replace(".", "", $action) . ".html";
|
||||
if (file_exists($path)) {
|
||||
$html = _post("html");
|
||||
run_hook('save_pages'); #HOOK
|
||||
if(file_put_contents($path, str_replace(["<div","</div>"],"",$html))){
|
||||
r2(U . 'pages/'.$action, 's', Lang::T("Saving page success"));
|
||||
}else{
|
||||
r2(U . 'pages/'.$action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
|
||||
if (file_put_contents($path, $html)) {
|
||||
if (_post('template_save') == 'yes') {
|
||||
if (!empty(_post('template_name'))) {
|
||||
file_put_contents("$PAGES_PATH/vouchers/" . _post('template_name') . '.html', $html);
|
||||
}
|
||||
}
|
||||
r2(getUrl('pages/') . $action, 's', Lang::T("Saving page success"));
|
||||
} else {
|
||||
r2(getUrl('pages/') . $action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
|
||||
}
|
||||
}else
|
||||
} else
|
||||
$ui->display('a404.tpl');
|
||||
}
|
||||
}
|
||||
|
@ -10,63 +10,91 @@ $ui->assign('_system_menu', 'paymentgateway');
|
||||
|
||||
$action = alphanumeric($routes[1]);
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if ($action == 'delete') {
|
||||
$pg = alphanumeric($routes[2]);
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $pg . '.php')) {
|
||||
deleteFile($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, $pg);
|
||||
}
|
||||
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway Deleted'));
|
||||
}
|
||||
|
||||
if (_post('save') == 'actives') {
|
||||
$pgs = '';
|
||||
if(is_array($_POST['pgs'])){
|
||||
$pgs = implode(',', $_POST['pgs']);
|
||||
}
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'payment_gateway')->find_one();
|
||||
if ($d) {
|
||||
$d->value = $pgs;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'payment_gateway';
|
||||
$d->value = $pgs;
|
||||
$d->save();
|
||||
}
|
||||
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway saved successfully'));
|
||||
}
|
||||
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php')) {
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (function_exists($action . '_save_config')) {
|
||||
call_user_func($action . '_save_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
switch ($action) {
|
||||
case 'delete':
|
||||
$pg = alphanumeric($routes[2]);
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $pg . '.php')) {
|
||||
deleteFile($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, $pg);
|
||||
}
|
||||
} else {
|
||||
if (function_exists($action . '_show_config')) {
|
||||
call_user_func($action . '_show_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway Deleted'));
|
||||
|
||||
case 'audit':
|
||||
$pg = alphanumeric($routes[2]);
|
||||
$q = alphanumeric(_req('q'), '-._ ');
|
||||
$query = ORM::for_table('tbl_payment_gateway')->order_by_desc("id");
|
||||
$query->selects('id', 'username', 'gateway', 'gateway_trx_id', 'plan_id', 'plan_name', 'routers_id', 'routers', 'price', 'pg_url_payment', 'payment_method', 'payment_channel', 'expired_date', 'created_date', 'paid_date', 'trx_invoice', 'status');
|
||||
$query->where('gateway', $pg);
|
||||
if (!empty($q)) {
|
||||
$query->whereRaw("(gateway_trx_id LIKE '%$q%' OR username LIKE '%$q%' OR routers LIKE '%$q%' OR plan_name LIKE '%$q%')");
|
||||
$append_url = 'q=' . urlencode($q);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($action)) {
|
||||
r2(U . 'paymentgateway', 'w', Lang::T('Payment Gateway Not Found'));
|
||||
} else {
|
||||
$files = scandir($PAYMENTGATEWAY_PATH);
|
||||
foreach ($files as $file) {
|
||||
if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
|
||||
$pgs[] = str_replace('.php', '', $file);
|
||||
$pgs = Paginator::findMany($query, ["search" => $search], 50, $append_url);
|
||||
|
||||
$ui->assign('_title', 'Payment Gateway Audit');
|
||||
$ui->assign('pgs', $pgs);
|
||||
$ui->assign('pg', $pg);
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('paymentgateway-audit.tpl');
|
||||
break;
|
||||
case 'auditview':
|
||||
$pg = alphanumeric($routes[2]);
|
||||
$d = ORM::for_table('tbl_payment_gateway')->find_one($pg);
|
||||
$d['pg_request'] = (!empty($d['pg_request']))? Text::jsonArray21Array(json_decode($d['pg_request'], true)) : [];
|
||||
$d['pg_paid_response'] = (!empty($d['pg_paid_response']))? Text::jsonArray21Array(json_decode($d['pg_paid_response'], true)) : [];
|
||||
$ui->assign('_title', 'Payment Gateway Audit View');
|
||||
$ui->assign('pg', $d);
|
||||
$ui->display('paymentgateway-audit-view.tpl');
|
||||
break;
|
||||
default:
|
||||
if (_post('save') == 'actives') {
|
||||
$pgs = '';
|
||||
if (is_array($_POST['pgs'])) {
|
||||
$pgs = implode(',', $_POST['pgs']);
|
||||
}
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'payment_gateway')->find_one();
|
||||
if ($d) {
|
||||
$d->value = $pgs;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'payment_gateway';
|
||||
$d->value = $pgs;
|
||||
$d->save();
|
||||
}
|
||||
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway saved successfully'));
|
||||
}
|
||||
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php')) {
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (function_exists($action . '_save_config')) {
|
||||
call_user_func($action . '_save_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
}
|
||||
} else {
|
||||
if (function_exists($action . '_show_config')) {
|
||||
call_user_func($action . '_show_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($action)) {
|
||||
r2(getUrl('paymentgateway'), 'w', Lang::T('Payment Gateway Not Found'));
|
||||
} else {
|
||||
$files = scandir($PAYMENTGATEWAY_PATH);
|
||||
foreach ($files as $file) {
|
||||
if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
|
||||
$pgs[] = str_replace('.php', '', $file);
|
||||
}
|
||||
}
|
||||
$ui->assign('_title', 'Payment Gateway Settings');
|
||||
$ui->assign('pgs', $pgs);
|
||||
$ui->assign('actives', explode(',', $config['payment_gateway']));
|
||||
$ui->display('paymentgateway.tpl');
|
||||
}
|
||||
}
|
||||
$ui->assign('_title', 'Payment Gateway Settings');
|
||||
$ui->assign('pgs', $pgs);
|
||||
$ui->assign('actives', explode(',', $config['payment_gateway']));
|
||||
$ui->display('paymentgateway.tpl');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,9 +20,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
ajax: {
|
||||
url: function(params) {
|
||||
if(params.term != undefined){
|
||||
return './index.php?_route=autoload/customer_select2&s='+params.term;
|
||||
return './?_route=autoload/customer_select2&s='+params.term;
|
||||
}else{
|
||||
return './index.php?_route=autoload/customer_select2';
|
||||
return './?_route=autoload/customer_select2';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,7 +49,11 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
} else {
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
@ -62,7 +66,7 @@ switch ($action) {
|
||||
$log .= "PLAN NOT FOUND : $tur[username], $tur[namebp], $tur[type], $tur[routers]<br>";
|
||||
}
|
||||
}
|
||||
r2(U . 'plan/list', 's', $log);
|
||||
r2(getUrl('plan/list'), 's', $log);
|
||||
case 'recharge':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
@ -101,15 +105,35 @@ switch ($action) {
|
||||
$cust = User::_info($id_customer);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
|
||||
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
|
||||
if (!$cust) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < $total_cost) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -122,6 +146,9 @@ switch ($action) {
|
||||
if (count($usings) == 0) {
|
||||
$usings[] = Lang::T('Cash');
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
$ui->assign('usings', $usings);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
@ -133,7 +160,7 @@ switch ($action) {
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->display('recharge-confirm.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', $msg);
|
||||
r2(getUrl('plan/recharge'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -145,10 +172,12 @@ switch ($action) {
|
||||
$server = _post('server');
|
||||
$planId = _post('plan');
|
||||
$using = _post('using');
|
||||
$stoken = _post('stoken');
|
||||
$svoucher = _post('svoucher');
|
||||
|
||||
if (!empty(App::getTokenValue($stoken))) {
|
||||
$username = App::getTokenValue($stoken);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
|
||||
if (!empty(App::getVoucherValue($svoucher))) {
|
||||
$username = App::getVoucherValue($svoucher);
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $username)->order_by_desc('id')->find_one();
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
@ -165,16 +194,36 @@ switch ($action) {
|
||||
$channel = $admin['fullname'];
|
||||
$cust = User::_info($id_customer);
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
|
||||
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
//$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
if (!$cust) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < $total_cost) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -185,18 +234,18 @@ switch ($action) {
|
||||
}
|
||||
if (Package::rechargeUser($id_customer, $server, $planId, $gateway, $channel)) {
|
||||
if ($using == 'balance') {
|
||||
Balance::min($cust['id'], $plan['price'] + $add_cost);
|
||||
Balance::min($cust['id'], $total_cost);
|
||||
}
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $cust['username'])->order_by_desc('id')->find_one();
|
||||
Package::createInvoice($in);
|
||||
App::setToken($stoken, $cust['username']);
|
||||
App::setVoucher($svoucher, $cust['username']);
|
||||
$ui->display('invoice.tpl');
|
||||
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $cust['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', "Failed to recharge account");
|
||||
r2(getUrl('plan/recharge'), 'e', "Failed to recharge account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', $msg);
|
||||
r2(getUrl('plan/recharge'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -208,9 +257,9 @@ switch ($action) {
|
||||
$c = ORM::for_table('tbl_customers')->where('username', $in['username'])->find_one();
|
||||
if ($c) {
|
||||
Message::sendInvoice($c, $in);
|
||||
r2(U . 'plan/view/' . $id, 's', "Success send to customer");
|
||||
r2(getUrl('plan/view/') . $id, 's', "Success send to customer");
|
||||
}
|
||||
r2(U . 'plan/view/' . $id, 'd', "Customer not found");
|
||||
r2(getUrl('plan/view/') . $id, 'd', "Customer not found");
|
||||
}
|
||||
Package::createInvoice($in);
|
||||
$ui->assign('_title', 'View Invoice');
|
||||
@ -228,11 +277,13 @@ switch ($action) {
|
||||
$ui->assign('content', $content);
|
||||
} else {
|
||||
$id = _post('id');
|
||||
if (empty($id)) {
|
||||
$id = $routes['2'];
|
||||
}
|
||||
$d = ORM::for_table('tbl_transactions')->where('id', $id)->find_one();
|
||||
$ui->assign('in', $d);
|
||||
$ui->assign('date', Lang::dateAndTimeFormat($d['recharged_on'], $d['recharged_time']));
|
||||
}
|
||||
|
||||
run_hook('print_invoice'); #HOOK
|
||||
$ui->display('invoice-print.tpl');
|
||||
break;
|
||||
@ -263,7 +314,7 @@ switch ($action) {
|
||||
$ui->assign('_title', 'Edit Plan');
|
||||
$ui->display('plan-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('plan/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -288,7 +339,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
_log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer ' . $c['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -354,14 +405,14 @@ switch ($action) {
|
||||
}
|
||||
$d->save();
|
||||
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['namebp'] . '][' . Lang::moneyFormat($p['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('plan/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'plan/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('plan/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'voucher':
|
||||
$ui->assign('_title', Lang::T('Vouchers'));
|
||||
$ui->assign('_title', Lang::T('Voucher Cards'));
|
||||
$search = _req('search');
|
||||
$router = _req('router');
|
||||
$customer = _req('customer');
|
||||
@ -371,9 +422,10 @@ switch ($action) {
|
||||
$ui->assign('customer', $customer);
|
||||
$ui->assign('status', $status);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('_system_menu', 'cards');
|
||||
|
||||
$query = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'));
|
||||
->inner_join('tbl_voucher', ['tbl_plans.id', '=', 'tbl_voucher.id_plan']);
|
||||
|
||||
if (!empty($router)) {
|
||||
$query->where('tbl_voucher.routers', $router);
|
||||
@ -482,8 +534,8 @@ switch ($action) {
|
||||
}
|
||||
$time3months = strtotime('-3 months');
|
||||
$d = ORM::for_table('tbl_voucher')->where_equal('status', '1')
|
||||
->where_raw("UNIX_TIMESTAMP(used_date) < $time3months")
|
||||
->findMany();
|
||||
->where_raw("UNIX_TIMESTAMP(used_date) < $time3months")
|
||||
->findMany();
|
||||
if ($d) {
|
||||
$jml = 0;
|
||||
foreach ($d as $v) {
|
||||
@ -492,7 +544,7 @@ switch ($action) {
|
||||
$jml++;
|
||||
}
|
||||
}
|
||||
r2(U . 'plan/voucher', 's', "$jml " . Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/voucher'), 's', "$jml " . Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
case 'print-voucher':
|
||||
$from_id = _post('from_id');
|
||||
@ -500,6 +552,7 @@ switch ($action) {
|
||||
$pagebreak = _post('pagebreak');
|
||||
$limit = _post('limit');
|
||||
$vpl = _post('vpl');
|
||||
$selected_datetime = _post('selected_datetime');
|
||||
if (empty($vpl)) {
|
||||
$vpl = 3;
|
||||
}
|
||||
@ -542,6 +595,17 @@ switch ($action) {
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_gt('tbl_voucher.id', $from_id);
|
||||
} else if ($from_id > 0 && $planid == 0 && $selected_datetime != '') {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_raw("DATE(created_at) = ?", [$selected_datetime])
|
||||
->where_gt('tbl_voucher.id', $from_id)
|
||||
->limit($limit);
|
||||
$vc = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_gt('tbl_voucher.id', $from_id);
|
||||
} else {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
@ -551,6 +615,16 @@ switch ($action) {
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0');
|
||||
}
|
||||
if (!empty($selected_datetime)) {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where('tbl_voucher.created_at', $selected_datetime)
|
||||
->limit($limit);
|
||||
$vc = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0');
|
||||
}
|
||||
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
$v = $v->find_many();
|
||||
$vc = $vc->count();
|
||||
@ -577,6 +651,19 @@ switch ($action) {
|
||||
$ui->assign('limit', $limit);
|
||||
$ui->assign('planid', $planid);
|
||||
|
||||
$createdate = ORM::for_table('tbl_voucher')
|
||||
->select_expr(
|
||||
"CASE WHEN DATE(created_at) = CURDATE() THEN 'Today' ELSE DATE(created_at) END",
|
||||
'created_datetime'
|
||||
)
|
||||
->where_not_equal('created_at', '0')
|
||||
->select_expr('COUNT(*)', 'voucher_count')
|
||||
->group_by('created_datetime')
|
||||
->order_by_desc('created_datetime')
|
||||
->find_array();
|
||||
|
||||
$ui->assign('createdate', $createdate);
|
||||
|
||||
$voucher = [];
|
||||
$n = 1;
|
||||
foreach ($v as $vs) {
|
||||
@ -592,6 +679,7 @@ switch ($action) {
|
||||
|
||||
$ui->assign('voucher', $voucher);
|
||||
$ui->assign('vc', $vc);
|
||||
$ui->assign('selected_datetime', $selected_datetime);
|
||||
|
||||
//for counting pagebreak
|
||||
$ui->assign('jml', 0);
|
||||
@ -602,6 +690,7 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
$type = _post('type');
|
||||
$plan = _post('plan');
|
||||
$voucher_format = _post('voucher_format');
|
||||
@ -609,18 +698,22 @@ switch ($action) {
|
||||
$server = _post('server');
|
||||
$numbervoucher = _post('numbervoucher');
|
||||
$lengthcode = _post('lengthcode');
|
||||
$printNow = _post('print_now', 'no');
|
||||
$voucherPerPage = _post('voucher_per_page', '36');
|
||||
|
||||
$msg = '';
|
||||
if ($type == '' or $plan == '' or $server == '' or $numbervoucher == '' or $lengthcode == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
if (empty($type) || empty($plan) || empty($server) || empty($numbervoucher) || empty($lengthcode)) {
|
||||
$msg .= Lang::T('All fields are required') . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($numbervoucher) == false) {
|
||||
if (!Validator::UnsignedNumber($numbervoucher)) {
|
||||
$msg .= 'The Number of Vouchers must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($lengthcode) == false) {
|
||||
if (!Validator::UnsignedNumber($lengthcode)) {
|
||||
$msg .= 'The Length Code must be a number' . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
// Update or create voucher prefix
|
||||
if (!empty($prefix)) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'voucher_prefix')->find_one();
|
||||
if ($d) {
|
||||
@ -633,11 +726,14 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
run_hook('create_voucher'); #HOOK
|
||||
|
||||
run_hook('create_voucher'); // HOOK
|
||||
$vouchers = [];
|
||||
$newVoucherIds = [];
|
||||
|
||||
if ($voucher_format == 'numbers') {
|
||||
if (strlen($lengthcode) < 6) {
|
||||
$msg .= 'The Length Code must be a more than 6 for numbers' . '<br>';
|
||||
if ($lengthcode < 6) {
|
||||
$msg .= 'The Length Code must be more than 6 for numbers' . '<br>';
|
||||
}
|
||||
$vouchers = generateUniqueNumericVouchers($numbervoucher, $lengthcode);
|
||||
} else {
|
||||
@ -657,19 +753,91 @@ switch ($action) {
|
||||
$d->type = $type;
|
||||
$d->routers = $server;
|
||||
$d->id_plan = $plan;
|
||||
$d->code = $prefix . $code;
|
||||
$d->code = "$prefix$code";
|
||||
$d->user = '0';
|
||||
$d->status = '0';
|
||||
$d->generated_by = $admin['id'];
|
||||
$d->save();
|
||||
}
|
||||
if ($numbervoucher == 1) {
|
||||
r2(U . 'plan/voucher-view/' . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
|
||||
$newVoucherIds[] = $d->id();
|
||||
}
|
||||
|
||||
r2(U . 'plan/voucher', 's', Lang::T('Create Vouchers Successfully'));
|
||||
if ($printNow == 'yes' && count($newVoucherIds) > 0) {
|
||||
$template = file_get_contents("pages/Voucher.html");
|
||||
$template = str_replace('[[company_name]]', $config['CompanyName'], $template);
|
||||
|
||||
$vouchersToPrint = ORM::for_table('tbl_voucher')
|
||||
->left_outer_join('tbl_plans', ['tbl_plans.id', '=', 'tbl_voucher.id_plan'])
|
||||
->where_in('tbl_voucher.id', $newVoucherIds)
|
||||
->find_many();
|
||||
|
||||
$voucherHtmls = [];
|
||||
$n = 1;
|
||||
|
||||
foreach ($vouchersToPrint as $vs) {
|
||||
$temp = $template;
|
||||
$temp = str_replace('[[qrcode]]', '<img src="qrcode/?data=' . $vs['code'] . '">', $temp);
|
||||
$temp = str_replace('[[price]]', Lang::moneyFormat($vs['price']), $temp);
|
||||
$temp = str_replace('[[voucher_code]]', $vs['code'], $temp);
|
||||
$temp = str_replace('[[plan]]', $vs['name_plan'], $temp);
|
||||
$temp = str_replace('[[counter]]', $n, $temp);
|
||||
$voucherHtmls[] = $temp;
|
||||
$n++;
|
||||
}
|
||||
|
||||
$vc = count($voucherHtmls);
|
||||
$ui->assign('voucher', $voucherHtmls);
|
||||
$ui->assign('vc', $vc);
|
||||
$ui->assign('jml', 0);
|
||||
$ui->assign('from_id', 0);
|
||||
$ui->assign('vpl', '3');
|
||||
$ui->assign('pagebreak', $voucherPerPage);
|
||||
$ui->display('print-voucher.tpl');
|
||||
}
|
||||
|
||||
if ($numbervoucher == 1) {
|
||||
r2(getUrl('plan/voucher-view/') . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
|
||||
}
|
||||
|
||||
r2(getUrl('plan/voucher'), 's', Lang::T('Create Vouchers Successfully'));
|
||||
} else {
|
||||
r2(U . 'plan/add-voucher/' . $id, 'e', $msg);
|
||||
r2(getUrl('plan/add-voucher/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'voucher-delete-many':
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$admin = Admin::_info();
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$voucherIds = json_decode($_POST['voucherIds'], true);
|
||||
|
||||
if (is_array($voucherIds) && !empty($voucherIds)) {
|
||||
$voucherIds = array_map('intval', $voucherIds);
|
||||
|
||||
try {
|
||||
ORM::for_table('tbl_voucher')
|
||||
->where_in('id', $voucherIds)
|
||||
->delete_many();
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('Failed to delete vouchers.')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Return success response
|
||||
echo json_encode(['status' => 'success', 'message' => Lang::T("Vouchers Deleted Successfully.")]);
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid or missing voucher IDs.")]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid request method.")]);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -687,11 +855,11 @@ switch ($action) {
|
||||
$voucher = ORM::for_table('tbl_voucher')
|
||||
->find_one($id);
|
||||
if (!in_array($voucher['generated_by'], $sales)) {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
}
|
||||
if (!$voucher) {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($voucher['id_plan']);
|
||||
if ($voucher && $plan) {
|
||||
@ -725,7 +893,7 @@ switch ($action) {
|
||||
$ui->assign('whatsapp', urlencode("```$content```"));
|
||||
$ui->display('voucher-view.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'voucher-delete':
|
||||
@ -737,7 +905,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_voucher')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'plan/voucher', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/voucher'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -756,9 +924,9 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$code = _post('code');
|
||||
$code = Text::alphanumeric(_post('code'), "-_.,");
|
||||
$user = ORM::for_table('tbl_customers')->where('id', _post('id_customer'))->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->where('code', $code)->where('status', 0)->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$code'")->where('status', 0)->find_one();
|
||||
|
||||
run_hook('refill_customer'); #HOOK
|
||||
if ($v1) {
|
||||
@ -770,10 +938,10 @@ switch ($action) {
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "Failed to refill account");
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('plan/refill'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
break;
|
||||
case 'deposit':
|
||||
@ -795,39 +963,57 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$user = _post('id_customer');
|
||||
$amount = _post('amount');
|
||||
$plan = _post('id_plan');
|
||||
$stoken = _req('stoken');
|
||||
if (App::getTokenValue($stoken)) {
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $user)->find_one();
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
|
||||
$note = _post('note');
|
||||
$svoucher = _req('svoucher');
|
||||
$c = ORM::for_table('tbl_customers')->find_one($user);
|
||||
if (App::getVoucherValue($svoucher)) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one(App::getVoucherValue($svoucher));
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
run_hook('deposit_customer'); #HOOK
|
||||
if (!empty($user) && !empty($plan)) {
|
||||
if (Package::rechargeUser($user, 'balance', $plan, "Deposit", $admin['fullname'])) {
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $user)->find_one();
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
|
||||
if (!empty($user) && strlen($amount) > 0 && $amount != 0) {
|
||||
$plan = [];
|
||||
$plan['name_plan'] = Lang::T('Balance');
|
||||
$plan['price'] = $amount;
|
||||
$trxId = Package::rechargeBalance($c, $plan, "Deposit", $admin['fullname'], $note);
|
||||
if ($trxId > 0) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one($trxId);
|
||||
Package::createInvoice($in);
|
||||
if (!empty($stoken)) {
|
||||
App::setToken($stoken, $in['id']);
|
||||
if (!empty($svoucher)) {
|
||||
App::setVoucher($svoucher, $trxId);
|
||||
}
|
||||
$ui->display('invoice.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "Failed to refill account");
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else if (!empty($user) && !empty($plan)) {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($plan);
|
||||
$trxId = Package::rechargeBalance($c, $p, "Deposit", $admin['fullname'], $note);
|
||||
if ($trxId > 0) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one($trxId);
|
||||
Package::createInvoice($in);
|
||||
if (!empty($svoucher)) {
|
||||
App::setVoucher($svoucher, $trxId);
|
||||
}
|
||||
$ui->display('invoice.tpl');
|
||||
} else {
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "All field is required");
|
||||
r2(getUrl('plan/refill'), 'e', "All field is required");
|
||||
}
|
||||
break;
|
||||
case 'extend':
|
||||
$id = $routes[2];
|
||||
$days = $routes[3];
|
||||
$stoken = $_GET['stoken'];
|
||||
if (App::getTokenValue($stoken)) {
|
||||
r2(U . 'plan', 's', "Extend already done");
|
||||
$svoucher = $_GET['svoucher'];
|
||||
if (App::getVoucherValue($svoucher)) {
|
||||
r2(getUrl('plan'), 's', "Extend already done");
|
||||
}
|
||||
$tur = ORM::for_table('tbl_user_recharges')->find_one($id);
|
||||
$status = $tur['status'];
|
||||
@ -839,7 +1025,7 @@ switch ($action) {
|
||||
//expired
|
||||
$expiration = date('Y-m-d', strtotime(" +$days day"));
|
||||
}
|
||||
App::setToken($stoken, $id);
|
||||
App::setVoucher($svoucher, $id);
|
||||
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
|
||||
if ($c) {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($tur['plan_id']);
|
||||
@ -848,6 +1034,8 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
global $isChangePlan;
|
||||
$isChangePlan = true;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -857,23 +1045,23 @@ switch ($action) {
|
||||
$tur->status = "on";
|
||||
$tur->save();
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Plan not found");
|
||||
r2(getUrl('plan'), 's', "Plan not found");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Customer not found");
|
||||
r2(getUrl('plan'), 's', "Customer not found");
|
||||
}
|
||||
Message::sendTelegram("#u$tur[username] #extend #" . $p['type'] . " \n" . $p['name_plan'] .
|
||||
"\nLocation: " . $p['routers'] .
|
||||
"\nCustomer: " . $c['fullname'] .
|
||||
"\nNew Expired: " . Lang::dateAndTimeFormat($expiration, $tur['time']));
|
||||
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] for $days days", $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan', 's', "Extend until $expiration");
|
||||
r2(getUrl('plan'), 's', "Extend until $expiration");
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Customer is not expired yet");
|
||||
r2(getUrl('plan'), 's', "Customer is not expired yet");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/plan.js"></script>');
|
||||
$ui->assign('_title', Lang::T('Customer'));
|
||||
$search = _post('search');
|
||||
$status = _req('status');
|
||||
|
@ -7,5 +7,5 @@
|
||||
if(function_exists($routes[1])){
|
||||
call_user_func($routes[1]);
|
||||
}else{
|
||||
r2(U.'dashboard', 'e', 'Function not found');
|
||||
r2(getUrl('dashboard'), 'e', 'Function not found');
|
||||
}
|
@ -25,7 +25,7 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
|
||||
$json = json_decode($txt, true);
|
||||
if (empty($json['plugins']) && empty($json['payment_gateway'])) {
|
||||
unlink($cache);
|
||||
r2(U . 'pluginmanager');
|
||||
r2(getUrl('pluginmanager'));
|
||||
}
|
||||
} else {
|
||||
$data = Http::getData($plugin_repository);
|
||||
@ -35,23 +35,23 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
|
||||
switch ($action) {
|
||||
case 'refresh':
|
||||
if (file_exists($cache)) unlink($cache);
|
||||
r2(U . "pluginmanager", 's', 'Refresh success');
|
||||
r2(getUrl('pluginmanager'), 's', 'Refresh success');
|
||||
break;
|
||||
case 'dlinstall':
|
||||
if($_app_stage == 'demo'){
|
||||
r2(U . "pluginmanager", 'e', 'Demo Mode cannot install as it Security risk');
|
||||
if ($_app_stage == 'demo') {
|
||||
r2(getUrl('pluginmanager'), 'e', 'Demo Mode cannot install as it Security risk');
|
||||
}
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
|
||||
}
|
||||
if (!is_writeable($DEVICE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder devices/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder devices/ is not writable');
|
||||
}
|
||||
if (!is_writeable($UI_PATH . DIRECTORY_SEPARATOR . 'themes')) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder themes/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder themes/ is not writable');
|
||||
}
|
||||
$cache = $CACHE_PATH . DIRECTORY_SEPARATOR . 'installer' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($cache)) {
|
||||
@ -62,25 +62,47 @@ switch ($action) {
|
||||
$zip->open($_FILES['zip_plugin']['tmp_name']);
|
||||
$zip->extractTo($cache);
|
||||
$zip->close();
|
||||
$plugin = basename($_FILES['zip_plugin']['name']);
|
||||
unlink($_FILES['zip_plugin']['tmp_name']);
|
||||
$success = 0;
|
||||
//moving
|
||||
if (file_exists($cache . 'plugin')) {
|
||||
File::copyFolder($cache . 'plugin' . DIRECTORY_SEPARATOR, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($cache . 'paymentgateway')) {
|
||||
File::copyFolder($cache . 'paymentgateway' . DIRECTORY_SEPARATOR, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($cache . 'theme')) {
|
||||
File::copyFolder($cache . 'theme' . DIRECTORY_SEPARATOR, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($cache . 'device')) {
|
||||
File::copyFolder($cache . 'device' . DIRECTORY_SEPARATOR, $DEVICE_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if ($success == 0) {
|
||||
// old plugin and theme using this
|
||||
$check = strtolower($ghUrl);
|
||||
if (strpos($check, 'plugin') !== false) {
|
||||
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
|
||||
} else if (strpos($check, 'payment') !== false) {
|
||||
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
|
||||
} else if (strpos($check, 'theme') !== false) {
|
||||
rename($folder, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $plugin);
|
||||
} else if (strpos($check, 'device') !== false) {
|
||||
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
}
|
||||
//Cleaning
|
||||
File::deleteFolder($cache);
|
||||
r2(U . "pluginmanager", 's', 'Installation success');
|
||||
r2(getUrl('pluginmanager'), 's', 'Installation success');
|
||||
} else if (_post('gh_url', '') != '') {
|
||||
$ghUrl = _post('gh_url', '');
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
$ghUrl = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $ghUrl);
|
||||
}
|
||||
$plugin = basename($ghUrl);
|
||||
$file = $cache . $plugin . '.zip';
|
||||
$fp = fopen($file, 'w+');
|
||||
@ -99,30 +121,51 @@ switch ($action) {
|
||||
$zip->extractTo($cache);
|
||||
$zip->close();
|
||||
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-main' . DIRECTORY_SEPARATOR;
|
||||
if(!file_exists($folder)) {
|
||||
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-master' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
$success = 0;
|
||||
if (file_exists($folder . 'plugin')) {
|
||||
File::copyFolder($folder . 'plugin' . DIRECTORY_SEPARATOR, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($folder . 'paymentgateway')) {
|
||||
File::copyFolder($folder . 'paymentgateway' . DIRECTORY_SEPARATOR, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($folder . 'theme')) {
|
||||
File::copyFolder($folder . 'theme' . DIRECTORY_SEPARATOR, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if (file_exists($folder . 'device')) {
|
||||
File::copyFolder($folder . 'device' . DIRECTORY_SEPARATOR, $DEVICE_PATH . DIRECTORY_SEPARATOR);
|
||||
$success++;
|
||||
}
|
||||
if ($success == 0) {
|
||||
// old plugin and theme using this
|
||||
$check = strtolower($ghUrl);
|
||||
if (strpos($check, 'plugin') !== false) {
|
||||
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
|
||||
} else if (strpos($check, 'payment') !== false) {
|
||||
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
|
||||
} else if (strpos($check, 'theme') !== false) {
|
||||
rename($folder, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $plugin);
|
||||
} else if (strpos($check, 'device') !== false) {
|
||||
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
}
|
||||
File::deleteFolder($cache);
|
||||
r2(U . "pluginmanager", 's', 'Installation success');
|
||||
r2(getUrl('pluginmanager'), 's', 'Installation success');
|
||||
} else {
|
||||
r2(U . 'pluginmanager', 'e', 'Nothing Installed');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Nothing Installed');
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
|
||||
}
|
||||
set_time_limit(-1);
|
||||
$tipe = $routes['2'];
|
||||
@ -132,6 +175,9 @@ switch ($action) {
|
||||
if ($tipe == 'plugin') {
|
||||
foreach ($json['plugins'] as $plg) {
|
||||
if ($plg['id'] == $plugin) {
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
|
||||
}
|
||||
$fp = fopen($file, 'w+');
|
||||
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
@ -153,12 +199,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
scanAndRemovePath($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been deleted');
|
||||
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been deleted');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -167,10 +213,10 @@ switch ($action) {
|
||||
break;
|
||||
case 'install':
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
|
||||
}
|
||||
set_time_limit(-1);
|
||||
$tipe = $routes['2'];
|
||||
@ -180,6 +226,9 @@ switch ($action) {
|
||||
if ($tipe == 'plugin') {
|
||||
foreach ($json['plugins'] as $plg) {
|
||||
if ($plg['id'] == $plugin) {
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
|
||||
}
|
||||
$fp = fopen($file, 'w+');
|
||||
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
@ -201,12 +250,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been installed');
|
||||
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -214,6 +263,9 @@ switch ($action) {
|
||||
} else if ($tipe == 'payment') {
|
||||
foreach ($json['payment_gateway'] as $plg) {
|
||||
if ($plg['id'] == $plugin) {
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
|
||||
}
|
||||
$fp = fopen($file, 'w+');
|
||||
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
@ -235,12 +287,49 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "paymentgateway", 's', 'Payment Gateway ' . $plugin . ' has been installed');
|
||||
r2(getUrl('paymentgateway'), 's', 'Payment Gateway ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if ($tipe == 'device') {
|
||||
foreach ($json['devices'] as $d) {
|
||||
if ($d['id'] == $plugin) {
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
$d['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $d['github']);
|
||||
}
|
||||
$fp = fopen($file, 'w+');
|
||||
$ch = curl_init($d['github'] . '/archive/refs/heads/master.zip');
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_FILE, $fp);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
fclose($fp);
|
||||
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($file);
|
||||
$zip->extractTo($CACHE_PATH);
|
||||
$zip->close();
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-main/');
|
||||
if (!file_exists($folder)) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(getUrl('settings/devices'), 's', 'Device ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -255,6 +344,7 @@ switch ($action) {
|
||||
$ui->assign('zipExt', $zipExt);
|
||||
$ui->assign('plugins', $json['plugins']);
|
||||
$ui->assign('pgs', $json['payment_gateway']);
|
||||
$ui->assign('dvcs', $json['devices']);
|
||||
$ui->display('plugin-manager.tpl');
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . 'MikrotikPppoe' . '.php';
|
||||
|
||||
switch ($action) {
|
||||
case 'list':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pool.js"></script>');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/pool.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
@ -51,7 +51,7 @@ switch ($action) {
|
||||
run_hook('view_edit_pool'); #HOOK
|
||||
$ui->display('pool-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'pool/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('pool/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -65,7 +65,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -78,7 +78,7 @@ switch ($action) {
|
||||
$log .= 'DONE: ' . $pool['pool_name'] . ': ' . $pool['range_ip'] . '<br>';
|
||||
}
|
||||
}
|
||||
r2(U . 'pool/list', 's', $log);
|
||||
r2(getUrl('pool/list'), 's', $log);
|
||||
break;
|
||||
case 'add-post':
|
||||
$name = _post('name');
|
||||
@ -108,9 +108,9 @@ switch ($action) {
|
||||
(new MikrotikPppoe())->add_pool($b);
|
||||
}
|
||||
$b->save();
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'pool/add', 'e', $msg);
|
||||
r2(getUrl('pool/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -143,12 +143,136 @@ switch ($action) {
|
||||
(new MikrotikPppoe())->update_pool($old, $d);
|
||||
}
|
||||
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'pool/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('pool/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
|
||||
case 'port':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/pool.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
$query = ORM::for_table('tbl_port_pool')->where_like('pool_name', '%' . $name . '%')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query, ['name' => $name]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_port_pool')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_port'); #HOOK
|
||||
$ui->display('port.tpl');
|
||||
break;
|
||||
|
||||
case 'add-port':
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
run_hook('view_add_port'); #HOOK
|
||||
$ui->display('port-add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit-port':
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_port'); #HOOK
|
||||
$ui->display('port-edit.tpl');
|
||||
} else {
|
||||
r2(getUrl('pool/port'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete-port':
|
||||
$id = $routes['2'];
|
||||
run_hook('delete_port'); #HOOK
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'sync':
|
||||
$pools = ORM::for_table('tbl_port_pool')->find_many();
|
||||
$log = '';
|
||||
foreach ($pools as $pool) {
|
||||
if ($pool['routers'] != 'radius') {
|
||||
(new MikrotikPppoe())->update_pool($pool, $pool);
|
||||
$log .= 'DONE: ' . $pool['port_name'] . ': ' . $pool['range_port'] . '<br>';
|
||||
}
|
||||
}
|
||||
r2(getUrl('pool/list'), 's', $log);
|
||||
break;
|
||||
case 'add-port-post':
|
||||
$name = _post('name');
|
||||
$port_range = _post('port_range');
|
||||
$public_ip = _post('public_ip');
|
||||
$routers = _post('routers');
|
||||
run_hook('add_pool'); #HOOK
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 2) == false) {
|
||||
$msg .= 'Name should be between 3 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($port_range == '' or $routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_port_pool')->where('routers', $routers)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Routers already have ports, each router can only have 1 port range!') . '<br>';
|
||||
}
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_port_pool')->create();
|
||||
$b->public_ip = $public_ip;
|
||||
$b->port_name = $name;
|
||||
$b->range_port = $port_range;
|
||||
$b->routers = $routers;
|
||||
$b->save();
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(getUrl('pool/add-port'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'edit-port-post':
|
||||
$name = _post('name');
|
||||
$public_ip = _post('public_ip');
|
||||
$range_port = _post('range_port');
|
||||
$routers = _post('routers');
|
||||
run_hook('edit_port'); #HOOK
|
||||
$msg = '';
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 2) == false) {
|
||||
$msg .= 'Name should be between 3 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($range_port == '' or $routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
$id = _post('id');
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
$old = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if (!$d) {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
$d->port_name = $name;
|
||||
$d->public_ip = $public_ip;
|
||||
$d->range_port = $range_port;
|
||||
$d->routers = $routers;
|
||||
$d->save();
|
||||
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(getUrl('pool/edit-port/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'pool/list/', 's', '');
|
||||
r2(getUrl('pool/list/'), 's', '');
|
||||
}
|
||||
|
@ -58,12 +58,12 @@ switch ($action) {
|
||||
if ($msg == '') {
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
|
||||
if ((new Radius())->nasAdd($shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community) > 0) {
|
||||
r2(U . 'radius/nas-list/', 's', "NAS Added");
|
||||
r2(getUrl('radius/nas-list/'), 's', "NAS Added");
|
||||
} else {
|
||||
r2(U . 'radius/nas-add/', 'e', "NAS Added Failed");
|
||||
r2(getUrl('radius/nas-add/'), 'e', "NAS Added Failed");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', $msg);
|
||||
r2(getUrl('radius/nas-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'nas-edit':
|
||||
@ -80,7 +80,7 @@ switch ($action) {
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('radius-nas-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'radius/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('radius/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -115,12 +115,12 @@ switch ($action) {
|
||||
if ($msg == '') {
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
|
||||
if ((new Radius())->nasUpdate($id, $shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community)) {
|
||||
r2(U . 'radius/list/', 's', "NAS Saved");
|
||||
r2(getUrl('radius/list/'), 's', "NAS Saved");
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', 'NAS NOT Exists');
|
||||
r2(getUrl('radius/nas-add'), 'e', 'NAS NOT Exists');
|
||||
}
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', $msg);
|
||||
r2(getUrl('radius/nas-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'nas-delete':
|
||||
@ -129,7 +129,7 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
} else {
|
||||
r2(U . 'radius/nas-list', 'e', 'NAS Not found');
|
||||
r2(getUrl('radius/nas-list'), 'e', 'NAS Not found');
|
||||
}
|
||||
default:
|
||||
$ui->assign('_system_menu', 'radius');
|
||||
|
@ -5,6 +5,9 @@
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
if ($_c['disable_registration'] == 'noreg') {
|
||||
_alert(Lang::T('Registration Disabled'), 'danger', "login");
|
||||
}
|
||||
if (isset($routes['1'])) {
|
||||
$do = $routes['1'];
|
||||
} else {
|
||||
@ -22,36 +25,39 @@ switch ($do) {
|
||||
$password = _post('password');
|
||||
$cpassword = _post('cpassword');
|
||||
$address = _post('address');
|
||||
if (!empty($config['sms_url'])) {
|
||||
$phonenumber = Lang::phoneFormat($username);
|
||||
$username = $phonenumber;
|
||||
} else if (strlen($username) < 21) {
|
||||
$phonenumber = $username;
|
||||
}
|
||||
|
||||
// Separate phone number input if OTP is required
|
||||
$phone_number = ($config['sms_otp_registration'] == 'yes') ? alphanumeric(_post('phone_number'), "+_.@-") : $username;
|
||||
|
||||
$msg = '';
|
||||
if (Validator::Length($username, 35, 2) == false) {
|
||||
$msg .= 'Username should be between 3 to 55 characters' . '<br>';
|
||||
$msg .= "Username should be between 3 to 55 characters<br>";
|
||||
}
|
||||
if (Validator::Length($fullname, 36, 2) == false) {
|
||||
$msg .= 'Full Name should be between 3 to 25 characters' . '<br>';
|
||||
if ($config['man_fields_fname'] == 'yes') {
|
||||
if (Validator::Length($fullname, 36, 2) == false) {
|
||||
$msg .= "Full Name should be between 3 to 25 characters<br>";
|
||||
}
|
||||
}
|
||||
if (!Validator::Length($password, 35, 2)) {
|
||||
$msg .= 'Password should be between 3 to 35 characters' . '<br>';
|
||||
$msg .= "Password should be between 3 to 35 characters<br>";
|
||||
}
|
||||
if (!Validator::Email($email)) {
|
||||
$msg .= 'Email is not Valid<br>';
|
||||
if ($config['man_fields_email'] == 'yes') {
|
||||
if (!Validator::Email($email)) {
|
||||
$msg .= 'Email is not Valid<br>';
|
||||
}
|
||||
}
|
||||
if ($password != $cpassword) {
|
||||
$msg .= Lang::T('Passwords does not match') . '<br>';
|
||||
}
|
||||
|
||||
if (!empty($config['sms_url'])) {
|
||||
$otpPath .= sha1($username . $db_password) . ".txt";
|
||||
// OTP verification if OTP is enabled
|
||||
if ($_c['sms_otp_registration'] == 'yes') {
|
||||
$otpPath .= sha1("$phone_number$db_pass") . ".txt";
|
||||
run_hook('validate_otp'); #HOOK
|
||||
//expired 10 minutes
|
||||
// Expire after 10 minutes
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) > 1200) {
|
||||
unlink($otpPath);
|
||||
r2(U . 'register', 's', 'Verification code expired');
|
||||
r2(getUrl('register'), 's', 'Verification code expired');
|
||||
} else if (file_exists($otpPath)) {
|
||||
$code = file_get_contents($otpPath);
|
||||
if ($code != $otp_code) {
|
||||
@ -59,97 +65,146 @@ switch ($do) {
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Wrong Verification code');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
exit();
|
||||
} else {
|
||||
unlink($otpPath);
|
||||
}
|
||||
} else {
|
||||
r2(U . 'register', 's', 'No Verification code');
|
||||
r2(getUrl('register'), 's', 'No Verification code');
|
||||
}
|
||||
}
|
||||
|
||||
// Check if username already exists
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Account already axist') . '<br>';
|
||||
$msg .= Lang::T('Account already exists') . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
run_hook('register_user'); #HOOK
|
||||
$d = ORM::for_table('tbl_customers')->create();
|
||||
$d->username = alphanumeric($username, "+_.@-");
|
||||
$d->password = $password;
|
||||
$d->fullname = $fullname;
|
||||
$d->address = $address;
|
||||
$d->email = $email;
|
||||
$d->phonenumber = $phonenumber;
|
||||
$d->phonenumber = $phone_number;
|
||||
if ($d->save()) {
|
||||
$user = $d->id();
|
||||
r2(U . 'login', 's', Lang::T('Register Success! You can login now'));
|
||||
if ($config['photo_register'] == 'yes' && !empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
$d->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
User::setFormCustomField($user);
|
||||
run_hook('register_user'); #HOOK
|
||||
$msg .= Lang::T('Registration successful') . '<br>';
|
||||
if ($config['reg_nofify_admin'] == 'yes') {
|
||||
sendTelegram($config['CompanyName'] . ' - ' . Lang::T('New User Registration') . "\n\nFull Name: " . $fullname . "\nUsername: " . $username . "\nEmail: " . $email . "\nPhone Number: " . $phone_number . "\nAddress: " . $address);
|
||||
}
|
||||
r2(getUrl('login'), 's', Lang::T('Register Success! You can login now'));
|
||||
} else {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Failed to register');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_otp_register'); #HOOK
|
||||
$ui->display('register-rotp.tpl');
|
||||
$ui->display('customer/register-rotp.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', $msg);
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('register.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
// Check if OTP is enabled
|
||||
if (!empty($config['sms_url']) && $_c['sms_otp_registration'] == 'yes') {
|
||||
// Display register-otp.tpl if OTP is enabled
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
} else {
|
||||
// Display register.tpl if OTP is not enabled
|
||||
$ui->display('customer/register.tpl');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!empty($config['sms_url'])) {
|
||||
$username = _post('username');
|
||||
if (!empty($username)) {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($_c['sms_otp_registration'] == 'yes') {
|
||||
$phone_number = _post('phone_number');
|
||||
if (!empty($phone_number)) {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $phone_number)->find_one();
|
||||
if ($d) {
|
||||
r2(U . 'register', 's', Lang::T('Account already axist'));
|
||||
r2(getUrl('register'), 's', Lang::T('Account already exists'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
touch($otpPath . 'index.html');
|
||||
}
|
||||
$otpPath .= sha1($username . $db_password) . ".txt";
|
||||
//expired 10 minutes
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) < 1200) {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('notify', 'Please wait ' . (1200 - (time() - filemtime($otpPath))) . ' seconds before sending another SMS');
|
||||
$otpPath .= sha1($phone_number . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) < 600) {
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Please wait ' . (600 - (time() - filemtime($otpPath))) . ' seconds before sending another SMS');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpPath, $otp);
|
||||
Message::sendSMS($username, $config['CompanyName'] . "\nYour Verification code are: $otp");
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('notify', 'Verification code has been sent to your phone');
|
||||
if ($config['phone_otp_type'] == 'whatsapp') {
|
||||
Message::sendWhatsapp($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
} else if ($config['phone_otp_type'] == 'both') {
|
||||
Message::sendWhatsapp($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
Message::sendSMS($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
} else {
|
||||
Message::sendSMS($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
}
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Registration code has been sent to your phone');
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->display('register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, true));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_otp_register'); #HOOK
|
||||
$ui->display('register-rotp.tpl');
|
||||
$ui->display('customer/register-rotp.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, true));
|
||||
$ui->assign('username', "");
|
||||
$ui->assign('fullname', "");
|
||||
$ui->assign('address', "");
|
||||
$ui->assign('email', "");
|
||||
$ui->assign('otp', false);
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_register'); #HOOK
|
||||
$ui->display('register.tpl');
|
||||
$ui->display('customer/register.tpl');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -21,13 +21,243 @@ $before_30_days = date('Y-m-d', strtotime('today - 30 days'));
|
||||
$month_n = date('n');
|
||||
|
||||
switch ($action) {
|
||||
case 'ajax':
|
||||
$data = $routes['2'];
|
||||
$reset_day = $config['reset_day'];
|
||||
if (empty($reset_day)) {
|
||||
$reset_day = 1;
|
||||
}
|
||||
//first day of month
|
||||
if (date("d") >= $reset_day) {
|
||||
$start_date = date('Y-m-' . $reset_day);
|
||||
} else {
|
||||
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
||||
}
|
||||
$sd = _req('sd', $start_date);
|
||||
$ed = _req('ed', $mdate);
|
||||
$ts = _req('ts', '00:00:00');
|
||||
$te = _req('te', '23:59:59');
|
||||
$types = ORM::for_table('tbl_transactions')->getEnum('type');
|
||||
$tps = ($_GET['tps']) ? $_GET['tps'] : $types;
|
||||
$plans = array_column(ORM::for_table('tbl_transactions')->select('plan_name')->distinct('plan_name')->find_array(), 'plan_name');
|
||||
$plns = ($_GET['plns']) ? $_GET['plns'] : $plans;
|
||||
$methods = array_column(ORM::for_table('tbl_transactions')->rawQuery("SELECT DISTINCT SUBSTRING_INDEX(`method`, ' - ', 1) as method FROM tbl_transactions;")->findArray(), 'method');
|
||||
$mts = ($_GET['mts']) ? $_GET['mts'] : $methods;
|
||||
$routers = array_column(ORM::for_table('tbl_transactions')->select('routers')->distinct('routers')->find_array(), 'routers');
|
||||
$rts = ($_GET['rts']) ? $_GET['rts'] : $routers;
|
||||
$result = [];
|
||||
switch ($data) {
|
||||
case 'type':
|
||||
foreach ($tps as $tp) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->where('type', $tp);
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
$query->where_in('routers', $rts);
|
||||
}
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) {
|
||||
$result['datas'][] = $count;
|
||||
$result['labels'][] = "$tp ($count)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'plan':
|
||||
foreach ($plns as $pln) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->where('plan_name', $pln);
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
$query->where_in('routers', $rts);
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) {
|
||||
$result['datas'][] = $count;
|
||||
$result['labels'][] = "$pln ($count)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'method':
|
||||
foreach ($mts as $mt) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->where_like('method', "$mt - %");
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
$query->where_in('routers', $rts);
|
||||
}
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
}
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) {
|
||||
$result['datas'][] = $count;
|
||||
$result['labels'][] = "$mt ($count)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'router':
|
||||
foreach ($rts as $rt) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->where('routers', $rt);
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) {
|
||||
$result['datas'][] = $count;
|
||||
$result['labels'][] = "$rt ($count)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'line':
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->order_by_desc('id');
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
$query->where_in('routers', $rts);
|
||||
}
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
$datas = $query->find_array();
|
||||
$period = new DatePeriod(
|
||||
new DateTime($sd),
|
||||
new DateInterval('P1D'),
|
||||
new DateTime($ed)
|
||||
);
|
||||
$pos = 0;
|
||||
$dates = [];
|
||||
foreach ($period as $key => $value) {
|
||||
$dates[] = $value->format('Y-m-d');
|
||||
}
|
||||
$dates = array_reverse($dates);
|
||||
$result = [];
|
||||
$temp;
|
||||
foreach ($dates as $date) {
|
||||
$result['labels'][] = $date;
|
||||
// type
|
||||
foreach ($tps as $key) {
|
||||
if (!isset($temp[$key][$date])) {
|
||||
$temp[$key][$date] = 0;
|
||||
}
|
||||
foreach ($datas as $data) {
|
||||
if ($data['recharged_on'] == date('Y-m-d', strtotime($date)) && $data['type'] == $key) {
|
||||
$temp[$key][$date] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//plan
|
||||
foreach ($plns as $key) {
|
||||
if (!isset($temp[$key][$date])) {
|
||||
$temp[$key][$date] = 0;
|
||||
}
|
||||
foreach ($datas as $data) {
|
||||
if ($data['recharged_on'] == date('Y-m-d', strtotime($date)) && $data['plan_name'] == $key) {
|
||||
$temp[$key][$date] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//method
|
||||
foreach ($mts as $key) {
|
||||
if (!isset($temp[$key][$date])) {
|
||||
$temp[$key][$date] = 0;
|
||||
}
|
||||
foreach ($datas as $data) {
|
||||
if ($data['recharged_on'] == date('Y-m-d', strtotime($date)) && strpos($data['method'], $key) !== false) {
|
||||
$temp[$key][$date] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rts as $key) {
|
||||
if (!isset($temp[$key][$date])) {
|
||||
$temp[$key][$date] = 0;
|
||||
}
|
||||
foreach ($datas as $data) {
|
||||
if ($data['recharged_on'] == date('Y-m-d', strtotime($date)) && $data['routers'] == $key) {
|
||||
$temp[$key][$date] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
$pos++;
|
||||
if ($pos > 29) {
|
||||
// only 30days
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($temp as $key => $value) {
|
||||
$array = ['label' => $key];
|
||||
$total = 0;
|
||||
foreach ($value as $k => $v) {
|
||||
$total += $v;
|
||||
$array['data'][] = $v;
|
||||
}
|
||||
if($total>0){
|
||||
$result['datas'][] = $array;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$result = ['labels' => [], 'datas' => []];
|
||||
}
|
||||
echo json_encode($result);
|
||||
die();
|
||||
case 'by-date':
|
||||
case 'activation':
|
||||
$q = (_post('q') ? _post('q') : _get('q'));
|
||||
$keep = _post('keep');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM tbl_transactions WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
|
||||
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
|
||||
r2(getUrl('logs/list/'), 's', "Delete logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('tbl_transactions')->where_like('invoice', '%' . $q . '%')->order_by_desc('id');
|
||||
@ -107,7 +337,7 @@ switch ($action) {
|
||||
$ed = _req('ed', $mdate);
|
||||
$ts = _req('ts', '00:00:00');
|
||||
$te = _req('te', '23:59:59');
|
||||
$urlquery = str_replace('_route=reports&', '', $_SERVER['QUERY_STRING']);
|
||||
$urlquery = str_replace('_route=reports', '', $_SERVER['QUERY_STRING']);
|
||||
|
||||
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
@ -154,6 +384,6 @@ switch ($action) {
|
||||
$ui->assign('dr', $dr);
|
||||
$ui->assign('mdate', $mdate);
|
||||
run_hook('view_daily_reports'); #HOOK
|
||||
$ui->display('reports-daily.tpl');
|
||||
$ui->display('reports.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -18,24 +18,26 @@ if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
$leafletpickerHeader = <<<EOT
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">
|
||||
EOT;
|
||||
|
||||
switch ($action) {
|
||||
case 'list':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/routers.js"></script>');
|
||||
|
||||
case 'maps':
|
||||
$name = _post('name');
|
||||
$query = ORM::for_table('tbl_routers')->where_not_equal('coordinates', '')->order_by_desc('id');
|
||||
$query->selects(['id', 'name', 'coordinates', 'description', 'coverage', 'enabled']);
|
||||
if ($name != '') {
|
||||
$query = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query, ['name' => $name]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_routers')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
$query->where_like('name', '%' . $name . '%');
|
||||
}
|
||||
|
||||
$d = Paginator::findMany($query, ['name' => $name], '20', '', true);
|
||||
$ui->assign('name', $name);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_routers'); #HOOK
|
||||
$ui->display('routers.tpl');
|
||||
$ui->assign('_title', Lang::T('Routers Geo Location Information'));
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
|
||||
$ui->display('routers-maps.tpl');
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
run_hook('view_add_routers'); #HOOK
|
||||
$ui->display('routers-add.tpl');
|
||||
@ -47,12 +49,13 @@ switch ($action) {
|
||||
if (!$d) {
|
||||
$d = ORM::for_table('tbl_routers')->where_equal('name', _get('name'))->find_one();
|
||||
}
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_router_edit'); #HOOK
|
||||
$ui->display('routers-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'routers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('routers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -62,7 +65,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_routers')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'routers/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('routers/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -75,16 +78,18 @@ switch ($action) {
|
||||
$enabled = _post('enabled');
|
||||
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 4) == false) {
|
||||
$msg .= 'Name should be between 5 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($ip_address == '' or $username == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
if (Validator::Length($name, 30, 1) == false) {
|
||||
$msg .= 'Name should be between 1 to 30 characters' . '<br>';
|
||||
}
|
||||
if($enabled || _post("testIt")){
|
||||
if ($ip_address == '' or $username == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_routers')->where('ip_address', $ip_address)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('IP Router Already Exist') . '<br>';
|
||||
$d = ORM::for_table('tbl_routers')->where('ip_address', $ip_address)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('IP Router Already Exist') . '<br>';
|
||||
}
|
||||
}
|
||||
if (strtolower($name) == 'radius') {
|
||||
$msg .= '<b>Radius</b> name is reserved<br>';
|
||||
@ -92,7 +97,7 @@ switch ($action) {
|
||||
|
||||
if ($msg == '') {
|
||||
run_hook('add_router'); #HOOK
|
||||
if(_post("testIt")){
|
||||
if (_post("testIt")) {
|
||||
(new MikrotikHotspot())->getClient($ip_address, $username, $password);
|
||||
}
|
||||
$d = ORM::for_table('tbl_routers')->create();
|
||||
@ -104,9 +109,9 @@ switch ($action) {
|
||||
$d->enabled = $enabled;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'routers/list', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('routers/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'routers/add', 'e', $msg);
|
||||
r2(getUrl('routers/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -117,13 +122,17 @@ switch ($action) {
|
||||
$username = _post('username');
|
||||
$password = _post('password');
|
||||
$description = _post('description');
|
||||
$coordinates = _post('coordinates');
|
||||
$coverage = _post('coverage');
|
||||
$enabled = $_POST['enabled'];
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 4) == false) {
|
||||
$msg .= 'Name should be between 5 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($ip_address == '' or $username == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
if($enabled || _post("testIt")){
|
||||
if ($ip_address == '' or $username == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$id = _post('id');
|
||||
@ -141,10 +150,12 @@ switch ($action) {
|
||||
}
|
||||
$oldname = $d['name'];
|
||||
|
||||
if ($d['ip_address'] != $ip_address) {
|
||||
$c = ORM::for_table('tbl_routers')->where('ip_address', $ip_address)->where_not_equal('id', $id)->find_one();
|
||||
if ($c) {
|
||||
$msg .= 'IP Already Exists<br>';
|
||||
if($enabled || _post("testIt")){
|
||||
if ($d['ip_address'] != $ip_address) {
|
||||
$c = ORM::for_table('tbl_routers')->where('ip_address', $ip_address)->where_not_equal('id', $id)->find_one();
|
||||
if ($c) {
|
||||
$msg .= 'IP Already Exists<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +165,7 @@ switch ($action) {
|
||||
|
||||
if ($msg == '') {
|
||||
run_hook('router_edit'); #HOOK
|
||||
if(_post("testIt")){
|
||||
if (_post("testIt")) {
|
||||
(new MikrotikHotspot())->getClient($ip_address, $username, $password);
|
||||
}
|
||||
$d->name = $name;
|
||||
@ -162,6 +173,8 @@ switch ($action) {
|
||||
$d->username = $username;
|
||||
$d->password = $password;
|
||||
$d->description = $description;
|
||||
$d->coordinates = $coordinates;
|
||||
$d->coverage = $coverage;
|
||||
$d->enabled = $enabled;
|
||||
$d->save();
|
||||
if ($name != $oldname) {
|
||||
@ -184,12 +197,24 @@ switch ($action) {
|
||||
$p->set('routers', $name);
|
||||
$p->save();
|
||||
}
|
||||
r2(U . 'routers/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('routers/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'routers/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('routers/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'routers/list/', 's', '');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/routers.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
$name = _post('name');
|
||||
$query = ORM::for_table('tbl_routers')->order_by_desc('id');
|
||||
if ($name != '') {
|
||||
$query->where_like('name', '%' . $name . '%');
|
||||
}
|
||||
$d = Paginator::findMany($query, ['name' => $name]);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_routers'); #HOOK
|
||||
$ui->display('routers.tpl');
|
||||
break;
|
||||
}
|
||||
|
21
system/controllers/search_user.php
Normal file
21
system/controllers/search_user.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
$query = isset($_GET['query']) ? trim($_GET['query']) : '';
|
||||
|
||||
if (!empty($query)) {
|
||||
$results = ORM::for_table('tbl_customers')
|
||||
->where_like('username', "%$query%")
|
||||
->find_many();
|
||||
|
||||
if ($results) {
|
||||
echo '<ul>';
|
||||
foreach ($results as $user) {
|
||||
echo '<li><a href="'.$_url.'?_route=customers/view/'.$user->id.'">' . htmlspecialchars($user->username, ENT_QUOTES, 'UTF-8') . '</a></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
} else {
|
||||
echo '<p>' . Lang::T('No users found.') . '</p>';
|
||||
}
|
||||
} else {
|
||||
echo '<p>' . Lang::T('Please enter a search term.') . '</p>';
|
||||
}
|
@ -33,7 +33,7 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'services/hotspot', 's', $log);
|
||||
r2(getUrl('services/hotspot'), 's', $log);
|
||||
} else if ($routes['2'] == 'pppoe') {
|
||||
$plans = ORM::for_table('tbl_plans')->where('type', 'PPPOE')->find_many();
|
||||
$log = '';
|
||||
@ -49,11 +49,11 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', $log);
|
||||
r2(getUrl('services/pppoe'), 's', $log);
|
||||
}
|
||||
r2(U . 'services/hotspot', 'w', 'Unknown command');
|
||||
r2(getUrl('services/hotspot'), 'w', 'Unknown command');
|
||||
case 'hotspot':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/hotspot.js"></script>');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/hotspot.js"></script>');
|
||||
$name = _req('name');
|
||||
$type1 = _req('type1');
|
||||
$type2 = _req('type2');
|
||||
@ -83,9 +83,9 @@ switch ($action) {
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'Hotspot')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if(count($ids)){
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
}else{
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
@ -193,7 +193,7 @@ switch ($action) {
|
||||
run_hook('view_edit_plan'); #HOOK
|
||||
$ui->display('hotspot-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('services/hotspot'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -214,7 +214,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'services/hotspot', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/hotspot'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -307,9 +307,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/edit/' . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/add', 'e', $msg);
|
||||
r2(getUrl('services/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -321,6 +321,7 @@ switch ($action) {
|
||||
$id_bw = _post('id_bw');
|
||||
$typebp = _post('typebp');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$limit_type = _post('limit_type');
|
||||
$time_limit = _post('time_limit');
|
||||
$time_unit = _post('time_unit');
|
||||
@ -353,6 +354,11 @@ switch ($action) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
run_hook('edit_plan'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
@ -378,6 +384,7 @@ switch ($action) {
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price; // Set price with or without tax based on configuration
|
||||
$d->price_old = $price_old;
|
||||
$d->typebp = $typebp;
|
||||
$d->limit_type = $limit_type;
|
||||
$d->time_limit = $time_limit;
|
||||
@ -413,15 +420,15 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/hotspot', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/hotspot'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pppoe':
|
||||
$ui->assign('_title', Lang::T('PPPOE Plans'));
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pppoe.js"></script>');
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/pppoe.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
$name = _req('name');
|
||||
@ -453,9 +460,9 @@ switch ($action) {
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'PPPOE')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if(count($ids)){
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
}else{
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
@ -573,7 +580,7 @@ switch ($action) {
|
||||
run_hook('view_edit_ppoe'); #HOOK
|
||||
$ui->display('pppoe-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('services/pppoe'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -595,7 +602,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -693,9 +700,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/pppoe-add', 'e', $msg);
|
||||
r2(getUrl('services/pppoe-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -705,6 +712,7 @@ switch ($action) {
|
||||
$name = _post('name_plan');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
@ -728,6 +736,10 @@ switch ($action) {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
$old = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
if ($d) {
|
||||
@ -758,6 +770,7 @@ switch ($action) {
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->price_old = $price_old;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
@ -788,9 +801,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/pppoe-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/pppoe-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'balance':
|
||||
@ -828,13 +841,14 @@ switch ($action) {
|
||||
if ($d) {
|
||||
run_hook('delete_balance'); #HOOK
|
||||
$d->delete();
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
case 'balance-edit-post':
|
||||
$id = _post('id');
|
||||
$name = _post('name');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
|
||||
@ -851,17 +865,21 @@ switch ($action) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
run_hook('edit_ppoe'); #HOOK
|
||||
if ($msg == '') {
|
||||
$d->name_plan = $name;
|
||||
$d->price = $price;
|
||||
$d->enabled = $enabled;
|
||||
$d->price_old = $price_old;
|
||||
$d->prepaid = 'yes';
|
||||
$d->save();
|
||||
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/balance-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/balance-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'balance-add-post':
|
||||
@ -896,9 +914,389 @@ switch ($action) {
|
||||
$d->prepaid = 'yes';
|
||||
$d->save();
|
||||
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/balance-add', 'e', $msg);
|
||||
r2(getUrl('services/balance-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'vpn':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="'.APP_URL.'/ui/lib/c/pppoe.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
$name = _req('name');
|
||||
$type1 = _req('type1');
|
||||
$type2 = _req('type2');
|
||||
$type3 = _req('type3');
|
||||
$bandwidth = _req('bandwidth');
|
||||
$valid = _req('valid');
|
||||
$device = _req('device');
|
||||
$status = _req('status');
|
||||
$router = _req('router');
|
||||
$ui->assign('type1', $type1);
|
||||
$ui->assign('type2', $type2);
|
||||
$ui->assign('type3', $type3);
|
||||
$ui->assign('bandwidth', $bandwidth);
|
||||
$ui->assign('valid', $valid);
|
||||
$ui->assign('device', $device);
|
||||
$ui->assign('status', $status);
|
||||
$ui->assign('router', $router);
|
||||
|
||||
$append_url = "&type1=" . urlencode($type1)
|
||||
. "&type2=" . urlencode($type2)
|
||||
. "&type3=" . urlencode($type3)
|
||||
. "&bandwidth=" . urlencode($bandwidth)
|
||||
. "&valid=" . urlencode($valid)
|
||||
. "&device=" . urlencode($device)
|
||||
. "&status=" . urlencode($status)
|
||||
. "&router=" . urlencode($router);
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'VPN')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
$ui->assign('type3s', ORM::for_table('tbl_plans')->getEnum("typebp"));
|
||||
$ui->assign('valids', ORM::for_table('tbl_plans')->getEnum("validity_unit"));
|
||||
$ui->assign('routers', array_column(ORM::for_table('tbl_plans')->distinct()->select("routers")->whereNotEqual('routers', '')->findArray(), 'routers'));
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
$query = ORM::for_table('tbl_bandwidth')
|
||||
->left_outer_join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))
|
||||
->where('tbl_plans.type', 'VPN');
|
||||
if (!empty($type1)) {
|
||||
$query->where('tbl_plans.prepaid', $type1);
|
||||
}
|
||||
if (!empty($type2)) {
|
||||
$query->where('tbl_plans.plan_type', $type2);
|
||||
}
|
||||
if (!empty($type3)) {
|
||||
$query->where('tbl_plans.typebp', $type3);
|
||||
}
|
||||
if (!empty($bandwidth)) {
|
||||
$query->where('tbl_plans.id_bw', $bandwidth);
|
||||
}
|
||||
if (!empty($valid)) {
|
||||
$query->where('tbl_plans.validity_unit', $valid);
|
||||
}
|
||||
if (!empty($router)) {
|
||||
if ($router == 'radius') {
|
||||
$query->where('tbl_plans.is_radius', '1');
|
||||
} else {
|
||||
$query->where('tbl_plans.routers', $router);
|
||||
}
|
||||
}
|
||||
if (!empty($device)) {
|
||||
$query->where('tbl_plans.device', $device);
|
||||
}
|
||||
if (in_array($status, ['0', '1'])) {
|
||||
$query->where('tbl_plans.enabled', $status);
|
||||
}
|
||||
if ($name != '') {
|
||||
$query->where_like('tbl_plans.name_plan', '%' . $name . '%');
|
||||
}
|
||||
$d = Paginator::findMany($query, ['name' => $name], 20, $append_url);
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_vpn'); #HOOK
|
||||
$ui->display('vpn.tpl');
|
||||
break;
|
||||
|
||||
case 'vpn-add':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
$d = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
$ui->assign('d', $d);
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
run_hook('view_add_vpn'); #HOOK
|
||||
$ui->display('vpn-add.tpl');
|
||||
break;
|
||||
|
||||
case 'vpn-edit':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_plans')->find_one($id);
|
||||
if ($d) {
|
||||
if (empty($d['device'])) {
|
||||
if ($d['is_radius']) {
|
||||
$d->device = 'Radius';
|
||||
} else {
|
||||
$d->device = 'MikrotikVpn';
|
||||
}
|
||||
$d->save();
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$p = ORM::for_table('tbl_pool')->where('routers', ($d['is_radius']) ? 'radius' : $d['routers'])->find_many();
|
||||
$ui->assign('p', $p);
|
||||
$b = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
$ui->assign('b', $b);
|
||||
$r = [];
|
||||
if ($d['is_radius']) {
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
}
|
||||
$ui->assign('r', $r);
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
//select expired plan
|
||||
if ($d['is_radius']) {
|
||||
$exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("is_radius", 1)->findArray();
|
||||
} else {
|
||||
$exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("routers", $d['routers'])->findArray();
|
||||
}
|
||||
$ui->assign('exps', $exps);
|
||||
run_hook('view_edit_vpn'); #HOOK
|
||||
$ui->display('vpn-edit.tpl');
|
||||
} else {
|
||||
r2(getUrl('services/vpn'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'vpn-delete':
|
||||
$id = $routes['2'];
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->find_one($id);
|
||||
if ($d) {
|
||||
run_hook('delete_vpn'); #HOOK
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->remove_plan($d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'vpn-add-post':
|
||||
$name = _post('name_plan');
|
||||
$plan_type = _post('plan_type');
|
||||
$radius = _post('radius');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
$device = _post('device');
|
||||
$pool = _post('pool_name');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
$expired_date = _post('expired_date');
|
||||
|
||||
|
||||
$msg = '';
|
||||
if (Validator::UnsignedNumber($validity) == false) {
|
||||
$msg .= 'The validity must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($price) == false) {
|
||||
$msg .= 'The price must be a number' . '<br>';
|
||||
}
|
||||
if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
if (empty($radius)) {
|
||||
if ($routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('name_plan', $name)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Name Plan Already Exist') . '<br>';
|
||||
}
|
||||
run_hook('add_vpn'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
if ($b['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
$raddown = '000';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
$raddown = '000000';
|
||||
}
|
||||
if ($b['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
$radup = '000';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
$radup = '000000';
|
||||
}
|
||||
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
|
||||
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
|
||||
$rate = trim($rate . " " . $b['burst']);
|
||||
$d = ORM::for_table('tbl_plans')->create();
|
||||
$d->type = 'VPN';
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
$d->pool = $pool;
|
||||
if (!empty($radius)) {
|
||||
$d->is_radius = 1;
|
||||
$d->routers = '';
|
||||
} else {
|
||||
$d->is_radius = 0;
|
||||
$d->routers = $routers;
|
||||
}
|
||||
if ($prepaid == 'no') {
|
||||
if ($expired_date > 28 && $expired_date < 1) {
|
||||
$expired_date = 20;
|
||||
}
|
||||
$d->expired_date = $expired_date;
|
||||
} else {
|
||||
$d->expired_date = 0;
|
||||
}
|
||||
$d->enabled = $enabled;
|
||||
$d->prepaid = $prepaid;
|
||||
$d->device = $device;
|
||||
$d->save();
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->add_plan($d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(getUrl('services/vpn-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit-vpn-post':
|
||||
$id = _post('id');
|
||||
$plan_type = _post('plan_type');
|
||||
$name = _post('name_plan');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
$device = _post('device');
|
||||
$pool = _post('pool_name');
|
||||
$plan_expired = _post('plan_expired');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
$expired_date = _post('expired_date');
|
||||
$on_login = _post('on_login');
|
||||
$on_logout = _post('on_logout');
|
||||
|
||||
$msg = '';
|
||||
if (Validator::UnsignedNumber($validity) == false) {
|
||||
$msg .= 'The validity must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($price) == false) {
|
||||
$msg .= 'The price must be a number' . '<br>';
|
||||
}
|
||||
if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
if($price_old<=$price){
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
$old = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
if ($d) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
run_hook('edit_vpn'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
if ($b['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
$raddown = '000';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
$raddown = '000000';
|
||||
}
|
||||
if ($b['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
$radup = '000';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
$radup = '000000';
|
||||
}
|
||||
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
|
||||
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
|
||||
$rate = trim($rate . " " . $b['burst']);
|
||||
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->price_old = $price_old;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
$d->routers = $routers;
|
||||
$d->pool = $pool;
|
||||
$d->plan_expired = $plan_expired;
|
||||
$d->enabled = $enabled;
|
||||
$d->prepaid = $prepaid;
|
||||
$d->device = $device;
|
||||
$d->on_login = $on_login;
|
||||
$d->on_logout = $on_logout;
|
||||
if ($prepaid == 'no') {
|
||||
if ($expired_date > 28 && $expired_date < 1) {
|
||||
$expired_date = 20;
|
||||
}
|
||||
$d->expired_date = $expired_date;
|
||||
} else {
|
||||
$d->expired_date = 0;
|
||||
}
|
||||
$d->save();
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->update_plan($old, $d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(getUrl('services/vpn-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -34,11 +34,11 @@ switch ($action) {
|
||||
$dev = pathinfo($file, PATHINFO_FILENAME);
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . $file;
|
||||
$dvc = new $dev;
|
||||
if(method_exists($dvc, 'description')){
|
||||
if (method_exists($dvc, 'description')) {
|
||||
$arr = $dvc->description();
|
||||
$arr['file'] = $dev;
|
||||
$devices[] = $arr;
|
||||
}else{
|
||||
} else {
|
||||
$devices[] = [
|
||||
'title' => $dev,
|
||||
'description' => '',
|
||||
@ -59,19 +59,19 @@ switch ($action) {
|
||||
|
||||
if (!empty(_get('testWa'))) {
|
||||
$result = Message::sendWhatsapp(_get('testWa'), 'PHPNuxBill Test Whatsapp');
|
||||
r2(U . "settings/app", 's', 'Test Whatsapp has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test Whatsapp has been send<br>Result: ' . $result);
|
||||
}
|
||||
if (!empty(_get('testSms'))) {
|
||||
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
|
||||
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test SMS has been send<br>Result: ' . $result);
|
||||
}
|
||||
if (!empty(_get('testEmail'))) {
|
||||
Message::sendEmail(_get('testEmail'), 'PHPNuxBill Test Email', 'PHPNuxBill Test Email Body');
|
||||
r2(U . "settings/app", 's', 'Test Email has been send');
|
||||
r2(getUrl('settings/app'), 's', 'Test Email has been send');
|
||||
}
|
||||
if (!empty(_get('testTg'))) {
|
||||
$result = Message::sendTelegram('PHPNuxBill Test Telegram');
|
||||
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test Telegram has been send<br>Result: ' . $result);
|
||||
}
|
||||
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
@ -81,6 +81,35 @@ switch ($action) {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
|
||||
}
|
||||
$ui->assign('logo', $logo);
|
||||
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
|
||||
$themes = [];
|
||||
$files = scandir('ui/themes/');
|
||||
foreach ($files as $file) {
|
||||
@ -88,6 +117,20 @@ switch ($action) {
|
||||
$themes[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
$template_files = glob('ui/ui/customer/login-custom-*.tpl');
|
||||
$templates = [];
|
||||
|
||||
foreach ($template_files as $file) {
|
||||
$parts = explode('-', basename($file, '.tpl'));
|
||||
$template_identifier = $parts[2] ?? 'unknown';
|
||||
$templates[] = [
|
||||
'filename' => basename($file),
|
||||
'value' => $template_identifier,
|
||||
'name' => str_replace('_', ' ', ucfirst($template_identifier))
|
||||
];
|
||||
}
|
||||
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
if (function_exists("shell_exec")) {
|
||||
@ -111,11 +154,17 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
if (empty($config['mikrotik_sms_command'])) {
|
||||
$config['mikrotik_sms_command'] = "/tool sms send";
|
||||
}
|
||||
$ui->assign('template_files', $templates);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('php', $php);
|
||||
$ui->assign('dir', str_replace('controllers', '', __DIR__));
|
||||
$ui->assign('themes', $themes);
|
||||
run_hook('view_app_settings'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('app-settings.tpl');
|
||||
break;
|
||||
|
||||
@ -123,10 +172,15 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$company = _post('CompanyName');
|
||||
$custom_tax_rate = filter_var(_post('custom_tax_rate'), FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
if (preg_match('/[^0-9.]/', $custom_tax_rate)) {
|
||||
r2(U . 'settings/app', 'e', 'Special characters are not allowed in tax rate');
|
||||
r2(getUrl('settings/app'), 'e', 'Special characters are not allowed in tax rate');
|
||||
die();
|
||||
}
|
||||
run_hook('save_settings'); #HOOK
|
||||
@ -136,11 +190,11 @@ switch ($action) {
|
||||
File::resizeCropImage($_FILES['logo']['tmp_name'], $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png', 1078, 200, 100);
|
||||
if (file_exists($_FILES['logo']['tmp_name'])) unlink($_FILES['logo']['tmp_name']);
|
||||
} else {
|
||||
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
if ($company == '') {
|
||||
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
|
||||
if ($_POST['general'] && $company == '') {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('All field is required'));
|
||||
} else {
|
||||
if ($radius_enable) {
|
||||
try {
|
||||
@ -151,11 +205,17 @@ switch ($action) {
|
||||
$ui->assign("error_message", "Radius table not found.<br><br>" .
|
||||
$e->getMessage() .
|
||||
"<br><br>Download <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/Development/install/radius.sql\">here</a> or <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/install/radius.sql\">here</a> and import it to database.<br><br>Check config.php for radius connection details");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('error.tpl');
|
||||
die();
|
||||
}
|
||||
}
|
||||
// Save all settings including tax system
|
||||
$_POST['man_fields_email'] = isset($_POST['man_fields_email']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_fname'] = isset($_POST['man_fields_fname']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_address'] = isset($_POST['man_fields_address']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_custom'] = isset($_POST['man_fields_custom']) ? 'yes' : 'no';
|
||||
$enable_session_timeout = isset($_POST['enable_session_timeout']) ? 1 : 0;
|
||||
$_POST['enable_session_timeout'] = $enable_session_timeout;
|
||||
foreach ($_POST as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
@ -168,29 +228,104 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
//checkbox
|
||||
$checks = ['hide_mrc', 'hide_tms', 'hide_aui', 'hide_al', 'hide_uet', 'hide_vs', 'hide_pg'];
|
||||
foreach ($checks as $check) {
|
||||
if (!isset($_POST[$check])) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $check)->find_one();
|
||||
if ($d) {
|
||||
$d->value = 'no';
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $check;
|
||||
$d->value = 'no';
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_log('[' . $admin['username'] . ']: ' . Lang::T('Settings Saved Successfully'), $admin['user_type'], $admin['id']);
|
||||
|
||||
r2(U . 'settings/app', 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/app'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'login-page-post':
|
||||
// Login page post
|
||||
$login_page_title = _post('login_page_head');
|
||||
$login_page_description = _post('login_page_description');
|
||||
$login_Page_template = _post('login_Page_template');
|
||||
$login_page_type = _post('login_page_type');
|
||||
$csrf_token = _post('csrf_token');
|
||||
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
if ($login_page_type == 'custom' && (empty($login_Page_template) || empty($login_page_title) || empty($login_page_description))) {
|
||||
r2(getUrl('settings/app'), 'e', 'Please fill all required fields');
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen($login_page_title) > 25) {
|
||||
r2(getUrl('settings/app'), 'e', 'Login page title must not exceed 25 characters');
|
||||
return;
|
||||
}
|
||||
if (strlen($login_page_description) > 100) {
|
||||
r2(getUrl('settings/app'), 'e', 'Login page description must not exceed 50 characters');
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = [
|
||||
'login_page_head' => $login_page_title,
|
||||
'login_page_description' => $login_page_description,
|
||||
'login_Page_template' => $login_Page_template,
|
||||
'login_page_type' => $login_page_type,
|
||||
];
|
||||
|
||||
$image_paths = [];
|
||||
$allowed_types = ['image/jpeg', 'image/png'];
|
||||
|
||||
if ($_FILES['login_page_favicon']['name'] != '') {
|
||||
$favicon_type = $_FILES['login_page_favicon']['type'];
|
||||
if (in_array($favicon_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_favicon']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_favicon']['name'], PATHINFO_EXTENSION);
|
||||
$favicon_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('favicon_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_favicon']['tmp_name'], $favicon_path, 16, 16, 100);
|
||||
$settings['login_page_favicon'] = basename($favicon_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_favicon']['tmp_name'])) unlink($_FILES['login_page_favicon']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Favicon must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($_FILES['login_page_wallpaper']['name'] != '') {
|
||||
$wallpaper_type = $_FILES['login_page_wallpaper']['type'];
|
||||
if (in_array($wallpaper_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_wallpaper']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_wallpaper']['name'], PATHINFO_EXTENSION);
|
||||
$wallpaper_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('wallpaper_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_wallpaper']['tmp_name'], $wallpaper_path, 1920, 1080, 100);
|
||||
$settings['login_page_wallpaper'] = basename($wallpaper_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_wallpaper']['tmp_name'])) unlink($_FILES['login_page_wallpaper']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Wallpaper must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($_FILES['login_page_logo']['name'] != '') {
|
||||
$logo_type = $_FILES['login_page_logo']['type'];
|
||||
if (in_array($logo_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_logo']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_logo']['name'], PATHINFO_EXTENSION);
|
||||
$logo_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('logo_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_logo']['tmp_name'], $logo_path, 300, 60, 100);
|
||||
$settings['login_page_logo'] = basename($logo_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_logo']['tmp_name'])) unlink($_FILES['login_page_logo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Logo must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $key;
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
|
||||
_log('[' . $admin['username'] . ']: ' . Lang::T('Login Page Settings Saved Successfully'), $admin['user_type'], $admin['id']);
|
||||
r2(getUrl('settings/app'), 's', Lang::T('Login Page Settings Saved Successfully'));
|
||||
break;
|
||||
|
||||
case 'localisation':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
@ -215,6 +350,8 @@ switch ($action) {
|
||||
$ui->assign('tlist', $timezonelist);
|
||||
$ui->assign('xjq', ' $("#tzone").select2(); ');
|
||||
run_hook('view_localisation'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('app-localisation.tpl');
|
||||
break;
|
||||
|
||||
@ -222,13 +359,17 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$tzone = _post('tzone');
|
||||
$date_format = _post('date_format');
|
||||
$country_code_phone = _post('country_code_phone');
|
||||
$lan = _post('lan');
|
||||
run_hook('save_localisation'); #HOOK
|
||||
if ($tzone == '' or $date_format == '' or $lan == '') {
|
||||
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('All field is required'));
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'timezone')->find_one();
|
||||
$d->value = $tzone;
|
||||
@ -293,6 +434,16 @@ switch ($action) {
|
||||
$d->value = _post('pppoe_plan');
|
||||
$d->save();
|
||||
}
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'vpn_plan')->find_one();
|
||||
if ($d) {
|
||||
$d->value = _post('vpn_plan');
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'vpn_plan';
|
||||
$d->value = _post('vpn_plan');
|
||||
$d->save();
|
||||
}
|
||||
|
||||
$currency_code = $_POST['currency_code'];
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one();
|
||||
@ -302,9 +453,8 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'language')->find_one();
|
||||
$d->value = $lan;
|
||||
$d->save();
|
||||
unset($_SESSION['Lang']);
|
||||
_log('[' . $admin['username'] . ']: ' . 'Settings Saved Successfully', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/localisation', 's', 'Settings Saved Successfully');
|
||||
r2(getUrl('settings/localisation'), 's', 'Settings Saved Successfully');
|
||||
}
|
||||
break;
|
||||
|
||||
@ -375,16 +525,20 @@ switch ($action) {
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('search', $search);
|
||||
run_hook('view_list_admin'); #HOOK
|
||||
$ui->display('users.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin.tpl');
|
||||
break;
|
||||
|
||||
case 'users-add':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Add User'));
|
||||
$ui->assign('agents', ORM::for_table('tbl_users')->where('user_type', 'Agent')->find_many());
|
||||
$ui->display('users-add.tpl');
|
||||
$ui->display('admin-add.tpl');
|
||||
break;
|
||||
case 'users-view':
|
||||
$ui->assign('_title', Lang::T('Edit User'));
|
||||
@ -411,9 +565,11 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', $d['username']);
|
||||
$ui->display('users-view.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin-view.tpl');
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'users-edit':
|
||||
@ -445,12 +601,31 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
if ($d) {
|
||||
if (isset($routes['3']) && $routes['3'] == 'deletePhoto') {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo']) && strpos($d['photo'], 'default') === false) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
$d->photo = '/admin.default.png';
|
||||
$d->save();
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', 'You have successfully deleted the photo');
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', 'No photo found to delete');
|
||||
}
|
||||
}
|
||||
$ui->assign('id', $id);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_admin'); #HOOK
|
||||
$ui->display('users-edit.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -461,15 +636,15 @@ switch ($action) {
|
||||
|
||||
$id = $routes['2'];
|
||||
if (($admin['id']) == $id) {
|
||||
r2(U . 'settings/users', 'e', 'Sorry You can\'t delete yourself');
|
||||
r2(getUrl('settings/users'), 'e', 'Sorry You can\'t delete yourself');
|
||||
}
|
||||
$d = ORM::for_table('tbl_users')->find_one($id);
|
||||
if ($d) {
|
||||
run_hook('delete_admin'); #HOOK
|
||||
$d->delete();
|
||||
r2(U . 'settings/users', 's', Lang::T('User deleted Successfully'));
|
||||
r2(getUrl('settings/users'), 's', Lang::T('User deleted Successfully'));
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -477,6 +652,10 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/users-add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = _post('username');
|
||||
$fullname = _post('fullname');
|
||||
$password = _post('password');
|
||||
@ -534,13 +713,17 @@ switch ($action) {
|
||||
}
|
||||
|
||||
_log('[' . $admin['username'] . ']: ' . "Created $user_type <b>$username</b>", $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/users', 's', Lang::T('Account Created Successfully'));
|
||||
r2(getUrl('settings/users'), 's', Lang::T('Account Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'settings/users-add', 'e', $msg);
|
||||
r2(getUrl('settings/users-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'users-edit-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/users-edit/'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = _post('username');
|
||||
$fullname = _post('fullname');
|
||||
$password = _post('password');
|
||||
@ -597,6 +780,55 @@ switch ($action) {
|
||||
}
|
||||
run_hook('edit_admin'); #HOOK
|
||||
if ($msg == '') {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'])) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$d->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
$d->username = $username;
|
||||
if ($password != '') {
|
||||
$password = Password::_crypt($password);
|
||||
@ -627,19 +859,25 @@ switch ($action) {
|
||||
$d->save();
|
||||
|
||||
_log('[' . $admin['username'] . ']: $username ' . Lang::T('User Updated Successfully'), $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/users', 's', 'User Updated Successfully');
|
||||
r2(getUrl('settings/users-view/') . $id, 's', 'User Updated Successfully');
|
||||
} else {
|
||||
r2(U . 'settings/users-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('settings/users-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'change-password':
|
||||
run_hook('view_change_password'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('change-password.tpl');
|
||||
break;
|
||||
|
||||
case 'change-password-post':
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
if ($password != '') {
|
||||
$d = ORM::for_table('tbl_users')->where('username', $admin['username'])->find_one();
|
||||
run_hook('change_password'); #HOOK
|
||||
@ -649,10 +887,10 @@ switch ($action) {
|
||||
$npass = _post('npass');
|
||||
$cnpass = _post('cnpass');
|
||||
if (!Validator::Length($npass, 15, 5)) {
|
||||
r2(U . 'settings/change-password', 'e', 'New Password must be 6 to 14 character');
|
||||
r2(getUrl('settings/change-password'), 'e', 'New Password must be 6 to 14 character');
|
||||
}
|
||||
if ($npass != $cnpass) {
|
||||
r2(U . 'settings/change-password', 'e', 'Both Password should be same');
|
||||
r2(getUrl('settings/change-password'), 'e', 'Both Password should be same');
|
||||
}
|
||||
|
||||
$npass = Password::_crypt($npass);
|
||||
@ -662,15 +900,15 @@ switch ($action) {
|
||||
_msglog('s', Lang::T('Password changed successfully, Please login again'));
|
||||
_log('[' . $admin['username'] . ']: Password changed successfully', $admin['user_type'], $admin['id']);
|
||||
|
||||
r2(U . 'admin');
|
||||
r2(getUrl('admin'));
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -684,6 +922,9 @@ switch ($action) {
|
||||
} else {
|
||||
$ui->assign('_json', json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true));
|
||||
}
|
||||
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_default', json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true));
|
||||
$ui->display('app-notifications.tpl');
|
||||
break;
|
||||
@ -691,15 +932,19 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/notifications'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
file_put_contents($UPLOAD_PATH . "/notifications.json", json_encode($_POST));
|
||||
r2(U . 'settings/notifications', 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/notifications'), 's', Lang::T('Settings Saved Successfully'));
|
||||
break;
|
||||
case 'dbstatus':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
$dbc = new mysqli($db_host, $db_user, $db_password, $db_name);
|
||||
$dbc = new mysqli($db_host, $db_user, $db_pass, $db_name);
|
||||
if ($result = $dbc->query('SHOW TABLE STATUS')) {
|
||||
$tables = array();
|
||||
while ($row = $result->fetch_array()) {
|
||||
@ -781,9 +1026,9 @@ switch ($action) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
if (file_exists($_FILES['json']['tmp_name'])) unlink($_FILES['json']['tmp_name']);
|
||||
r2(U . "settings/dbstatus", 's', "Restored $suc success $fal failed");
|
||||
r2(getUrl('settings/dbstatus'), 's', "Restored $suc success $fal failed");
|
||||
} else {
|
||||
r2(U . "settings/dbstatus", 'e', 'Upload failed');
|
||||
r2(getUrl('settings/dbstatus'), 'e', 'Upload failed');
|
||||
}
|
||||
break;
|
||||
case 'language':
|
||||
@ -796,12 +1041,18 @@ switch ($action) {
|
||||
} else {
|
||||
$ui->assign('langs', []);
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('language-add.tpl');
|
||||
break;
|
||||
|
||||
case 'lang-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/language'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
file_put_contents($lan_file, json_encode($_POST, JSON_PRETTY_PRINT));
|
||||
r2(U . 'settings/language', 's', Lang::T('Translation saved Successfully'));
|
||||
r2(getUrl('settings/language'), 's', Lang::T('Translation saved Successfully'));
|
||||
break;
|
||||
|
||||
case 'maintenance':
|
||||
@ -809,7 +1060,12 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (_post('save') == 'save') {
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/maintenance'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$status = isset($_POST['maintenance_mode']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
|
||||
$force_logout = isset($_POST['maintenance_mode_logout']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
|
||||
$date = isset($_POST['maintenance_date']) ? $_POST['maintenance_date'] : null;
|
||||
@ -833,13 +1089,47 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
|
||||
r2(U . "settings/maintenance", 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/maintenance'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('_title', Lang::T('Maintenance Mode Settings'));
|
||||
$ui->display('maintenance-mode.tpl');
|
||||
break;
|
||||
|
||||
case 'miscellaneous':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
if (_post('save') == 'save') {
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/miscellaneous'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
foreach ($_POST as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $key;
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
|
||||
r2(getUrl('settings/miscellaneous'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('_title', Lang::T('Miscellaneous Settings'));
|
||||
$ui->display('app-miscellaneous.tpl');
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
@ -11,19 +12,17 @@ $action = $routes['1'];
|
||||
$user = User::_info();
|
||||
$ui->assign('_user', $user);
|
||||
|
||||
require_once 'system/autoload/PEAR2/Autoload.php';
|
||||
|
||||
switch ($action) {
|
||||
|
||||
case 'activation':
|
||||
run_hook('view_activate_voucher'); #HOOK
|
||||
$ui->assign('code', alphanumeric(_get('code'),"-"));
|
||||
$ui->display('user-activation.tpl');
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-_.,"));
|
||||
$ui->display('customer/activation.tpl');
|
||||
break;
|
||||
|
||||
case 'activation-post':
|
||||
$code = _post('code');
|
||||
$v1 = ORM::for_table('tbl_voucher')->where('code', $code)->where('status', 0)->find_one();
|
||||
$code = alphanumeric(_post('code'), "-_.,");
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$code'")->where('status', 0)->find_one();
|
||||
run_hook('customer_activate_voucher'); #HOOK
|
||||
if ($v1) {
|
||||
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Voucher", $code)) {
|
||||
@ -31,37 +30,43 @@ switch ($action) {
|
||||
$v1->used_date = date('Y-m-d H:i:s');
|
||||
$v1->user = $user['username'];
|
||||
$v1->save();
|
||||
r2(U . "voucher/list-activated", 's', Lang::T('Activation Vouchers Successfully'));
|
||||
r2(getUrl('voucher/list-activated'), 's', Lang::T('Activation Vouchers Successfully'));
|
||||
} else {
|
||||
r2(U . 'voucher/activation', 'e', "Failed to refill account");
|
||||
r2(getUrl('voucher/activation'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'voucher/activation', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('voucher/activation'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'list-activated':
|
||||
$ui->assign('_system_menu', 'list-activated');
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id');
|
||||
$query = ORM::for_table('tbl_transactions')->where('user_id', $user['id'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
|
||||
if (empty($d) || $d < 5) {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', Lang::T('Activation History'));
|
||||
run_hook('customer_view_activation_list'); #HOOK
|
||||
$ui->display('user-activation-list.tpl');
|
||||
$ui->display('customer/activation-list.tpl');
|
||||
|
||||
break;
|
||||
case 'invoice':
|
||||
$id = $routes[2];
|
||||
if(empty($id)){
|
||||
if (empty($id)) {
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id')->find_one();
|
||||
}else{
|
||||
} else {
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->where('id', $id)->find_one();
|
||||
}
|
||||
if($in){
|
||||
if ($in) {
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice-customer.tpl');
|
||||
}else{
|
||||
r2(U . 'voucher/list-activated', 'e', Lang::T('Not Found'));
|
||||
$ui->display('customer/invoice-customer.tpl');
|
||||
} else {
|
||||
r2(getUrl('voucher/list-activated'), 'e', Lang::T('Not Found'));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
152
system/cron.php
152
system/cron.php
@ -1,6 +1,27 @@
|
||||
<?php
|
||||
|
||||
include "../init.php";
|
||||
$lockFile = "$CACHE_PATH/router_monitor.lock";
|
||||
|
||||
if (!is_dir($CACHE_PATH)) {
|
||||
echo "Directory '$CACHE_PATH' does not exist. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$lock = fopen($lockFile, 'c');
|
||||
|
||||
if ($lock === false) {
|
||||
echo "Failed to open lock file. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!flock($lock, LOCK_EX | LOCK_NB)) {
|
||||
echo "Script is already running. Exiting...\n";
|
||||
fclose($lock);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$isCli = true;
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$isCli = false;
|
||||
@ -32,8 +53,11 @@ foreach ($d as $ds) {
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
if (empty($c)) {
|
||||
$c = $u;
|
||||
}
|
||||
$dvc = Package::getDevice($p);
|
||||
if($_app_stage != 'demo'){
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->remove_customer($c, $p);
|
||||
@ -50,7 +74,7 @@ foreach ($d as $ds) {
|
||||
// autorenewal from deposit
|
||||
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
|
||||
list($bills, $add_cost) = User::getBills($ds['customer_id']);
|
||||
if ($add_cost > 0) {
|
||||
if ($add_cost != 0) {
|
||||
if (!empty($add_cost)) {
|
||||
$p['price'] += $add_cost;
|
||||
}
|
||||
@ -78,3 +102,127 @@ foreach ($d as $ds) {
|
||||
echo " : ACTIVE \r\n";
|
||||
}
|
||||
}
|
||||
|
||||
//Cek interim-update radiusrest
|
||||
if ($config['frrest_interim_update'] != 0) {
|
||||
|
||||
$r_a = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY acctstatustype = 'Start' OR acctstatustype = 'Interim-Update'")
|
||||
->where_lte('dateAdded', date("Y-m-d H:i:s"))->find_many();
|
||||
|
||||
foreach ($r_a as $ra) {
|
||||
$interval = $_c['frrest_interim_update']*60;
|
||||
$timeUpdate = strtotime($ra['dateAdded'])+$interval;
|
||||
$timeNow = strtotime(date("Y-m-d H:i:s"));
|
||||
if ($timeNow >= $timeUpdate) {
|
||||
$ra->acctstatustype = 'Stop';
|
||||
$ra->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config['router_check']) {
|
||||
echo "Checking router status...\n";
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
if (!$routers) {
|
||||
echo "No active routers found in the database.\n";
|
||||
flock($lock, LOCK_UN);
|
||||
fclose($lock);
|
||||
unlink($lockFile);
|
||||
exit;
|
||||
}
|
||||
|
||||
$offlineRouters = [];
|
||||
$errors = [];
|
||||
|
||||
foreach ($routers as $router) {
|
||||
// check if custom port
|
||||
if (strpos($router->ip_address, ':') === false){
|
||||
$ip = $router->ip_address;
|
||||
$port = 8728;
|
||||
} else {
|
||||
[$ip, $port] = explode(':', $router->ip_address);
|
||||
}
|
||||
$isOnline = false;
|
||||
|
||||
try {
|
||||
$timeout = 5;
|
||||
if (is_callable('fsockopen') && false === stripos(ini_get('disable_functions'), 'fsockopen')) {
|
||||
$fsock = @fsockopen($ip, $port, $errno, $errstr, $timeout);
|
||||
if ($fsock) {
|
||||
fclose($fsock);
|
||||
$isOnline = true;
|
||||
} else {
|
||||
throw new Exception("Unable to connect to $ip on port $port using fsockopen: $errstr ($errno)");
|
||||
}
|
||||
} elseif (is_callable('stream_socket_client') && false === stripos(ini_get('disable_functions'), 'stream_socket_client')) {
|
||||
$connection = @stream_socket_client("$ip:$port", $errno, $errstr, $timeout);
|
||||
if ($connection) {
|
||||
fclose($connection);
|
||||
$isOnline = true;
|
||||
} else {
|
||||
throw new Exception("Unable to connect to $ip on port $port using stream_socket_client: $errstr ($errno)");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Neither fsockopen nor stream_socket_client are enabled on the server.");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
_log($e->getMessage());
|
||||
$errors[] = "Error with router $ip: " . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($isOnline) {
|
||||
$router->last_seen = date('Y-m-d H:i:s');
|
||||
$router->status = 'Online';
|
||||
} else {
|
||||
$router->status = 'Offline';
|
||||
$offlineRouters[] = $router;
|
||||
}
|
||||
|
||||
$router->save();
|
||||
}
|
||||
|
||||
if (!empty($offlineRouters)) {
|
||||
$message = "Dear Administrator,\n";
|
||||
$message .= "The following routers are offline:\n";
|
||||
foreach ($offlineRouters as $router) {
|
||||
$message .= "Name: {$router->name}, IP: {$router->ip_address}, Last Seen: {$router->last_seen}\n";
|
||||
}
|
||||
$message .= "\nPlease check the router's status and take appropriate action.\n\nBest regards,\nRouter Monitoring System";
|
||||
|
||||
$adminEmail = $config['mail_from'];
|
||||
$subject = "Router Offline Alert";
|
||||
Message::SendEmail($adminEmail, $subject, $message);
|
||||
sendTelegram($message);
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
$message = "The following errors occurred during router monitoring:\n";
|
||||
foreach ($errors as $error) {
|
||||
$message .= "$error\n";
|
||||
}
|
||||
|
||||
$adminEmail = $config['mail_from'];
|
||||
$subject = "Router Monitoring Error Alert";
|
||||
Message::SendEmail($adminEmail, $subject, $message);
|
||||
sendTelegram($message);
|
||||
}
|
||||
echo "Router monitoring finished\n";
|
||||
}
|
||||
|
||||
|
||||
if (defined('PHP_SAPI') && PHP_SAPI === 'cli') {
|
||||
echo "Cronjob finished\n";
|
||||
} else {
|
||||
echo "</pre>";
|
||||
}
|
||||
|
||||
flock($lock, LOCK_UN);
|
||||
fclose($lock);
|
||||
unlink($lockFile);
|
||||
|
||||
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
|
||||
file_put_contents($timestampFile, time());
|
||||
|
||||
|
||||
run_hook('cronjob_end'); #HOOK
|
||||
|
@ -33,10 +33,38 @@ class MikrotikHotspot
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$isExp = ORM::for_table('tbl_plans')->select("id")->where('plan_expired', $plan['id'])->find_one();
|
||||
$this->removeHotspotUser($client, $customer['username']);
|
||||
if ($isExp){
|
||||
$this->removeHotspotActiveUser($client, $customer['username']);
|
||||
}
|
||||
$this->addHotspotUser($client, $plan, $customer);
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$t = ORM::for_table('tbl_user_recharges')->where('username', $customer['username'])->where('status', 'on')->find_one();
|
||||
if ($t) {
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
$printRequest->setArgument('.proplist', '.id,limit-uptime,limit-bytes-total');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$userInfo = $client->sendSync($printRequest);
|
||||
$id = $userInfo->getProperty('.id');
|
||||
$uptime = $userInfo->getProperty('limit-uptime');
|
||||
$data = $userInfo->getProperty('limit-bytes-total');
|
||||
if (!empty($id) && (!empty($uptime) || !empty($data))) {
|
||||
$setRequest = new RouterOS\Request('/ip/hotspot/user/set');
|
||||
$setRequest->setArgument('numbers', $id);
|
||||
$setRequest->setArgument('profile', $t['namebp']);
|
||||
$client->sendSync($setRequest);
|
||||
} else {
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
@ -44,10 +72,13 @@ class MikrotikHotspot
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
if (!empty($plan['plan_expired'])) {
|
||||
$p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']);
|
||||
$this->add_customer($customer, $p);
|
||||
} else {
|
||||
$this->removeHotspotUser($client, $customer['username']);
|
||||
if($p){
|
||||
$this->add_customer($customer, $p);
|
||||
$this->removeHotspotActiveUser($client, $customer['username']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->removeHotspotUser($client, $customer['username']);
|
||||
$this->removeHotspotActiveUser($client, $customer['username']);
|
||||
}
|
||||
|
||||
@ -106,9 +137,10 @@ class MikrotikHotspot
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip hotspot active print',
|
||||
RouterOS\Query::where('name', $customer['username'])
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
return $id;
|
||||
}
|
||||
|
||||
function connect_customer($customer, $ip, $mac_address, $router_name)
|
||||
@ -207,7 +239,7 @@ class MikrotikHotspot
|
||||
function getClient($ip, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$iport = explode(":", $ip);
|
||||
@ -217,7 +249,7 @@ class MikrotikHotspot
|
||||
function removeHotspotUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
@ -235,7 +267,7 @@ class MikrotikHotspot
|
||||
function addHotspotUser($client, $plan, $customer)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/hotspot/user/add');
|
||||
@ -303,7 +335,7 @@ class MikrotikHotspot
|
||||
function setHotspotUser($client, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
@ -320,7 +352,7 @@ class MikrotikHotspot
|
||||
function setHotspotUserPackage($client, $username, $plan_name)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
@ -337,7 +369,7 @@ class MikrotikHotspot
|
||||
function removeHotspotActiveUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$onlineRequest = new RouterOS\Request('/ip/hotspot/active/print');
|
||||
@ -353,7 +385,7 @@ class MikrotikHotspot
|
||||
function getIpHotspotUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
|
@ -29,43 +29,83 @@ class MikrotikPppoe
|
||||
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
global $isChangePlan;
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
//check if customer exists
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$cid = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$cid = self::getIdByCustomer($customer, $client);
|
||||
$isExp = ORM::for_table('tbl_plans')->select("id")->where('plan_expired', $plan['id'])->find_one();
|
||||
if (empty($cid)) {
|
||||
//customer not exists, add it
|
||||
$this->addPpoeUser($client, $plan, $customer);
|
||||
$this->addPpoeUser($client, $plan, $customer, $isExp);
|
||||
}else{
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$pass = $customer['pppoe_password'];
|
||||
} else {
|
||||
$pass = $customer['password'];
|
||||
}
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
$unsetIP = false;
|
||||
if (!empty($customer['pppoe_ip']) && !$isExp){
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$unsetIP = true;
|
||||
}
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
$setRequest->setArgument('password', $pass);
|
||||
$client->sendSync($setRequest);
|
||||
|
||||
if($unsetIP){
|
||||
$unsetRequest = new RouterOS\Request('/ppp/secret/unset');
|
||||
$unsetRequest->setArgument('.id', $cid);
|
||||
$unsetRequest->setArgument('value-name','remote-address');
|
||||
$client->sendSync($unsetRequest);
|
||||
}
|
||||
|
||||
|
||||
//disconnect then
|
||||
//$this->removePpoeActive($client, $customer['username']);
|
||||
if(isset($isChangePlan) && $isChangePlan){
|
||||
$this->removePpoeActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removePpoeActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
if (!empty($plan['plan_expired'])) {
|
||||
$p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']);
|
||||
$this->add_customer($customer, $p);
|
||||
} else {
|
||||
$this->removePpoeUser($client, $customer['username']);
|
||||
if($p){
|
||||
$this->add_customer($customer, $p);
|
||||
$this->removePpoeActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removePpoeActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->removePpoeUser($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removePpoeUser($client, $customer['pppoe_username']);
|
||||
}
|
||||
$this->removePpoeActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removePpoeActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
|
||||
// customer change username
|
||||
@ -120,6 +160,23 @@ class MikrotikPppoe
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to ID by username from Mikrotik
|
||||
*/
|
||||
function getIdByCustomer($customer, $client){
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if(empty($id)){
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['pppoe_username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
function update_plan($old_name, $new_plan)
|
||||
{
|
||||
$mikrotik = $this->info($new_plan['routers']);
|
||||
@ -245,9 +302,17 @@ class MikrotikPppoe
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
RouterOS\Query::where('name', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if(empty($id)){
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('name', $customer['pppoe_username'])
|
||||
);
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
function info($name)
|
||||
@ -280,53 +345,25 @@ class MikrotikPppoe
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
|
||||
function addPpoeUser($client, $plan, $customer)
|
||||
function addPpoeUser($client, $plan, $customer, $isExp = false)
|
||||
{
|
||||
global $_app_stage;
|
||||
$addRequest = new RouterOS\Request('/ppp/secret/add');
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/add');
|
||||
$setRequest->setArgument('service', 'pppoe');
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$pass = $customer['pppoe_password'];
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$pass = $customer['password'];
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('name', $customer['username'])
|
||||
->setArgument('service', 'pppoe')
|
||||
->setArgument('profile', $plan['name_plan'])
|
||||
->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])))
|
||||
->setArgument('password', $pass)
|
||||
);
|
||||
}
|
||||
|
||||
function setPpoeUser($client, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setArgument('.proplist', '.id');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $user));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $id);
|
||||
$setRequest->setArgument('password', $pass);
|
||||
$client->sendSync($setRequest);
|
||||
}
|
||||
|
||||
function setPpoeUserPlan($client, $user, $plan)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip']) && !$isExp) {
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setArgument('.proplist', '.id');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $user));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $id);
|
||||
$setRequest->setArgument('profile', $plan);
|
||||
$client->sendSync($setRequest);
|
||||
}
|
||||
|
||||
|
512
system/devices/MikrotikVpn.php
Normal file
512
system/devices/MikrotikVpn.php
Normal file
@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
use PEAR2\Net\RouterOS;
|
||||
|
||||
class MikrotikVpn
|
||||
{
|
||||
|
||||
function description()
|
||||
{
|
||||
return [
|
||||
'title' => 'Mikrotik Vpn',
|
||||
'description' => 'To handle connection between PHPNuxBill with Mikrotik VPN',
|
||||
'author' => 'agstr',
|
||||
'url' => [
|
||||
'Github' => 'https://github.com/agstrxyz',
|
||||
'Telegram' => 'https://t.me/agstrxyz',
|
||||
'Youtube' => 'https://www.youtube.com/@agstrxyz',
|
||||
'Donate' => 'https://paypal.me/ibnux'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
global $isChangePlan;
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$cid = self::getIdByCustomer($customer, $client);
|
||||
if (empty($cid)) {
|
||||
$this->addVpnUser($client, $plan, $customer);
|
||||
} else {
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$setRequest->setArgument('remote-address', '0.0.0.0');
|
||||
}
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
$client->sendSync($setRequest);
|
||||
if (isset($isChangePlan) && $isChangePlan) {
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
if (!empty($plan['plan_expired'])) {
|
||||
$p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']);
|
||||
if ($p) {
|
||||
$this->add_customer($customer, $p);
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->removeVpnUser($client, $customer['username'], $customer['id']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnUser($client, $customer['pppoe_username'], $customer['id']);
|
||||
}
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
|
||||
public function change_username($plan, $from, $to)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $from));
|
||||
$cid = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (!empty($cid)) {
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
$setRequest->setArgument('name', $to);
|
||||
$client->sendSync($setRequest);
|
||||
$this->removeVpnActive($client, $from);
|
||||
}
|
||||
}
|
||||
|
||||
function add_plan($plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
}
|
||||
if ($bw['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
}
|
||||
$rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown;
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $plan['pool'])->find_one();
|
||||
$addRequest = new RouterOS\Request('/ppp/profile/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('name', $plan['name_plan'])
|
||||
->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip'] : $pool['pool_name'])
|
||||
->setArgument('remote-address', $pool['pool_name'])
|
||||
->setArgument('rate-limit', $rate)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function getIdByCustomer($customer, $client)
|
||||
{
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($id)) {
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['pppoe_username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
function update_plan($old_name, $new_plan)
|
||||
{
|
||||
$mikrotik = $this->info($new_plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp profile print .proplist=.id',
|
||||
RouterOS\Query::where('name', $old_name['name_plan'])
|
||||
);
|
||||
$profileID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($profileID)) {
|
||||
$this->add_plan($new_plan);
|
||||
} else {
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($new_plan['id_bw']);
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
}
|
||||
if ($bw['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
}
|
||||
$rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown;
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $new_plan['pool'])->find_one();
|
||||
$setRequest = new RouterOS\Request('/ppp/profile/set');
|
||||
$client->sendSync(
|
||||
$setRequest
|
||||
->setArgument('numbers', $profileID)
|
||||
->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip'] : $pool['pool_name'])
|
||||
->setArgument('remote-address', $pool['pool_name'])
|
||||
->setArgument('rate-limit', $rate)
|
||||
->setArgument('on-up', $new_plan['on_login'])
|
||||
->setArgument('on-down', $new_plan['on_logout'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function remove_plan($plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp profile print .proplist=.id',
|
||||
RouterOS\Query::where('name', $plan['name_plan'])
|
||||
);
|
||||
$profileID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
|
||||
$removeRequest = new RouterOS\Request('/ppp/profile/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $profileID)
|
||||
);
|
||||
}
|
||||
|
||||
function add_pool($pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$addRequest = new RouterOS\Request('/ip/pool/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('name', $pool['pool_name'])
|
||||
->setArgument('ranges', $pool['range_ip'])
|
||||
);
|
||||
}
|
||||
|
||||
function update_pool($old_pool, $new_pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($new_pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip pool print .proplist=.id',
|
||||
RouterOS\Query::where('name', $old_pool['pool_name'])
|
||||
);
|
||||
$poolID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($poolID)) {
|
||||
$this->add_pool($new_pool);
|
||||
} else {
|
||||
$setRequest = new RouterOS\Request('/ip/pool/set');
|
||||
$client->sendSync(
|
||||
$setRequest
|
||||
->setArgument('numbers', $poolID)
|
||||
->setArgument('name', $new_pool['pool_name'])
|
||||
->setArgument('ranges', $new_pool['range_ip'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function remove_pool($pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip pool print .proplist=.id',
|
||||
RouterOS\Query::where('name', $pool['pool_name'])
|
||||
);
|
||||
$poolID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/pool/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $poolID)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function online_customer($customer, $router_name)
|
||||
{
|
||||
$mikrotik = $this->info($router_name);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
|
||||
function info($name)
|
||||
{
|
||||
return ORM::for_table('tbl_routers')->where('name', $name)->find_one();
|
||||
}
|
||||
|
||||
function getClient($ip, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$iport = explode(":", $ip);
|
||||
return new RouterOS\Client($iport[0], $user, $pass, ($iport[1]) ? $iport[1] : null);
|
||||
}
|
||||
|
||||
function removeVpnUser($client, $username, $cstid)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
//$printRequest->setArgument('.proplist', '.id');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $username));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ppp/secret/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
$this->rmNat($client, $cstid);
|
||||
}
|
||||
|
||||
function addVpnUser($client, $plan, $customer)
|
||||
{
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/add');
|
||||
$setRequest->setArgument('service', 'any');
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$ips = $customer['pppoe_ip'];
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$ips = $this->checkIpAddr($plan['pool'], $customer['id']);
|
||||
$setRequest->setArgument('remote-address', $ips);
|
||||
}
|
||||
$this->addNat($client, $plan, $customer, $ips);
|
||||
$client->sendSync($setRequest);
|
||||
$customer->service_type = 'VPN';
|
||||
$customer->pppoe_ip = $ips;
|
||||
$customer->save();
|
||||
}
|
||||
|
||||
function removeVpnActive($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$onlineRequest = new RouterOS\Request('/ppp/active/print');
|
||||
$onlineRequest->setArgument('.proplist', '.id');
|
||||
$onlineRequest->setQuery(RouterOS\Query::where('name', $username));
|
||||
$id = $client->sendSync($onlineRequest)->getProperty('.id');
|
||||
|
||||
$removeRequest = new RouterOS\Request('/ppp/active/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
|
||||
|
||||
function addIpToAddressList($client, $ip, $listName, $comment = '')
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/firewall/address-list/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('address', $ip)
|
||||
->setArgument('comment', $comment)
|
||||
->setArgument('list', $listName)
|
||||
);
|
||||
}
|
||||
|
||||
function removeIpFromAddressList($client, $ip)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip firewall address-list print .proplist=.id',
|
||||
RouterOS\Query::where('address', $ip)
|
||||
);
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/firewall/address-list/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $id)
|
||||
);
|
||||
}
|
||||
|
||||
function addNat($client, $plan, $cust, $ips)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$this->checkPort($cust['id'], 'Winbox', $plan['routers']);
|
||||
$this->checkPort($cust['id'], 'Api', $plan['routers']);
|
||||
$this->checkPort($cust['id'], 'Web', $plan['routers']);
|
||||
$tcf = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $cust['id'])
|
||||
->find_many();
|
||||
$ip = ORM::for_table('tbl_port_pool')
|
||||
->where('routers', $plan['routers'])
|
||||
->find_one();
|
||||
foreach ($tcf as $cf) {
|
||||
$dst = $cf['field_value'];
|
||||
$cmnt = $cf['field_name'];
|
||||
if ($cmnt == 'Winbox') {
|
||||
$tp = '8291';
|
||||
}
|
||||
if ($cmnt == 'Web') {
|
||||
$tp = '80';
|
||||
}
|
||||
if ($cmnt == 'Api') {
|
||||
$tp = '8728';
|
||||
}
|
||||
if ($cmnt == 'Winbox' || $cmnt == 'Web' || $cmnt == 'Api') {
|
||||
$addRequest = new RouterOS\Request('/ip/firewall/nat/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('chain', 'dstnat')
|
||||
->setArgument('protocol', 'tcp')
|
||||
->setArgument('dst-port', $dst)
|
||||
->setArgument('action', 'dst-nat')
|
||||
->setArgument('to-addresses', $ips)
|
||||
->setArgument('to-ports', $tp)
|
||||
->setArgument('dst-address', $ip['public_ip'])
|
||||
->setArgument('comment', $cmnt . ' || ' . $cust['username'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rmNat($client, $cstid)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cst = ORM::for_table('tbl_customers')->find_one($cstid);
|
||||
$printRequest = new RouterOS\Request('/ip/firewall/nat/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('to-addresses', $cst['pppoe_ip']));
|
||||
$nats = $client->sendSync($printRequest);
|
||||
foreach ($nats as $nat) {
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/firewall/nat/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkPort($id, $portn, $router)
|
||||
{
|
||||
$tcf = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $id)
|
||||
->where('field_name', $portn)
|
||||
->find_one();
|
||||
$ports = ORM::for_table('tbl_port_pool')
|
||||
->where('routers', $router)
|
||||
->find_one();
|
||||
$port = explode('-', $ports['range_port']);
|
||||
if (empty($tcf) && !empty($ports)) {
|
||||
repeat:
|
||||
$portr = rand($port['0'], $port['1']);
|
||||
if (ORM::for_table('tbl_customers_fields')->where('field_value', $portr)->find_one()) {
|
||||
if ($portr == $port['1']) {
|
||||
return;
|
||||
}
|
||||
goto repeat;
|
||||
}
|
||||
$cf = ORM::for_table('tbl_customers_fields')->create();
|
||||
$cf->customer_id = $id;
|
||||
$cf->field_name = $portn;
|
||||
$cf->field_value = $portr;
|
||||
$cf->save();
|
||||
}
|
||||
}
|
||||
|
||||
function checkIpAddr($pname, $id)
|
||||
{
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
$ipp = ORM::for_table('tbl_pool')
|
||||
->where('pool_name', $pname)
|
||||
->find_one();
|
||||
$ip_r = explode('-', $ipp['range_ip']);
|
||||
$ip_1 = explode('.', $ip_r['0']);
|
||||
$ip_2 = explode('.', $ip_r['1']);
|
||||
repeat:
|
||||
$ipt = rand($ip_1['3'], $ip_2['3']);
|
||||
$ips = $ip_1['0'] . '.' . $ip_1['1'] . '.' . $ip_1['2'] . '.' . $ipt;
|
||||
if (empty($c['pppoe_ip'])) {
|
||||
if (ORM::for_table('tbl_customers')->where('pppoe_ip', $ips)->find_one()) {
|
||||
if ($ip_2['3'] == $ipt) {
|
||||
return;
|
||||
}
|
||||
goto repeat;
|
||||
}
|
||||
return $ips;
|
||||
}
|
||||
}
|
||||
}
|
@ -28,28 +28,104 @@ class Radius
|
||||
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
$b = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $customer['id'])
|
||||
->where('plan_id', $plan['id'])
|
||||
->where('status', 'on')
|
||||
->findMany();
|
||||
$p = ORM::for_table('tbl_plans')
|
||||
->where('id', $plan['id'])
|
||||
->findOne();
|
||||
|
||||
if($b){
|
||||
$this->customerAddPlan($customer, $plan, $b['expiration'] . ' ' . $b['time']);
|
||||
$date_only = date("Y-m-d");
|
||||
if ($p['validity_unit'] == 'Period') {
|
||||
// if customer has attribute Expired Date use it
|
||||
$day_exp = User::getAttribute("Expired Date", $customer['id']);
|
||||
if (!$day_exp) {
|
||||
// if customer no attribute Expired Date use plan expired date
|
||||
$day_exp = 20;
|
||||
if ($p['prepaid'] == 'no') {
|
||||
$day_exp = $p['expired_date'];
|
||||
}
|
||||
if (empty($day_exp)) {
|
||||
$day_exp = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($p['validity_unit'] == 'Months') {
|
||||
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' month'));
|
||||
$time = date("H:i:s");
|
||||
} else if ($p['validity_unit'] == 'Period') {
|
||||
$current_date = new DateTime($date_only);
|
||||
$exp_date = clone $current_date;
|
||||
$exp_date->modify('first day of next month');
|
||||
$exp_date->setDate($exp_date->format('Y'), $exp_date->format('m'), $day_exp);
|
||||
|
||||
$min_days = 7 * $p['validity'];
|
||||
$max_days = 35 * $p['validity'];
|
||||
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
|
||||
// If less than min_days away, move to the next period
|
||||
while ($days_until_exp < $min_days) {
|
||||
$exp_date->modify('+1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// If more than max_days away, move to the previous period
|
||||
while ($days_until_exp > $max_days) {
|
||||
$exp_date->modify('-1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// Final check to ensure we're not less than min_days or in the past
|
||||
if ($days_until_exp < $min_days || $exp_date <= $current_date) {
|
||||
$exp_date->modify('+1 month');
|
||||
}
|
||||
|
||||
// Adjust for multiple periods
|
||||
if ($p['validity'] > 1) {
|
||||
$exp_date->modify('+' . ($p['validity'] - 1) . ' months');
|
||||
}
|
||||
|
||||
$date_exp = $exp_date->format('Y-m-d');
|
||||
$time = "23:59:59";
|
||||
} else if ($p['validity_unit'] == 'Days') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
} else if ($p['validity_unit'] == 'Hrs') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' hour')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
} else if ($p['validity_unit'] == 'Mins') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' minute')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
}
|
||||
|
||||
if ($p) {
|
||||
$this->customerAddPlan($customer, $plan, $date_exp . ' ' . $time);
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$t = ORM::for_table('tbl_user_recharges')->where('username', $customer['username'])->where('status', 'on')->findOne();
|
||||
$date_exp = $t['expiration'];
|
||||
$time = $t['time'];
|
||||
$this->customerAddPlan($customer, $plan, $date_exp . ' ' . $time);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
if (!empty($plan['plan_expired'])) {
|
||||
$p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']);
|
||||
$this->customerAddPlan($customer, $p);
|
||||
if ($p) {
|
||||
$this->customerAddPlan($customer, $p);
|
||||
}
|
||||
} else {
|
||||
$this->customerDeactivate($customer['username'], true);
|
||||
}
|
||||
$this->customerDeactivate($customer['username'], true);
|
||||
}
|
||||
}
|
||||
|
||||
public function change_username($from, $to)
|
||||
public function change_username($plan, $from, $to)
|
||||
{
|
||||
$c = $this->getTableCustomer()->where_equal('username', $from)->findMany();
|
||||
if ($c) {
|
||||
@ -108,7 +184,7 @@ class Radius
|
||||
function remove_plan($plan)
|
||||
{
|
||||
// Delete Plan
|
||||
$this->getTablePackage()->where_equal('plan_id', "plan_" . $plan['id'])->delete_many();
|
||||
$this->getTablePackage()->where_equal('plan_id', $plan['id'])->delete_many();
|
||||
// Reset User Plan
|
||||
$c = $this->getTableUserPackage()->where_equal('groupname', "plan_" . $plan['id'])->findMany();
|
||||
if ($c) {
|
||||
@ -214,21 +290,29 @@ class Radius
|
||||
{
|
||||
$this->getTableCustomer()->where_equal('username', $username)->delete_many();
|
||||
$this->getTableUserPackage()->where_equal('username', $username)->delete_many();
|
||||
$this->getTableCustomerAttr()->where_equal('username', $username)->delete_many();
|
||||
}
|
||||
|
||||
/**
|
||||
* When add a plan to Customer, use this
|
||||
*/
|
||||
public function customerAddPlan($customer, $plan, $expired = null)
|
||||
public function customerAddPlan($customer, $plan, $expired = '')
|
||||
{
|
||||
global $config;
|
||||
if ($this->customerUpsert($customer, $plan)) {
|
||||
$p = $this->getTableUserPackage()->where_equal('username', $customer['username'])->findOne();
|
||||
if ($p) {
|
||||
// if exists
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->delAtribute($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-Data', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
|
||||
//$this->delAtribute($this->getTableCustomer(), 'Ascend-Data-Rate', 'username', $customer['username']);
|
||||
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
|
||||
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
|
||||
$p->groupname = "plan_" . $plan['id'];
|
||||
$p->save();
|
||||
} else {
|
||||
@ -238,53 +322,62 @@ class Radius
|
||||
$p->priority = 1;
|
||||
$p->save();
|
||||
}
|
||||
|
||||
|
||||
$this->addBandwidth($customer, $plan);
|
||||
|
||||
if ($plan['type'] == 'Hotspot' && $plan['typebp'] == "Limited") {
|
||||
if ($plan['limit_type'] == "Time_Limit") {
|
||||
if ($plan['time_unit'] == 'Hrs')
|
||||
$timelimit = $plan['time_limit'] * 60 * 60;
|
||||
else
|
||||
$timelimit = $plan['time_limit'] * 60;
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
|
||||
$this->upsertCustomer($customer['username'], 'Expire-After', $timelimit);
|
||||
} else if ($plan['limit_type'] == "Data_Limit") {
|
||||
if ($plan['data_unit'] == 'GB')
|
||||
$datalimit = $plan['data_limit'] . "000000000";
|
||||
else
|
||||
$datalimit = $plan['data_limit'] . "000000";
|
||||
//$this->upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
|
||||
// Mikrotik Spesific
|
||||
$this->upsertCustomer($customer['username'], 'Max-Data', $datalimit);
|
||||
//$this->upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
|
||||
} else if ($plan['limit_type'] == "Both_Limit") {
|
||||
if ($plan['time_unit'] == 'Hrs')
|
||||
$timelimit = $plan['time_limit'] * 60 * 60;
|
||||
else
|
||||
$timelimit = $plan['time_limit'] * 60;
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
|
||||
if ($plan['data_unit'] == 'GB')
|
||||
$datalimit = $plan['data_limit'] . "000000000";
|
||||
else
|
||||
$datalimit = $plan['data_limit'] . "000000";
|
||||
//$this->upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
|
||||
// Mikrotik Spesific
|
||||
$this->upsertCustomer($customer['username'], 'Max-Data', $datalimit);
|
||||
//$this->upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
|
||||
}
|
||||
} else {
|
||||
//$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->delAtribute($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-Data', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
|
||||
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
|
||||
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
|
||||
}
|
||||
|
||||
$this->disconnectCustomer($customer['username']);
|
||||
$this->getTableAcct()->where_equal('username', $customer['username'])->delete_many();
|
||||
|
||||
|
||||
// expired user
|
||||
if ($expired != null) {
|
||||
//$this->upsertCustomer($customer['username'], 'access-period', strtotime($expired) - time());
|
||||
if ($expired != '') {
|
||||
//extend session time only if the plan are the same
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
|
||||
$this->upsertCustomer($customer['username'], 'expiration', date('d M Y H:i:s', strtotime($expired)));
|
||||
$this->upsertCustomer($customer['username'], 'Expiration', date('d M Y H:i:s', strtotime($expired)));
|
||||
|
||||
// Mikrotik Spesific
|
||||
$this->upsertCustomer(
|
||||
$customer['username'],
|
||||
@ -293,12 +386,23 @@ class Radius
|
||||
);
|
||||
} else {
|
||||
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
|
||||
//$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'expiration', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Expiration', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
|
||||
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
|
||||
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
|
||||
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
|
||||
}
|
||||
|
||||
if ($plan['type'] == 'PPPOE') {
|
||||
if (!empty($customer['pppoe_ip']) && $expired != '') {
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-Pool', $plan['pool'], ':=');
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Address', $customer['pppoe_ip'], ':=');
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Netmask', '255.255.255.0', ':=');
|
||||
}else{
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-Pool', $plan['pool'], ':=');
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Address', '0.0.0.0', ':=');
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Netmask', '255.255.255.0', ':=');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -307,7 +411,8 @@ class Radius
|
||||
return false;
|
||||
}
|
||||
|
||||
public function customerUpsert($customer, $plan)
|
||||
|
||||
public function customerUpsert($customer, $plan) //Update or Insert customer plan
|
||||
{
|
||||
if ($plan['type'] == 'PPPOE') {
|
||||
$this->upsertCustomer($customer['username'], 'Cleartext-Password', (empty($customer['pppoe_password'])) ? $customer['password'] : $customer['pppoe_password']);
|
||||
@ -321,9 +426,9 @@ class Radius
|
||||
return true;
|
||||
}
|
||||
|
||||
private function delAtribute($tabel, $attribute, $key, $value)
|
||||
private function delAtribute($table, $attribute, $key, $value)
|
||||
{
|
||||
$r = $tabel->where_equal($key, $value)->whereEqual('attribute', $attribute)->findOne();
|
||||
$r = $table->where_equal($key, $value)->whereEqual('attribute', $attribute)->findOne();
|
||||
if ($r) $r->delete();
|
||||
}
|
||||
|
||||
@ -357,7 +462,8 @@ class Radius
|
||||
$r->attribute = $attr;
|
||||
$r->op = $op;
|
||||
$r->value = $value;
|
||||
return $r->save();
|
||||
$r->save();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* To insert or update existing customer Attribute
|
||||
@ -398,4 +504,31 @@ class Radius
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function addBandwidth($customer, $plan)
|
||||
{
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
|
||||
$unitdown = ($bw['rate_down_unit'] == 'Kbps') ? 'K' : 'M';
|
||||
$unitup = ($bw['rate_up_unit'] == 'Kbps') ? 'K' : 'M';
|
||||
|
||||
// TODO Burst mode [ 2M/1M 256K/128K 128K/64K 1s 1 64K/32K]
|
||||
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
// burst format: 2M/1M 256K/128K 128K/64K 1s 1 64K/32K
|
||||
$pattern = '/(\d+[KM])\/(\d+[KM]) (\d+[KM])\/(\d+[KM]) (\d+) (\d+) (\d+[KM])\/(\d+[KM])/';
|
||||
preg_match($pattern, $bw['burst'], $matches);
|
||||
if (count($matches) == 9) {
|
||||
|
||||
$burst = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown . ' ' . $matches[1] . '/' . $matches[2] . ' ' . $matches[3] . '/' . $matches[4] . ' ' . $matches[5] . ' ' . $matches[6] . ' ' . $matches[7] . '/' . $matches[8];
|
||||
$this->upsertCustomer($customer['username'], 'Mikrotik-Rate-Limit', $burst);
|
||||
} else {
|
||||
_log("Unexpected burst format for customer " . $customer['username']);
|
||||
}
|
||||
} else {
|
||||
//$this->upsertCustomer($customer['username'], 'Ascend-Data-Rate', $this->stringToInteger($bw['rate_up'] . $unitup) . "/" . $this->stringToInteger($bw['rate_down'] . $unitdown));
|
||||
$this->upsertCustomer($customer['username'], 'Mikrotik-Rate-Limit', $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -21,14 +21,28 @@ class RadiusRest {
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
// Remove Customer to Mikrotik/Device
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
// set zero data usage
|
||||
if ($plan['typebp'] == "Limited" && ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit")) {
|
||||
$cs = ORM::for_table("rad_acct")->where('username', $customer['username'])->findMany();
|
||||
foreach ($cs as $c) {
|
||||
$c->acctOutputOctets = 0;
|
||||
$c->acctInputOctets = 0;
|
||||
$c->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// customer change username
|
||||
public function change_username($from, $to)
|
||||
public function change_username($plan, $from, $to)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ class FileName {
|
||||
}
|
||||
|
||||
// customer change username
|
||||
public function change_username($from, $to)
|
||||
public function change_username($plan, $from, $to)
|
||||
{
|
||||
}
|
||||
|
||||
|
719
system/lan/arabic.json
Normal file
719
system/lan/arabic.json
Normal file
@ -0,0 +1,719 @@
|
||||
{
|
||||
"Log_in": "تسجيل الدخول",
|
||||
"Register": "تسجيل",
|
||||
"Announcement": "إعلان",
|
||||
"Registration_Info": "معلومات التسجيل",
|
||||
"Voucher_not_found__please_buy_voucher_befor_register": "القسيمة غير موجودة، يرجى شراء القسيمة قبل التسجيل",
|
||||
"Register_Success__You_can_login_now": "تم التسجيل بنجاح! يمكنك تسجيل الدخول الآن",
|
||||
"Log_in_to_Member_Panel": "تسجيل الدخول إلى لوحة الأعضاء",
|
||||
"Register_as_Member": "التسجيل كعضو",
|
||||
"Enter_Admin_Area": "دخول منطقة الإدارة",
|
||||
"PHPNuxBill": "PHPNuxBill",
|
||||
"Username": "اسم المستخدم",
|
||||
"Password": "كلمة المرور",
|
||||
"Passwords_does_not_match": "كلمات المرور غير متطابقة",
|
||||
"Account_already_axist": "الحساب موجود بالفعل",
|
||||
"Manage": "إدارة",
|
||||
"Submit": "إرسال",
|
||||
"Save_Changes": "حفظ التغييرات",
|
||||
"Cancel": "إلغاء",
|
||||
"Edit": "تعديل",
|
||||
"Delete": "حذف",
|
||||
"Welcome": "مرحباً",
|
||||
"Data_Created_Successfully": "تم إنشاء البيانات بنجاح",
|
||||
"Data_Updated_Successfully": "تم تحديث البيانات بنجاح",
|
||||
"Data_Deleted_Successfully": "تم حذف البيانات بنجاح",
|
||||
"Static_Pages": "صفحات ثابتة",
|
||||
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "فشل في حفظ الصفحة، تأكد من أنني أستطيع الكتابة إلى مجلد الصفحات، <i>chmod 664 pages/*.html<i>",
|
||||
"Saving_page_success": "تم حفظ الصفحة بنجاح",
|
||||
"Sometimes_you_need_to_refresh_3_times_until_content_change": "أحيانًا تحتاج إلى التحديث ثلاث مرات حتى يتغير المحتوى",
|
||||
"Dashboard": "لوحة التحكم",
|
||||
"Search_Customers___": "بحث العملاء...",
|
||||
"My_Account": "حسابي",
|
||||
"My_Profile": "ملفي الشخصي",
|
||||
"Settings": "الإعدادات",
|
||||
"Edit_Profile": "تعديل الملف الشخصي",
|
||||
"Change_Password": "تغيير كلمة المرور",
|
||||
"Logout": "تسجيل الخروج",
|
||||
"Services": "الخدمات",
|
||||
"Bandwidth_Plans": "خطط عرض النطاق الترددي",
|
||||
"Bandwidth_Name": "اسم عرض النطاق الترددي",
|
||||
"New_Bandwidth": "عرض نطاق ترددي جديد",
|
||||
"Edit_Bandwidth": "تعديل عرض النطاق الترددي",
|
||||
"Add_New_Bandwidth": "إضافة عرض نطاق ترددي جديد",
|
||||
"Rate_Download": "معدل التنزيل",
|
||||
"Rate_Upload": "معدل الرفع",
|
||||
"Name_Bandwidth_Already_Exist": "اسم عرض النطاق الترددي موجود بالفعل",
|
||||
"Hotspot_Plans": "خطط هوتسبوت",
|
||||
"PPPOE_Plans": "خطط PPPOE",
|
||||
"Plan_Name": "اسم الخطة",
|
||||
"New_Service_Plan": "خطة خدمة جديدة",
|
||||
"Add_Service_Plan": "إضافة خطة خدمة",
|
||||
"Edit_Service_Plan": "تعديل خطة الخدمة",
|
||||
"Name_Plan_Already_Exist": "اسم الخطة موجود بالفعل",
|
||||
"Plan_Type": "نوع الخطة",
|
||||
"Plan_Price": "سعر الخطة",
|
||||
"Limit_Type": "نوع الحد",
|
||||
"Unlimited": "غير محدود",
|
||||
"Limited": "محدود",
|
||||
"Time_Limit": "حد زمني",
|
||||
"Data_Limit": "حد البيانات",
|
||||
"Both_Limit": "كلاهما",
|
||||
"Plan_Validity": "صلاحية الخطة",
|
||||
"Select_Bandwidth": "اختر عرض النطاق الترددي",
|
||||
"Shared_Users": "المستخدمون المشتركين",
|
||||
"Choose_User_Type_Sales_to_disable_access_to_Settings": "اختر نوع المستخدم المبيعات لتعطيل الوصول إلى الإعدادات",
|
||||
"Current_Password": "كلمة المرور الحالية",
|
||||
"New_Password": "كلمة المرور الجديدة",
|
||||
"Administrator": "مدير",
|
||||
"Sales": "مبيعات",
|
||||
"Member": "عضو",
|
||||
"Confirm_New_Password": "تأكيد كلمة المرور الجديدة",
|
||||
"Confirm_Password": "تأكيد كلمة المرور",
|
||||
"Full_Name": "الاسم الكامل",
|
||||
"User_Type": "نوع المستخدم",
|
||||
"Address": "العنوان",
|
||||
"Created_On": "تم الإنشاء في",
|
||||
"Expires_On": "ينتهي في",
|
||||
"Phone_Number": "رقم الهاتف",
|
||||
"User_deleted_Successfully": "تم حذف المستخدم بنجاح",
|
||||
"Full_Administrator": "مدير كامل",
|
||||
"Keep_Blank_to_do_not_change_Password": "اتركه فارغًا لعدم تغيير كلمة المرور",
|
||||
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "اتركه فارغًا إذا كنت لا تريد عرض رمز العملة",
|
||||
"Theme_Style": "نمط السمة",
|
||||
"Theme_Color": "لون السمة",
|
||||
"Default_Language": "اللغة الافتراضية",
|
||||
"Network": "الشبكة",
|
||||
"Routers": "الموجهات",
|
||||
"IP_Pool": "مجمع IP",
|
||||
"New_Router": "موجه جديد",
|
||||
"Add_Router": "إضافة موجه",
|
||||
"Edit_Router": "تعديل الموجه",
|
||||
"Router_Name": "اسم الموجه",
|
||||
"IP_Address": "عنوان IP",
|
||||
"Router_Secret": "سر الموجه",
|
||||
"Description": "الوصف",
|
||||
"IP_Router_Already_Exist": "عنوان IP للموجه موجود بالفعل",
|
||||
"Name_Pool": "اسم المجمع",
|
||||
"Range_IP": "نطاق IP",
|
||||
"New_Pool": "مجمع جديد",
|
||||
"Add_Pool": "إضافة مجمع",
|
||||
"Edit_Pool": "تعديل المجمع",
|
||||
"Pool_Name_Already_Exist": "اسم المجمع موجود بالفعل",
|
||||
"Refill_Account": "إعادة شحن الحساب",
|
||||
"Recharge_Account": "إعادة شحن الحساب",
|
||||
"Select_Account": "اختر الحساب",
|
||||
"Service_Plan": "خطة الخدمة",
|
||||
"Recharge": "إعادة شحن",
|
||||
"Method": "طريقة",
|
||||
"Account_Created_Successfully": "تم إنشاء الحساب بنجاح",
|
||||
"Database_Status": "حالة قاعدة البيانات",
|
||||
"Total_Database_Size": "إجمالي حجم قاعدة البيانات",
|
||||
"Download_Database_Backup": "تحميل نسخة احتياطية من قاعدة البيانات",
|
||||
"Table_Name": "اسم الجدول",
|
||||
"Rows": "الصفوف",
|
||||
"Size": "الحجم",
|
||||
"Customer": "العميل",
|
||||
"Add_New_Contact": "إضافة جهة اتصال جديدة",
|
||||
"Edit_Contact": "تعديل جهة الاتصال",
|
||||
"List_Contact": "قائمة جهات الاتصال",
|
||||
"Manage_Contact": "إدارة جهات الاتصال",
|
||||
"Reports": "التقارير",
|
||||
"Daily_Reports": "التقارير اليومية",
|
||||
"Period_Reports": "تقارير الفترة",
|
||||
"All_Transactions": "جميع المعاملات",
|
||||
"Total_Income": "إجمالي الدخل",
|
||||
"All_Transactions_at_Date": "جميع المعاملات في التاريخ",
|
||||
"Export_for_Print": "تصدير للطباعة",
|
||||
"Print": "طباعة",
|
||||
"Export_to_PDF": "تصدير إلى PDF",
|
||||
"Click_Here_to_Print": "انقر هنا للطباعة",
|
||||
"You_can_use_html_tag": "يمكنك استخدام وسم HTML",
|
||||
"Date_Format": "تنسيق التاريخ",
|
||||
"Income_Today": "الدخل اليوم",
|
||||
"Income_This_Month": "الدخل هذا الشهر",
|
||||
"Users_Active": "المستخدمون النشطون",
|
||||
"Total_Users": "إجمالي المستخدمين",
|
||||
"Users": "المستخدمون",
|
||||
"Edit_User": "تعديل المستخدم",
|
||||
"Last_Login": "آخر تسجيل دخول",
|
||||
"Administrator_Users": "مستخدمو المدير",
|
||||
"Manage_Administrator": "إدارة المدير",
|
||||
"Add_New_Administrator": "إضافة مدير جديد",
|
||||
"Localisation": "الموقع",
|
||||
"Backup_Restore": "النسخ الاحتياطي / الاستعادة",
|
||||
"General_Settings": "الإعدادات العامة",
|
||||
"Date": "التاريخ",
|
||||
"Login_Successful": "تم تسجيل الدخول بنجاح",
|
||||
"Failed_Login": "فشل تسجيل الدخول",
|
||||
"Settings_Saved_Successfully": "تم حفظ الإعدادات بنجاح",
|
||||
"User_Updated_Successfully": "تم تحديث المستخدم بنجاح",
|
||||
"User_Expired__Today": "انتهت صلاحية المستخدم، اليوم",
|
||||
"Activity_Log": "سجل النشاطات",
|
||||
"View_Reports": "عرض التقارير",
|
||||
"View_All": "عرض الكل",
|
||||
"Number_of_Vouchers": "عدد القسائم",
|
||||
"Length_Code": "طول الكود",
|
||||
"Code_Voucher": "كود القسيمة",
|
||||
"Voucher": "قسيمة",
|
||||
"Hotspot_Voucher": "قسيمة هوتسبوت",
|
||||
"Status_Voucher": "حالة القسيمة",
|
||||
"Add_Vouchers": "إضافة قسائم",
|
||||
"Create_Vouchers_Successfully": "تم إنشاء القسائم بنجاح",
|
||||
"Generate": "توليد",
|
||||
"Print_side_by_side__it_will_easy_to_cut": "اطبع جنبًا إلى جنب، سيكون من السهل قصها",
|
||||
"From_Date": "من التاريخ",
|
||||
"To_Date": "إلى التاريخ",
|
||||
"New_Service": "خدمة جديدة",
|
||||
"Type": "نوع",
|
||||
"Finish": "إنهاء",
|
||||
"Application_Name__Company_Name": "اسم التطبيق / اسم الشركة",
|
||||
"This_Name_will_be_shown_on_the_Title": "سيتم عرض هذا الاسم في العنوان",
|
||||
"Next": "التالي",
|
||||
"Last": "الأخير",
|
||||
"Timezone": "المنطقة الزمنية",
|
||||
"Decimal_Point": "الفاصلة العشرية",
|
||||
"Thousands_Separator": "فاصل الآلاف",
|
||||
"Currency_Code": "رمز العملة",
|
||||
"Order_Voucher": "طلب قسيمة",
|
||||
"Voucher_Activation": "تفعيل القسيمة",
|
||||
"List_Activated_Voucher": "قائمة القسائم المفعلة",
|
||||
"Enter_voucher_code_here": "أدخل رمز القسيمة هنا",
|
||||
"Private_Message": "رسالة خاصة",
|
||||
"Inbox": "البريد الوارد",
|
||||
"Outbox": "البريد الصادر",
|
||||
"Compose": "إنشاء",
|
||||
"Send_to": "إرسال إلى",
|
||||
"Title": "العنوان",
|
||||
"Message": "الرسالة",
|
||||
"Your_Account_Information": "معلومات حسابك",
|
||||
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "مرحبًا بك في صفحة أعضاء اللوحة، في هذه الصفحة يمكنك:",
|
||||
"Invalid_Username_or_Password": "اسم المستخدم أو كلمة المرور غير صالحة",
|
||||
"You_do_not_have_permission_to_access_this_page": "ليس لديك إذن للوصول إلى هذه الصفحة",
|
||||
"Incorrect_Current_Password": "كلمة المرور الحالية غير صحيحة",
|
||||
"Password_changed_successfully__Please_login_again": "تم تغيير كلمة المرور بنجاح، يرجى تسجيل الدخول مرة أخرى",
|
||||
"All_field_is_required": "جميع الحقول مطلوبة",
|
||||
"Voucher_Not_Valid": "القسيمة غير صالحة",
|
||||
"Activation_Vouchers_Successfully": "تم تفعيل القسائم بنجاح",
|
||||
"Data_Not_Found": "لم يتم العثور على البيانات",
|
||||
"Search_by_Username": "البحث حسب اسم المستخدم",
|
||||
"Search_by_Name": "البحث حسب الاسم",
|
||||
"Search_by_Code_Voucher": "البحث حسب كود القسيمة",
|
||||
"Search": "بحث",
|
||||
"Select_a_customer": "اختر عميلاً",
|
||||
"Select_Routers": "اختر الموجهات",
|
||||
"Select_Plans": "اختر الخطط",
|
||||
"Select_Pool": "اختر المجمع",
|
||||
"Hrs": "ساعات",
|
||||
"Mins": "دقائق",
|
||||
"Days": "أيام",
|
||||
"Months": "أشهر",
|
||||
"Add_Language": "إضافة لغة",
|
||||
"Language_Name": "اسم اللغة",
|
||||
"Folder_Name": "اسم المجلد",
|
||||
"Translator": "المترجم",
|
||||
"Language_Name_Already_Exist": "اسم اللغة موجود بالفعل",
|
||||
"Payment_Gateway": "بوابة الدفع",
|
||||
"Community": "المجتمع",
|
||||
"1_user_can_be_used_for_many_devices_": "هل يمكن استخدام مستخدم واحد للعديد من الأجهزة؟",
|
||||
"Cannot_be_change_after_saved": "لا يمكن تغييرها بعد الحفظ",
|
||||
"Explain_Coverage_of_router": "شرح تغطية الموجه",
|
||||
"Name_of_Area_that_router_operated": "اسم المنطقة التي يعمل بها الموجه",
|
||||
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "عنوان URL لإشعار الدفع، عنوان URL لإشعار المتكرر، عنوان URL لإشعار دفع الحساب",
|
||||
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "عنوان URL لإعادة التوجيه بعد الانتهاء، عنوان URL لإعادة التوجيه بعد عدم الانتهاء، عنوان URL لإعادة التوجيه عند حدوث خطأ",
|
||||
"Status": "الحالة",
|
||||
"Plan_Not_found": "الخطة غير موجودة",
|
||||
"Failed_to_create_transaction_": "فشل في إنشاء المعاملة.",
|
||||
"Seller_has_not_yet_setup_Xendit_payment_gateway": "البائع لم يقم بعد بإعداد بوابة الدفع Xendit",
|
||||
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "المدير لم يقم بعد بإعداد بوابة الدفع Xendit، يرجى إخبار المدير",
|
||||
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "لديك معاملة غير مدفوعة، قم بإلغائها أو دفعها.",
|
||||
"Transaction_Not_found": "المعاملة غير موجودة",
|
||||
"Cancel_it_": "هل تريد إلغاءها؟",
|
||||
"expired": "منتهية الصلاحية",
|
||||
"Check_for_Payment": "التحقق من الدفع",
|
||||
"Transaction_still_unpaid_": "المعاملة لا تزال غير مدفوعة.",
|
||||
"Paid_Date": "تاريخ الدفع",
|
||||
"Transaction_has_been_paid_": "تم دفع المعاملة.",
|
||||
"PAID": "مدفوع",
|
||||
"CANCELED": "ملغي",
|
||||
"UNPAID": "غير مدفوع",
|
||||
"PAY_NOW": "ادفع الآن",
|
||||
"Buy_Hotspot_Plan": "شراء خطة هوتسبوت",
|
||||
"Buy_PPOE_Plan": "شراء خطة PPOE",
|
||||
"Package": "الحزمة",
|
||||
"Order_Internet_Package": "طلب حزمة إنترنت",
|
||||
"Unknown_Command_": "أمر غير معروف.",
|
||||
"Checking_payment": "التحقق من الدفع",
|
||||
"Create_Transaction_Success": "تم إنشاء المعاملة بنجاح",
|
||||
"You_have_unpaid_transaction": "لديك معاملة غير مدفوعة",
|
||||
"TripayPayment_Channel": "قناة الدفع Tripay",
|
||||
"Payment_Channel": "قناة الدفع",
|
||||
"Payment_check_failed_": "فشل التحقق من الدفع.",
|
||||
"Order_Package": "طلب الحزمة",
|
||||
"Transactions": "المعاملات",
|
||||
"Payments": "المدفوعات",
|
||||
"History": "التاريخ",
|
||||
"Order_History": "تاريخ الطلبات",
|
||||
"Gateway": "البوابة",
|
||||
"Date_Done": "تاريخ الإنجاز",
|
||||
"Unpaid_Order": "طلب غير مدفوع",
|
||||
"Payment_Gateway_Not_Found": "لم يتم العثور على بوابة الدفع",
|
||||
"Payment_Gateway_saved_successfully": "تم حفظ بوابة الدفع بنجاح",
|
||||
"ORDER": "طلب",
|
||||
"Package_History": "تاريخ الحزم",
|
||||
"Buy_History": "تاريخ الشراء",
|
||||
"Activation_History": "تاريخ التفعيل",
|
||||
"Buy_Package": "شراء حزمة",
|
||||
"Email": "البريد الإلكتروني",
|
||||
"Company_Footer": "تذييل الشركة",
|
||||
"Will_show_below_user_pages": "سيظهر أسفل صفحات المستخدم",
|
||||
"Request_OTP": "طلب رمز التحقق",
|
||||
"Verification_Code": "رمز التحقق",
|
||||
"SMS_Verification_Code": "رمز التحقق عبر الرسائل القصيرة",
|
||||
"Please_enter_your_email_address": "يرجى إدخال عنوان بريدك الإلكتروني",
|
||||
"Failed_to_create_Paypal_transaction_": "فشل في إنشاء معاملة Paypal.",
|
||||
"Plugin": "الإضافة",
|
||||
"Plugin_Manager": "مدير الإضافات",
|
||||
"User_Notification": "إشعار المستخدم",
|
||||
"Expired_Notification": "إشعار انتهاء الصلاحية",
|
||||
"User_will_get_notification_when_package_expired": "سيحصل المستخدم على إشعار عند انتهاء صلاحية الحزمة",
|
||||
"Expired_Notification_Message": "رسالة إشعار انتهاء الصلاحية",
|
||||
"Payment_Notification": "إشعار الدفع",
|
||||
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "سيحصل المستخدم على إشعار بالفاتورة عند شراء حزمة أو إعادة تعبئة الحزمة",
|
||||
"Current_IP": "عنوان IP الحالي",
|
||||
"Current_MAC": "عنوان MAC الحالي",
|
||||
"Login_Status": "حالة تسجيل الدخول",
|
||||
"Login_Request_successfully": "تم طلب تسجيل الدخول بنجاح",
|
||||
"Logout_Request_successfully": "تم طلب تسجيل الخروج بنجاح",
|
||||
"Disconnect_Internet_": "قطع الاتصال بالإنترنت؟",
|
||||
"Not_Online__Login_now_": "غير متصل، تسجيل الدخول الآن؟",
|
||||
"You_are_Online__Logout_": "أنت متصل، تسجيل الخروج؟",
|
||||
"Connect_to_Internet_": "الاتصال بالإنترنت؟",
|
||||
"Your_account_not_connected_to_internet": "حسابك غير متصل بالإنترنت",
|
||||
"Failed_to_create_transaction__": "فشل في إنشاء المعاملة.",
|
||||
"Failed_to_check_status_transaction__": "فشل في التحقق من حالة المعاملة.",
|
||||
"Disable_Voucher": "تعطيل القسيمة",
|
||||
"Balance": "الرصيد",
|
||||
"Balance_System": "نظام الرصيد",
|
||||
"Enable_System": "تمكين النظام",
|
||||
"Allow_Transfer": "السماح بالنقل",
|
||||
"Telegram_Notification": "إشعار تليغرام",
|
||||
"SMS_OTP_Registration": "تسجيل رمز التحقق عبر الرسائل القصيرة",
|
||||
"Whatsapp_Notification": "إشعار واتساب",
|
||||
"Tawk_to_Chat_Widget": "أداة الدردشة Tawk.to",
|
||||
"Invoice": "الفاتورة",
|
||||
"Country_Code_Phone": "رمز الهاتف للبلد",
|
||||
"Voucher_activation_menu_will_be_hidden": "سيتم إخفاء قائمة تفعيل القسيمة",
|
||||
"Customer_can_deposit_money_to_buy_voucher": "يمكن للعميل إيداع الأموال لشراء القسيمة",
|
||||
"Allow_balance_transfer_between_customers": "السماح بنقل الرصيد بين العملاء",
|
||||
"Reminder_Notification": "إشعار التذكير",
|
||||
"Reminder_Notification_Message": "رسالة إشعار التذكير",
|
||||
"Reminder_7_days": "تذكير 7 أيام",
|
||||
"Reminder_3_days": "تذكير 3 أيام",
|
||||
"Reminder_1_day": "تذكير يوم واحد",
|
||||
"PPPOE_Password": "كلمة مرور PPPOE",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "لا يمكن للمستخدم تغيير هذا، فقط المدير. إذا كان فارغًا، سيتم استخدام كلمة مرور المستخدم",
|
||||
"Invoice_Balance_Message": "رسالة رصيد الفاتورة",
|
||||
"Invoice_Notification_Payment": "إشعار دفع الفاتورة",
|
||||
"Balance_Notification_Payment": "إشعار دفع الرصيد",
|
||||
"Balance_Plans": "خطط الرصيد",
|
||||
"Buy_Balance": "شراء رصيد",
|
||||
"Price": "السعر",
|
||||
"Validity": "الصلاحية",
|
||||
"Disable_auto_renewal_": "تعطيل التجديد التلقائي؟",
|
||||
"Auto_Renewal_On": "التجديد التلقائي مفعل",
|
||||
"Enable_auto_renewal_": "تمكين التجديد التلقائي؟",
|
||||
"Auto_Renewal_Off": "التجديد التلقائي معطل",
|
||||
"Refill_Balance": "إعادة شحن الرصيد",
|
||||
"Invoice_Footer": "تذييل الفاتورة",
|
||||
"Pay_With_Balance": "الدفع بالرصيد",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "ادفع هذا بالرصيد؟ سيتم الكتابة فوق الحزمة النشطة الخاصة بك",
|
||||
"Success_to_buy_package": "تم شراء الحزمة بنجاح",
|
||||
"Auto_Renewal": "التجديد التلقائي",
|
||||
"View": "عرض",
|
||||
"Back": "العودة",
|
||||
"Active": "نشط",
|
||||
"Transfer_Balance": "نقل الرصيد",
|
||||
"Send_your_balance_": "إرسال رصيدك؟",
|
||||
"Send": "إرسال",
|
||||
"Cannot_send_to_yourself": "لا يمكن الإرسال إلى نفسك",
|
||||
"Sending_balance_success": "تم إرسال الرصيد بنجاح",
|
||||
"From": "من",
|
||||
"To": "إلى",
|
||||
"insufficient_balance": "رصيد غير كافٍ",
|
||||
"Send_Balance": "إرسال الرصيد",
|
||||
"Received_Balance": "الرصيد المستلم",
|
||||
"Minimum_Balance_Transfer": "الحد الأدنى لنقل الرصيد",
|
||||
"Minimum_Transfer": "الحد الأدنى للنقل",
|
||||
"Company_Logo": "شعار الشركة",
|
||||
"Expired_IP_Pool": "مجمع IP منتهي الصلاحية",
|
||||
"Proxy": "الوكيل",
|
||||
"Proxy_Server": "خادم الوكيل",
|
||||
"Proxy_Server_Login": "تسجيل دخول خادم الوكيل",
|
||||
"Hotspot_Plan": "خطة هوتسبوت",
|
||||
"PPPOE_Plan": "خطة PPPOE",
|
||||
"UNKNOWN": "غير معروف",
|
||||
"Are_You_Sure_": "هل أنت متأكد؟",
|
||||
"Success_to_send_package": "تم إرسال الحزمة بنجاح",
|
||||
"Target_has_active_plan__different_with_current_plant_": "الهدف لديه خطة نشطة، تختلف عن الخطة الحالية.",
|
||||
"Recharge_a_friend": "إعادة شحن صديق",
|
||||
"Buy_for_friend": "شراء لصديق",
|
||||
"Buy_this_for_friend_account_": "شراء هذا لحساب صديقك؟",
|
||||
"Review_package_before_recharge": "مراجعة الحزمة قبل الشحن",
|
||||
"Activate": "تفعيل",
|
||||
"Deactivate": "تعطيل",
|
||||
"Sync": "مزامنة",
|
||||
"Failed_to_create_PaymeTrust_transaction_": "فشل في إنشاء معاملة PaymeTrust.",
|
||||
"Location": "الموقع",
|
||||
"Radius_Plans": "خطط Radius",
|
||||
"Change_title_in_user_Plan_order": "تغيير العنوان في طلب خطة المستخدم",
|
||||
"Logs": "السجلات",
|
||||
"Voucher_Format": "تنسيق القسيمة",
|
||||
"Resend_To_Customer": "إعادة الإرسال للعميل",
|
||||
"Your_friend_do_not_have_active_package": "صديقك لا يملك حزمة نشطة",
|
||||
"Service_Type": "نوع الخدمة",
|
||||
"Others": "أخرى",
|
||||
"PPPoE": "PPPoE",
|
||||
"Hotspot": "هوتسبوت",
|
||||
"Disable_Registration": "تعطيل التسجيل",
|
||||
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "العميل يسجل الدخول فقط باستخدام رقم الهاتف وكود القسيمة، ستكون القسيمة كلمة المرور",
|
||||
"Login___Activate_Voucher": "تسجيل الدخول / تفعيل القسيمة",
|
||||
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "بعد أن يقوم العميل بتفعيل القسيمة أو تسجيل الدخول، سيتم إعادة توجيه العميل إلى هذا الرابط",
|
||||
"Voucher_Prefix": "بادئة القسيمة",
|
||||
"Voucher_activation_success__now_you_can_login": "تم تفعيل القسيمة بنجاح، الآن يمكنك تسجيل الدخول",
|
||||
"Buy_this__your_active_package_will_be_overwritten": "شراء هذا؟ سيتم الكتابة فوق الحزمة النشطة الخاصة بك",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "ادفع هذا بالرصيد؟ سيتم الكتابة فوق الحزمة النشطة الخاصة بك",
|
||||
"Buy_this__your_active_package_will_be_overwrite": "شراء هذا؟ سيتم الكتابة فوق الحزمة النشطة الخاصة بك",
|
||||
"Monthly_Registered_Customers": "العملاء المسجلين شهريًا",
|
||||
"Total_Monthly_Sales": "إجمالي المبيعات الشهرية",
|
||||
"Active_Users": "المستخدمون النشطون",
|
||||
"All_Users_Insights": "رؤى جميع المستخدمين",
|
||||
"SuperAdmin": "مدير النظام",
|
||||
"Radius": "Radius",
|
||||
"Radius_NAS": "Radius NAS",
|
||||
"Translation": "الترجمة",
|
||||
"Translation_saved_Successfully": "تم حفظ الترجمة بنجاح",
|
||||
"Language_Editor": "محرر اللغة",
|
||||
"year": "سنة",
|
||||
"month": "شهر",
|
||||
"week": "أسبوع",
|
||||
"day": "يوم",
|
||||
"hour": "ساعة",
|
||||
"minute": "دقيقة",
|
||||
"second": "ثانية",
|
||||
"Attributes": "السمات",
|
||||
"Profile": "الملف الشخصي",
|
||||
"Phone": "الهاتف",
|
||||
"City": "المدينة",
|
||||
"Sub_District": "الحي",
|
||||
"Ward": "الحي",
|
||||
"Credentials": "بيانات الاعتماد",
|
||||
"Agent": "الوكيل",
|
||||
"This_Token_will_act_as_SuperAdmin_Admin": "سيعمل هذا الرمز المميز كمدير النظام / المدير",
|
||||
"Login": "تسجيل الدخول",
|
||||
"Expired_Action": "إجراء منتهي الصلاحية",
|
||||
"Expired_Address_List_Name": "اسم قائمة العناوين المنتهية الصلاحية",
|
||||
"Address_List": "قائمة العناوين",
|
||||
"Optional": "اختياري",
|
||||
"Generated_By": "تم إنشاؤه بواسطة",
|
||||
"Admin": "مدير",
|
||||
"Password_should_be_minimum_6_characters": "يجب أن تكون كلمة المرور مكونة من 6 أحرف على الأقل",
|
||||
"Add_User": "إضافة مستخدم",
|
||||
"Send_Notification": "إرسال إشعار",
|
||||
"Code": "الكود",
|
||||
"Send_To_Customer": "إرسال للعميل",
|
||||
"Prev": "السابق",
|
||||
"Voucher_Not_Found": "القسيمة غير موجودة",
|
||||
"Miscellaneous": "متفرقات",
|
||||
"OTP_Required": "رمز التحقق مطلوب",
|
||||
"Change": "تغيير",
|
||||
"Change_Phone_Number": "تغيير رقم الهاتف",
|
||||
"Current_Number": "الرقم الحالي",
|
||||
"New_Number": "الرقم الجديد",
|
||||
"Input_your_phone_number": "أدخل رقم هاتفك",
|
||||
"OTP": "رمز التحقق",
|
||||
"Enter_OTP_that_was_sent_to_your_phone": "أدخل رمز التحقق الذي تم إرساله إلى هاتفك",
|
||||
"Update": "تحديث",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number": "رمز التحقق مطلوب عندما يريد المستخدم تغيير رقم الهاتف",
|
||||
"Rate": "المعدل",
|
||||
"Burst": "الانفجار",
|
||||
"Editing_Bandwidth_will_not_automatically_update_the_plan__you_need_to_edit_the_plan_then_save_again": "تحرير عرض النطاق الترددي لن يحدث تحديثًا تلقائيًا للخطة، تحتاج إلى تحرير الخطة ثم الحفظ مرة أخرى",
|
||||
"OTP_Method": "طريقة رمز التحقق",
|
||||
"SMS": "الرسائل القصيرة",
|
||||
"WhatsApp": "واتساب",
|
||||
"SMS_and_WhatsApp": "الرسائل القصيرة وواتساب",
|
||||
"The_method_which_OTP_will_be_sent_to_user": "الطريقة التي سيتم إرسال رمز التحقق بها إلى المستخدم",
|
||||
"Report_Viewer": "عارض التقارير",
|
||||
"Super_Administrator": "مدير النظام الأعلى",
|
||||
"Send_To": "إرسال إلى",
|
||||
"Resend": "إعادة الإرسال",
|
||||
"Alert": "تنبيه",
|
||||
"success": "نجاح",
|
||||
"Click_Here": "انقر هنا",
|
||||
"danger": "خطر",
|
||||
"Logout_Successful": "تم تسجيل الخروج بنجاح",
|
||||
"warning": "تحذير",
|
||||
"Users_Announcement": "إعلان للمستخدمين",
|
||||
"Customer_Announcement": "إعلان للعملاء",
|
||||
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 فترة = 1 شهر، تنتهي في 20 من كل شهر",
|
||||
"Period": "الفترة",
|
||||
"Add": "إضافة",
|
||||
"Select_Payment_Gateway": "اختر بوابة الدفع",
|
||||
"Available_Payment_Gateway": "بوابة الدفع المتاحة",
|
||||
"Pay_Now": "ادفع الآن",
|
||||
"Please_select_Payment_Gateway": "يرجى اختيار بوابة الدفع",
|
||||
"Payment_Gateway_Deleted": "تم حذف بوابة الدفع",
|
||||
"Payment_Gateway_not_set__please_set_it_in_Settings": "بوابة الدفع غير محددة، يرجى إعدادها في الإعدادات",
|
||||
"Failed_to_create_Transaction__": "فشل في إنشاء المعاملة.",
|
||||
"Show_To_Customer": "عرض للعميل",
|
||||
"Using": "باستخدام",
|
||||
"Default": "افتراضي",
|
||||
"Customer_Balance": "رصيد العميل",
|
||||
"Vouchers": "القسائم",
|
||||
"Refill_Customer": "إعادة شحن العميل",
|
||||
"Recharge_Customer": "إعادة شحن العميل",
|
||||
"Plans": "الخطط",
|
||||
"PPPOE": "PPPOE",
|
||||
"Bandwidth": "عرض النطاق الترددي",
|
||||
"Customers": "العملاء",
|
||||
"Actives": "النشطون",
|
||||
"Name": "الاسم",
|
||||
"Confirm": "تأكيد",
|
||||
"Plan": "الخطة",
|
||||
"Total": "الإجمالي",
|
||||
"Current_Cycle": "الدورة الحالية",
|
||||
"Additional_Cost": "التكلفة الإضافية",
|
||||
"Remaining": "المتبقي",
|
||||
"Not_Found": "غير موجود",
|
||||
"Cash": "نقدًا",
|
||||
"Payment_not_found": "لم يتم العثور على الدفع",
|
||||
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "إذا كان لدى صديقك تكلفة إضافية، ستدفعها أيضًا",
|
||||
"Cache_cleared_successfully_": "تم مسح الذاكرة المؤقتة بنجاح!",
|
||||
"Paid": "مدفوع",
|
||||
"Send_Message": "إرسال رسالة",
|
||||
"Send_Personal_Message": "إرسال رسالة شخصية",
|
||||
"Send_Via": "إرسال عبر",
|
||||
"Compose_your_message___": "أنشئ رسالتك...",
|
||||
"Use_placeholders_": "استخدم العناصر النائبة:",
|
||||
"Customer_Name": "اسم العميل",
|
||||
"Customer_Username": "اسم المستخدم للعميل",
|
||||
"Customer_Phone": "هاتف العميل",
|
||||
"Your_Company_Name": "اسم شركتك",
|
||||
"Message_Sent_Successfully": "تم إرسال الرسالة بنجاح",
|
||||
"Send_Bulk_Message": "إرسال رسالة مجمعة",
|
||||
"Group": "المجموعة",
|
||||
"All_Customers": "جميع العملاء",
|
||||
"New_Customers": "عملاء جدد",
|
||||
"Expired_Customers": "عملاء منتهية صلاحيتهم",
|
||||
"Active_Customers": "العملاء النشطون",
|
||||
"Map": "الخريطة",
|
||||
"Customer_Location": "موقع العميل",
|
||||
"Account_Type": "نوع الحساب",
|
||||
"Coordinates": "الإحداثيات",
|
||||
"Latitude_and_Longitude_coordinates_for_map_must_be_separate_with_comma____": "يجب أن تكون إحداثيات خطوط العرض والطول للخريطة مفصولة بفاصلة",
|
||||
"Customer_Geo_Location_Information": "معلومات الموقع الجغرافي للعميل",
|
||||
"List": "القائمة",
|
||||
"Lists": "القوائم",
|
||||
"Single_Customer": "عميل واحد",
|
||||
"Bulk_Customers": "عملاء مجمعين",
|
||||
"Message_per_time": "رسالة لكل مرة",
|
||||
"5_Messages": "5 رسائل",
|
||||
"10_Messages": "10 رسائل",
|
||||
"15_Messages": "15 رسالة",
|
||||
"20_Messages": "20 رسالة",
|
||||
"30_Messages": "30 رسالة",
|
||||
"40_Messages": "40 رسالة",
|
||||
"50_Messages": "50 رسالة",
|
||||
"60_Messages": "60 رسالة",
|
||||
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "استخدم 20 وما فوق إذا كنت ترسل لجميع العملاء لتجنب انتهاء مهلة الخادم",
|
||||
"Delay": "التأخير",
|
||||
"No_Delay": "بدون تأخير",
|
||||
"5_Seconds": "5 ثوانٍ",
|
||||
"10_Seconds": "10 ثوانٍ",
|
||||
"15_Seconds": "15 ثانية",
|
||||
"20_Seconds": "20 ثانية",
|
||||
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "استخدم 5 ثوانٍ على الأقل إذا كنت ترسل لجميع العملاء لتجنب الحظر من مزود الرسائل الخاص بك",
|
||||
"Testing__if_checked_no_real_message_is_sent_": "اختبار [إذا تم التحقق منه، لن يتم إرسال رسالة حقيقية]",
|
||||
"All_fields_are_required": "جميع الحقول مطلوبة",
|
||||
"Personal": "شخصي",
|
||||
"Email_Notification": "إشعار البريد الإلكتروني",
|
||||
"Router_Name___Location": "اسم الموجه / الموقع",
|
||||
"Plan_Category": "فئة الخطة",
|
||||
"ID": "المعرف",
|
||||
"Internet_Plan": "خطة الإنترنت",
|
||||
"Privacy_Policy": "سياسة الخصوصية",
|
||||
"Terms_and_Conditions": "الشروط والأحكام",
|
||||
"Contact": "الاتصال",
|
||||
"will_be_replaced_with_Customer_Name": "سيتم استبداله باسم العميل",
|
||||
"will_be_replaced_with_Customer_username": "سيتم استبداله باسم المستخدم للعميل",
|
||||
"will_be_replaced_with_Package_name": "سيتم استبداله باسم الحزمة",
|
||||
"will_be_replaced_with_Package_price": "سيتم استبداله بسعر الحزمة",
|
||||
"additional_bills_for_customers": "فواتير إضافية للعملاء",
|
||||
"will_be_replaced_with_Expiration_date": "سيتم استبداله بتاريخ انتهاء الصلاحية",
|
||||
"Your_Company_Name_at_Settings": "اسم شركتك في الإعدادات",
|
||||
"Your_Company_Address_at_Settings": "عنوان شركتك في الإعدادات",
|
||||
"Your_Company_Phone_at_Settings": "هاتف شركتك في الإعدادات",
|
||||
"Invoice_number": "رقم الفاتورة",
|
||||
"Date_invoice_created": "تاريخ إنشاء الفاتورة",
|
||||
"Payment_gateway_user_paid_from": "بوابة الدفع التي دفع منها المستخدم",
|
||||
"Payment_channel_user_paid_from": "قناة الدفع التي دفع منها المستخدم",
|
||||
"is_Hotspot_or_PPPOE": "هل هو هوتسبوت أو PPPOE",
|
||||
"Internet_Package": "حزمة الإنترنت",
|
||||
"Internet_Package_Prices": "أسعار حزمة الإنترنت",
|
||||
"Receiver_name": "اسم المستلم",
|
||||
"Username_internet": "اسم المستخدم للإنترنت",
|
||||
"User_password": "كلمة مرور المستخدم",
|
||||
"Expired_datetime": "تاريخ ووقت انتهاء الصلاحية",
|
||||
"For_Notes_by_admin": "للملاحظات من قبل المدير",
|
||||
"Transaction_datetime": "تاريخ ووقت المعاملة",
|
||||
"Balance_Before": "الرصيد قبل",
|
||||
"Balance_After": "الرصيد بعد",
|
||||
"how_much_balance_have_been_send": "كم من الرصيد تم إرساله",
|
||||
"Current_Balance": "الرصيد الحالي",
|
||||
"Sender_name": "اسم المرسل",
|
||||
"how_much_balance_have_been_received": "كم من الرصيد تم استلامه",
|
||||
"Extend_Postpaid_Expiration": "تمديد انتهاء الدفع المسبق",
|
||||
"Allow_Extend": "السماح بالتمديد",
|
||||
"Extend_Days": "تمديد الأيام",
|
||||
"Confirmation_Message": "رسالة التأكيد",
|
||||
"You_are_already_logged_in": "أنت مسجل الدخول بالفعل",
|
||||
"Extend": "تمديد",
|
||||
"Created___Expired": "تم الإنشاء / منتهي الصلاحية",
|
||||
"Bank_Transfer": "تحويل بنكي",
|
||||
"Recharge_Using": "إعادة الشحن باستخدام",
|
||||
"ago": "منذ",
|
||||
"Disabled": "معطل",
|
||||
"Banned": "محظور",
|
||||
"Customer_cannot_login_again": "لا يمكن للعميل تسجيل الدخول مرة أخرى",
|
||||
"Customer_can_login_but_cannot_buy_internet_plan__Admin_cannot_recharge_customer": "يمكن للعميل تسجيل الدخول ولكن لا يمكنه شراء خطة الإنترنت، لا يمكن للمدير إعادة شحن العميل",
|
||||
"Don_t_forget_to_deactivate_all_active_plan_too": "لا تنسى تعطيل جميع الخطط النشطة أيضًا",
|
||||
"Ascending": "تصاعدي",
|
||||
"Descending": "تنازلي",
|
||||
"Created_Date": "تاريخ الإنشاء",
|
||||
"Inactive": "غير نشط",
|
||||
"Suspended": "معلق",
|
||||
"Query": "استعلام",
|
||||
"Notes": "ملاحظات",
|
||||
"This_account_status": "حالة هذا الحساب",
|
||||
"Maintenance_Mode": "وضع الصيانة",
|
||||
"Maintenance_Mode_Settings": "إعدادات وضع الصيانة",
|
||||
"Status_": "الحالة:",
|
||||
"End_Date_": "تاريخ الانتهاء:",
|
||||
"Save": "حفظ",
|
||||
"Site_is_temporarily_unavailable_": "الموقع غير متاح مؤقتًا.",
|
||||
"Scheduled_maintenance_is_currently_in_progress__Please_check_back_soon_": "الصيانة المجدولة جارية حاليًا. يرجى التحقق مرة أخرى قريبًا.",
|
||||
"We_apologize_for_any_inconvenience_": "نعتذر عن أي إزعاج.",
|
||||
"The": "الـ",
|
||||
"Team": "الفريق",
|
||||
"Extend_Package_Expiry": "تمديد انتهاء الحزمة",
|
||||
"No": "لا",
|
||||
"Yes": "نعم",
|
||||
"If_user_buy_same_internet_plan__expiry_date_will_extend": "إذا اشترى المستخدم نفس خطة الإنترنت، سيتم تمديد تاريخ انتهاء الصلاحية",
|
||||
"Tax_System": "نظام الضرائب",
|
||||
"Enable_Tax_System": "تمكين نظام الضرائب",
|
||||
"Tax_will_be_calculated_in_Internet_Plan_Price": "سيتم حساب الضريبة في سعر خطة الإنترنت",
|
||||
"Tax_Rate": "معدل الضريبة",
|
||||
"0_5_": "0.5%",
|
||||
"1_": "1%",
|
||||
"1_5_": "1.5%",
|
||||
"2_": "2%",
|
||||
"5_": "5%",
|
||||
"10_": "10%",
|
||||
"Custom": "مخصص",
|
||||
"Tax_Rates_in_percentage": "معدلات الضريبة بالنسبة المئوية",
|
||||
"Custom_Tax_Rate": "معدل الضريبة المخصص",
|
||||
"Enter_Custom_Tax_Rate": "أدخل معدل الضريبة المخصص",
|
||||
"Enter_the_custom_tax_rate__e_g___3_75_for_3_75__": "أدخل معدل الضريبة المخصص (مثال: 3.75 لـ 3.75%)",
|
||||
"Additional_Information": "معلومات إضافية",
|
||||
"City_of_Resident": "مدينة الإقامة",
|
||||
"District": "المنطقة",
|
||||
"State": "الولاية",
|
||||
"State_of_Resident": "ولاية الإقامة",
|
||||
"Zip": "الرمز البريدي",
|
||||
"Zip_Code": "الرمز البريدي",
|
||||
"Local_IP": "IP المحلي",
|
||||
"Device": "الجهاز",
|
||||
"Expired_Internet_Plan": "خطة الإنترنت المنتهية الصلاحية",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_plan": "عند انتهاء الصلاحية، سيتم نقل العميل إلى خطة الإنترنت المحددة",
|
||||
"Plugin_Installer": "مثبت الإضافة",
|
||||
"Expired_Date": "تاريخ الانتهاء",
|
||||
"Expired": "منتهية الصلاحية",
|
||||
"Time": "الوقت",
|
||||
"Data": "البيانات",
|
||||
"Category": "الفئة",
|
||||
"later": "لاحقًا",
|
||||
"Package_Details": "تفاصيل الحزمة",
|
||||
"Summary": "الملخص",
|
||||
"Devices_Not_Found": "لم يتم العثور على الأجهزة",
|
||||
"Income_reset_date": "تاريخ إعادة ضبط الدخل",
|
||||
"Devices": "الأجهزة",
|
||||
"Documentation": "التوثيق",
|
||||
"Hotspot_Auth_Method": "طريقة المصادقة لهوتسبوت",
|
||||
"Api": "API",
|
||||
"Http_Chap": "Http-Chap",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "طريقة المصادقة لهوتسبوت. تأكد من تغيير صفحة تسجيل الدخول لهوتسبوت.",
|
||||
"Business": "الأعمال",
|
||||
"Source": "المصدر",
|
||||
"Destination": "الوجهة",
|
||||
"Activate_Voucher": "تفعيل القسيمة",
|
||||
"Voucher_invalid": "القسيمة غير صالحة",
|
||||
"Account_Not_Found": "الحساب غير موجود",
|
||||
"Internet_Voucher_Expired": "القسيمة الإنترنت منتهية الصلاحية",
|
||||
"Additional_Billing": "الفواتير الإضافية",
|
||||
"Used_Date": "تاريخ الاستخدام",
|
||||
"Filter": "التصفية",
|
||||
"Start_time": "وقت البدء",
|
||||
"End_Time": "وقت الانتهاء",
|
||||
"Internet_Plans": "خطط الإنترنت",
|
||||
"Methods": "الطرق",
|
||||
"Hap_Lite": "Hap Lite",
|
||||
"balance": "الرصيد",
|
||||
"radius": "Radius",
|
||||
"Start_Date": "تاريخ البدء",
|
||||
"End_Date": "تاريخ الانتهاء",
|
||||
"New_Version_Notification": "إشعار الإصدار الجديد",
|
||||
"Enabled": "مفعل",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "هذا لإخطارك عندما تكون هناك تحديثات جديدة متاحة",
|
||||
"Number": "الرقم",
|
||||
"NAS": "NAS",
|
||||
"MAC_Address": "عنوان MAC",
|
||||
"Uptime": "وقت التشغيل",
|
||||
"Upload": "الرفع",
|
||||
"Download": "التنزيل",
|
||||
"CPU_Load": "حمل المعالج",
|
||||
"Temperature": "درجة الحرارة",
|
||||
"Voltage": "الجهد الكهربائي",
|
||||
"Wireless_Status": "حالة اللاسلكي",
|
||||
"Interface_Status": "حالة الواجهة",
|
||||
"Hotspot_Online_Users": "مستخدمو الهوتسبوت المتصلون",
|
||||
"PPPoE_Online_Users": "مستخدمو PPPoE المتصلون",
|
||||
"Traffic_Monitor": "مراقبة الحركة",
|
||||
"Interface_Name": "اسم الواجهة",
|
||||
"Tx__bytes_Out_": "Tx (البيانات المرسلة)",
|
||||
"Rx__bytes_In_": "Rx (البيانات المستلمة)",
|
||||
"Total_Usage": "إجمالي الاستخدام",
|
||||
"Server": "الخادم",
|
||||
"Mac_Address": "عنوان MAC",
|
||||
"Session_Time_Left": "الوقت المتبقي للجلسة",
|
||||
"Upload__RX_": "الرفع (RX)",
|
||||
"Download__TX_": "التنزيل (TX)",
|
||||
"Service": "الخدمة",
|
||||
"Caller_ID": "معرف المتصل",
|
||||
"Interface": "الواجهة",
|
||||
"Last_Ip": "آخر IP",
|
||||
"Last_Activity": "آخر نشاط",
|
||||
"Signal_Strength": "قوة الإشارة",
|
||||
"Tx___Rx_CCQ": "Tx / Rx CCQ",
|
||||
"Rx_Rate": "معدل الاستلام",
|
||||
"Tx_Rate": "معدل الإرسال",
|
||||
"TX": "الإرسال",
|
||||
"RX": "الاستلام",
|
||||
"Date_Time": "التاريخ / الوقت",
|
||||
"Topic": "الموضوع",
|
||||
"Info": "المعلومات",
|
||||
"Success": "نجاح",
|
||||
"Error": "خطأ",
|
||||
"Warning": "تحذير",
|
||||
"Force_Logout_": "تسجيل الخروج القسري:",
|
||||
"Disconnect": "قطع الاتصال"
|
||||
}
|
@ -312,7 +312,6 @@
|
||||
"Reminder_3_days": "Reminder 3 days",
|
||||
"Reminder_1_day": "Reminder 1 day",
|
||||
"PPPOE_Password": "PPPOE Password",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
|
||||
"Invoice_Balance_Message": "Invoice Balance Message",
|
||||
"Invoice_Notification_Payment": "Invoice Notification Payment",
|
||||
"Balance_Notification_Payment": "Balance Notification Payment",
|
||||
@ -659,9 +658,7 @@
|
||||
"Voucher_invalid": "Voucher invalid",
|
||||
"Account_Not_Found": "Account Not Found",
|
||||
"Internet_Voucher_Expired": "Internet Voucher Expired",
|
||||
"": "",
|
||||
"Additional_Billing": "Additional Billing",
|
||||
"_": "-",
|
||||
"Used_Date": "Used Date",
|
||||
"Filter": "Filter",
|
||||
"Start_time": "Start time",
|
||||
@ -672,5 +669,299 @@
|
||||
"balance": "balance",
|
||||
"radius": "radius",
|
||||
"Start_Date": "Start Date",
|
||||
"End_Date": "End Date"
|
||||
"End_Date": "End Date",
|
||||
"New_Version_Notification": "New Version Notification",
|
||||
"Enabled": "Enabled",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "This is to notify you when new updates is available",
|
||||
"Enable_Session_Timeout": "Enable Session Timeout",
|
||||
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Logout Admin if not Available\/Online a period of time",
|
||||
"Timeout_Duration": "Timeout Duration",
|
||||
"Enter_the_session_timeout_duration__minutes_": "Enter the session timeout duration (minutes)",
|
||||
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Idle Timeout, Logout Admin if Idle for xx minutes",
|
||||
"Failed_to_create_transaction__please_tell_seller_": "Failed to create transaction, please tell seller.",
|
||||
"paid_off": "paid off",
|
||||
"Sync_account_if_you_failed_login_to_internet": "Sync account if you failed login to internet",
|
||||
"Channel": "Channel",
|
||||
"Payment_Link": "Payment Link",
|
||||
"Created": "Created",
|
||||
"Previous": "Previous",
|
||||
"Share": "Share",
|
||||
"Mail_Deleted_Successfully": "Mail Deleted Successfully",
|
||||
"Message_Not_Found": "Message Not Found",
|
||||
"Send_Welcome_Message": "Send Welcome Message",
|
||||
"WA": "WA",
|
||||
"_": "-",
|
||||
"Routers_Maps": "Routers Maps",
|
||||
"Routers_Geo_Location_Information": "Routers Geo Location Information",
|
||||
"Coverage": "Coverage",
|
||||
"PPPoE_Username_already_used_by_another_customer": "PPPoE Username already used by another customer",
|
||||
"just_now": "just now",
|
||||
"Not_Working_for_freeradius": "Not Working for freeradius",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "User Cannot change this, only admin. if it Empty it will use Customer Credentials",
|
||||
"Failed_to_buy_package": "Failed to buy package",
|
||||
"New_Voucher_Created": "New Voucher Created",
|
||||
"New_Voucher_for_10mbps_Created": "New Voucher for 10mbps Created",
|
||||
"Show_Chart": "Show Chart",
|
||||
"For_PDF_Reports___Best_size_1078_x_200___uploaded_image_will_be_autosize": "For PDF Reports | Best size 1078 x 200 | uploaded image will be autosize",
|
||||
"For_invoice_print_using_Thermal_Printer": "For invoice print using Thermal Printer",
|
||||
"Theme": "Theme",
|
||||
"Theme_Info": "Theme Info",
|
||||
"This_used_for_admin_to_select_payment_in_recharge__using_comma_for_every_new_options": "This used for admin to select payment in recharge, using comma for every new options",
|
||||
"Income_will_reset_every_this_day": "Income will reset every this day",
|
||||
"edit_at_config_php": "edit at config.php",
|
||||
"Hide_Dashboard_Content": "Hide Dashboard Content",
|
||||
"Radius_Instructions": "Radius Instructions",
|
||||
"Customer_can_request_to_extend_expirations": "Customer can request to extend expirations",
|
||||
"i_agree_to_extends_and_will_paid_full_after_this": "i agree to extends and will paid full after this",
|
||||
"Telegram_Bot_Token": "Telegram Bot Token",
|
||||
"You_will_get_Payment_and_Error_notification_": "You will get Payment and Error notification<",
|
||||
"Must_include": "Must include",
|
||||
"it_will_be_replaced_": "it will be replaced.",
|
||||
"Or_use_Mikrotik_SMS": "Or use Mikrotik SMS",
|
||||
"You_can_use": "You can use",
|
||||
"in_here_too_": "in here too.",
|
||||
"Empty_this_to_use_internal_mail___PHP": "Empty this to use internal mail() PHP",
|
||||
"Mail_Reply_To": "Mail Reply To",
|
||||
"Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "Customer will reply email to this address, empty if you want to use From Address",
|
||||
"You_will_get_Payment_and_Error_notification": "You will get Payment and Error notification",
|
||||
"Languge_set_to_english": "Bahasa diatur ke bahasa Inggris",
|
||||
"Forgot_Password": "Forgot Password",
|
||||
"_Are_You_Sure_": "Are You Sure?",
|
||||
"Send_your_balance___": "Send your balance ?",
|
||||
"Search_Users": "Search Users",
|
||||
"Theme_Voucher": "Theme Voucher",
|
||||
"Payment_Info": "Payment Info",
|
||||
"Radius_Package": "Radius Package",
|
||||
"Hotspot_Package": "Hotspot Package",
|
||||
"PPPOE_Package": "PPPOE Package",
|
||||
"VPN_Package": "VPN Package",
|
||||
"Application_Name___Company_Name": "Application Name \/ Company Name",
|
||||
"Print_Max_Char": "Print Max Char",
|
||||
"Redirect_URL_after_Activation": "Redirect URL after Activation",
|
||||
"Enable_Radius": "Enable Radius",
|
||||
"Customer_Balance_System": "Customer Balance System",
|
||||
"Telegram_User_Channel_Group_ID": "Telegram User\/Channel\/Group ID",
|
||||
"Test_SMS": "Test SMS",
|
||||
"SMS_Server_URL": "SMS Server URL",
|
||||
"Select_Router": "Select Router",
|
||||
"Free_Server": "Free Server",
|
||||
"WhatsApp_Server_URL": "WhatsApp Server URL",
|
||||
"SMTP_Username": "SMTP Username",
|
||||
"SMTP_Password": "SMTP Password",
|
||||
"SMTP_Security": "SMTP Security",
|
||||
"None": "None",
|
||||
"By_WhatsApp": "By WhatsApp",
|
||||
"By_SMS": "By SMS",
|
||||
"By_Email": "By Email",
|
||||
"From_Direct_Chat_Link_": "From Direct Chat Link.",
|
||||
"Access_Token": "Access Token",
|
||||
"Empty_this_to_randomly_created_API_key": "Empty this to randomly created API key",
|
||||
"Router_Check": "Router Check",
|
||||
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "If enabled, the system will notify Admin when router goes Offline, If admin have 10 or more router and many customers, it will get overlapping, you can disabled",
|
||||
"Phone_OTP_Required": "Phone OTP Required",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "OTP is required when user want to change phone number and registration",
|
||||
"by_WhatsApp": "by WhatsApp",
|
||||
"By_WhatsApp_and_SMS": "By WhatsApp and SMS",
|
||||
"Email_OTP_Required": "Email OTP Required",
|
||||
"OTP_is_required_when_user_want_to_change_Email_Address": "OTP is required when user want to change Email Address",
|
||||
"Show_Bandwidth_Plan": "Show Bandwidth Plan",
|
||||
"_for_Customer": "for Customer",
|
||||
"Custome": "Custom",
|
||||
"Custome_Tax_Rate": "Custome Tax Rate",
|
||||
"Enter_Custome_Tax_Rate": "Enter Custome Tax Rate",
|
||||
"Authentication": "Authentication",
|
||||
"Github_Username": "Github Username",
|
||||
"Github_Token": "Github Token",
|
||||
"Create_GitHub_personal_access_token": "Create GitHub personal access token",
|
||||
"only_need_repo_scope": "only need repo scope",
|
||||
"This_will_allow_you_to_download_plugin_from_private_paid_repository": "This will allow you to download plugin from private\/paid repository",
|
||||
"Expired_Cronjob_Every_5_Minutes": "Expired Cronjob Every 5 Minutes",
|
||||
"Expired_Cronjob_Every_1_Hour": "Expired Cronjob Every 1 Hour",
|
||||
"Reminder_Cronjob_Every_7_AM": "Reminder Cronjob Every 7 AM",
|
||||
"Force_Logout_": "Force Logout:",
|
||||
"Activation": "Activation",
|
||||
"Package_Name": "Package Name",
|
||||
"Routers_Offline": "Routers Offline",
|
||||
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Cron appear not been setup, please check your cron setup.",
|
||||
"3_Months": "3 Months",
|
||||
"Invalid_or_Expired_CSRF_Token": "Invalid or Expired CSRF Token",
|
||||
"Miscellaneous_Settings": "Miscellaneous Settings",
|
||||
"Check_if_Customer_Online": "Check if Customer Online",
|
||||
"This_will_show_is_Customer_currently_is_online_or_not": "This will show is Customer currently is online or not",
|
||||
"General": "General",
|
||||
"Tax_Rates_by_percentage": "Tax Rates by percentage",
|
||||
"Settings_For_Mikrotik": "Mikrotik Settings",
|
||||
"Settings_For_Cron_Expired": "Settings For Cron Expired",
|
||||
"Choose_one__above_or_below": "Choose one, above or below",
|
||||
"Settings_For_Cron_Reminder": "Settings For Cron Reminder",
|
||||
"Upload_Zip_Plugin_Theme_Device": "Upload Zip Plugin\/Theme\/Device",
|
||||
"Install": "Install",
|
||||
"To_download_from_private_paid_repository": "To download from private\/paid repository",
|
||||
"Set_your_Github_Authentication_first": "Set your Github Authentication first",
|
||||
"SMS_Notification": "SMS Notification",
|
||||
"Customer_Registration_need_to_validate_using_OTP": "Customer Registration need to validate using OTP",
|
||||
"Registration_Username": "Registration Username",
|
||||
"Registration": "Registration",
|
||||
"For_Registration_and_Update_Phone_Number": "For Registration and Update Phone Number",
|
||||
"Voucher_Only": "Voucher Only",
|
||||
"No_Registration": "No Registration",
|
||||
"Allow_Registration": "Allow Registration",
|
||||
"Prepaid": "Prepaid",
|
||||
"Postpaid": "Postpaid",
|
||||
"Not_Active": "Not Active",
|
||||
"New_Service_Package": "New Service Package",
|
||||
"Limit": "Limit",
|
||||
"Create_expired_Internet_Package": "Create expired Internet Package",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "When customer expired, you can move it to Expired Internet Package",
|
||||
"Disable": "Disable",
|
||||
"Create_expired_Internet_Plan": "Create expired Internet Plan",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "When customer expired, you can move it to Expired Internet Plan",
|
||||
"Payment_Method": "Payment Method",
|
||||
"Created_on": "Created on",
|
||||
"Expires_on": "Expires on",
|
||||
"Edit_Service_Package": "Edit Service Package",
|
||||
"Package_Type": "Package Type",
|
||||
"Package_Price": "Package Price",
|
||||
"Price_Before_Discount": "Price Before Discount",
|
||||
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "For Discount Rate, this is price before get discount, must be more expensive with real price",
|
||||
"Package_Validity": "Package Validity",
|
||||
"Expired_Internet_Package": "Expired Internet Package",
|
||||
"Default___Remove_Customer": "Default - Remove Customer",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_package": "When Expired, customer will be move to selected internet package",
|
||||
"on_login___on_up": "on-login \/ on-up",
|
||||
"on_logout___on_down": "on-logout \/ on-down",
|
||||
"Online_Status": "Online Status",
|
||||
"Last_Seen": "Last Seen",
|
||||
"Online": "Online",
|
||||
"Offline": "Offline",
|
||||
"Check_if_Mikrotik_Online_": "Check if Mikrotik is Online?",
|
||||
"To_check_if_Mikrotik_is_Online_or_not__go_to_Settings__set_Router_Check_Enabled": "To check if Mikrotik is Online or not, go to Settings, set Router Check Enabled",
|
||||
"via_SMS": "via SMS",
|
||||
"Via_WhatsApp": "Via WhatsApp",
|
||||
"Via_WhatsApp_and_SMS": "Via WhatsApp and SMS",
|
||||
"Make_sure_you_use_API_Port__Default_8728": "Make sure you use API Port, Default 8728",
|
||||
"Make_sure_Username_and_Password_are_correct": "Make sure Username and Password are correct",
|
||||
"Make_sure_your_hosting_not_blocking_port_to_external": "Make sure your hosting not blocking port to external",
|
||||
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Make sure your Mikrotik accessible from PHPNuxBill",
|
||||
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "If you just update PHPNuxBill from upload files, try click Update",
|
||||
"Update_PHPNuxBill": "Update PHPNuxBill",
|
||||
"Ask_Github_Community": "Ask Github Community",
|
||||
"Ask_Telegram_Community": "Ask Telegram Community",
|
||||
"Transaction_History_List": "Transaction History List",
|
||||
"Login_as_Customer": "Login as Customer",
|
||||
"info": "info",
|
||||
"Registration_code": "Registration code",
|
||||
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "Admin can only have single session login, it will logout another session",
|
||||
"Single_session_Admin": "Single session Admin",
|
||||
"Get_Directions": "Get Directions",
|
||||
"Buy_Balance_Plans": "Buy Balance Plans",
|
||||
"Buy": "Buy",
|
||||
"Cron_Job_last_ran_on": "Cron Job last ran on",
|
||||
"VPN_Plans": "VPN Plans",
|
||||
"Postpaid_Recharge_for_the_first_time_use": "Postpaid Recharge for the first time use",
|
||||
"Or": "Or",
|
||||
"Balance_Package": "Balance Package",
|
||||
"Balance_Custom": "Balance Custom",
|
||||
"Balance_Amount": "Balance Amount",
|
||||
"Select_Balance_Package_or_Custom_Amount": "Select Balance Package or Custom Amount",
|
||||
"Note": "Note",
|
||||
"Or_custom_balance_amount_below": "Or custom balance amount below",
|
||||
"Input_custom_balance__will_ignore_plan_above": "Input custom balance, will ignore plan above",
|
||||
"Cron_has_not_run_for_over_1_hour__Please_check_your_setup_": "Cron has not run for over 1 hour. Please check your setup.",
|
||||
"Hello": "Hello",
|
||||
"your_internet_package": "your internet package",
|
||||
"has_been_expired": "has been expired",
|
||||
"Welcome_Message": "Welcome Message",
|
||||
"will_be_replaced_with_Customer_password": "will be replaced with Customer password",
|
||||
"will_be_replaced_with_Customer_Portal_URL": "will be replaced with Customer Portal URL",
|
||||
"will_be_replaced_with_Company_Name": "will be replaced with Company Name",
|
||||
"Token_has_expired__Please_log_in_again_": "Token has expired. Please log in again.",
|
||||
"Minute": "Minute",
|
||||
"Hour": "Hour",
|
||||
"Failed_to_connect_to_device": "Failed to connect to device",
|
||||
"Custom_Balance": "Custom Balance",
|
||||
"Input_Desired_Amount": "Input Desired Amount",
|
||||
"Security": "Security",
|
||||
"Enable_CSRF_Validation": "Enable CSRF Validation",
|
||||
"Cross_site_request_forgery": "Cross-site request forgery",
|
||||
"Validity_Periode": "Validity Periode",
|
||||
"Insufficient_balance": "Insufficient balance",
|
||||
"Display_bandwidth_plan_for_customer": "Display bandwidth plan for customer",
|
||||
"Allow_Balance_Custom_Amount": "Allow Balance Custom Amount",
|
||||
"Allow_Customer_buy_balance_with_any_amount": "Allow Customer buy balance with any amount",
|
||||
"Customer_Login_Page_Settings": "Customer Login Page Settings",
|
||||
"Choose_Template": "Choose Template",
|
||||
"Select_your_login_template_type": "Select your login template type",
|
||||
"Select_Login_Page": "Select Login Page",
|
||||
"Select_your_preferred_login_template": "Select your preferred login template",
|
||||
"Page_Heading___Company_Name": "Page Heading \/ Company Name",
|
||||
"This_Name_will_be_shown_on_the_login_wallpaper": "This Name will be shown on the login wallpaper",
|
||||
"Page_Description": "Page Description",
|
||||
"This_will_also_display_on_wallpaper__You_can_use_html_tag": "This will also display on wallpaper, You can use html tag",
|
||||
"Favicon": "Favicon",
|
||||
"Best_size_30_x_30___uploaded_image_will_be_autosize": "Best size 30 x 30 | uploaded image will be autosize",
|
||||
"Login_Page_Logo": "Login Page Logo",
|
||||
"Best_size_300_x_60___uploaded_image_will_be_autosize": "Best size 300 x 60 | uploaded image will be autosize",
|
||||
"Login_Page_Wallpaper": "Login Page Wallpaper",
|
||||
"Best_size_1920_x_1080___uploaded_image_will_be_autosize": "Best size 1920 x 1080 | uploaded image will be autosize",
|
||||
"Single_Admin_Session": "Single Admin Session",
|
||||
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Expired Cronjob Every 5 Minutes [Recommended]",
|
||||
"Login_Page_Settings_Saved_Successfully": "Login Page Settings Saved Successfully",
|
||||
"Sign_in_into_your_account": "Sign in into your account",
|
||||
"Don_t_have_an_account_": "Don't have an account?",
|
||||
"You_do_not_have_permission_to_access_this_page_in_demo_mode": "You do not have permission to access this page in demo mode",
|
||||
"Custom_Fields": "Custom Fields",
|
||||
"New_Field": "New Field",
|
||||
"Data_Change": "Data Change",
|
||||
"Photo": "Photo",
|
||||
"Home_Address": "Home Address",
|
||||
"Email_Address": "Email Address",
|
||||
"Photo_Required": "Photo Required",
|
||||
"Customer_Registration_need_to_upload_their_photo": "Customer Registration need to upload their photo",
|
||||
"Account_already_exists": "Account already exists",
|
||||
"Notify_Admin": "Notify Admin",
|
||||
"Notify_Admin_upon_self_registration": "Notify Admin upon self registration",
|
||||
"Registration_Mandatory_Fields": "Registration Mandatory Fields",
|
||||
"Mikrotik_SMS_Command": "Mikrotik SMS Command",
|
||||
"Mandatory_Fields": "Mandatory Fields",
|
||||
"Usernames": "Usernames",
|
||||
"Yours_Balance": "Yours Balance",
|
||||
"Friend_Usernames": "Friend Usernames",
|
||||
"Send_yours_balance___": "Send yours balance ? ",
|
||||
"Cards": "Cards",
|
||||
"CRM": "CRM",
|
||||
"Coupons": "Coupons",
|
||||
"Search_Coupons": "Search Coupons",
|
||||
"Add_Coupon": "Add Coupon",
|
||||
"Value": "Value",
|
||||
"Max_Usage": "Max Usage",
|
||||
"Usage_Count": "Usage Count",
|
||||
"Min_Order": "Min Order",
|
||||
"Max_Discount": "Max Discount",
|
||||
"Updated_Date": "Updated Date",
|
||||
"Action": "Action",
|
||||
"No_coupons_found_": "No coupons found.",
|
||||
"Delete_Selected": "Delete Selected",
|
||||
"Voucher_Cards": "Voucher Cards",
|
||||
"Create_Date": "Create Date",
|
||||
"Message_Results": "Message Results",
|
||||
"Total_SMS_Sent": "Total SMS Sent",
|
||||
"Total_SMS_Failed": "Total SMS Failed",
|
||||
"Total_WhatsApp_Sent": "Total WhatsApp Sent",
|
||||
"Total_WhatsApp_Failed": "Total WhatsApp Failed",
|
||||
"First_Name": "First Name",
|
||||
"Last_Name": "Last Name",
|
||||
"Not_Working_with_Freeradius_Mysql": "Not Working with Freeradius Mysql",
|
||||
"Radius_Rest_Interim_Update": "Radius Rest Interim-Update",
|
||||
"in_minutes__leave_0_to_disable_this_feature_": "in minutes, leave 0 to disable this feature.",
|
||||
"Check_if_Router_Online_": "Check if Router Online?",
|
||||
"To_check_whether_the_Router_is_online_or_not__please_visit_the_following_page": "To check whether the Router is online or not, please visit the following page",
|
||||
"Cek_Now": "Cek Now",
|
||||
"Pretty_URL": "Pretty URL",
|
||||
"rename__htaccess_firewall_to__htaccess": "rename .htaccess_firewall to .htaccess",
|
||||
"Show_chart": "Show chart",
|
||||
"Max_30_days": "Max 30 days",
|
||||
"Information": "Information",
|
||||
"Export_and_Print_will_show_all_data_without_pagination": "Export and Print will show all data without pagination",
|
||||
"Free_Internet_Plan_updated_successfully_": "Free Internet Plan updated successfully!"
|
||||
}
|
@ -381,8 +381,8 @@
|
||||
"SuperAdmin": "Super Admin",
|
||||
"Lists": "Daftar",
|
||||
"Vouchers": "Voucher",
|
||||
"Refill_Customer": "Isi Ulang Pelanggan",
|
||||
"Recharge_Customer": "Isi Ulang Pelanggan",
|
||||
"Refill_Customer": "Isi Ulang Voucher",
|
||||
"Recharge_Customer": "Isi Ulang Paket",
|
||||
"Plans": "Paket",
|
||||
"PPPOE": "PPPOE",
|
||||
"Bandwidth": "Bandwidth",
|
||||
@ -484,13 +484,13 @@
|
||||
"Income_reset_date": "Tanggal pengaturan ulang pendapatan",
|
||||
"Extend_Package_Expiry": "Perpanjang Masa Kedaluwarsa Paket",
|
||||
"Yes": "Ya",
|
||||
"No": "TIDAK",
|
||||
"No": "Tidak",
|
||||
"If_user_buy_same_internet_plan__expiry_date_will_extend": "Jika pengguna membeli paket internet yang sama, tanggal kedaluwarsa akan diperpanjang",
|
||||
"Tax_System": "Sistem pajak",
|
||||
"Enable_Tax_System": "Aktifkan Sistem Pajak",
|
||||
"Tax_will_be_calculated_in_Internet_Plan_Price": "Pajak akan dihitung dalam Harga Paket Internet",
|
||||
"Tax_Rate": "Persentase pajak",
|
||||
"Custom": "Kebiasaan",
|
||||
"Custom": "Kustom",
|
||||
"Tax_Rates_in_percentage": "Tarif Pajak dalam persentase",
|
||||
"Custom_Tax_Rate": "Tarif Pajak Khusus",
|
||||
"Enter_Custom_Tax_Rate": "Masukkan Tarif Pajak Khusus",
|
||||
@ -510,7 +510,7 @@
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Ketika Expired, pelanggan akan dipindahkan ke paket internet yang dipilih",
|
||||
"Period": "Periode",
|
||||
"Rate": "Kecepatan",
|
||||
"Burst": "Meletus",
|
||||
"Burst": "Burst",
|
||||
"Router_Name___Location": "Nama\/Lokasi Router",
|
||||
"Extend": "Memperpanjang",
|
||||
"City": "Kota",
|
||||
@ -523,7 +523,7 @@
|
||||
"Descending": "Menurun",
|
||||
"Query": "Query",
|
||||
"Add": "Menambahkan",
|
||||
"Logout_Successful": "Logout Berhasil",
|
||||
"Logout_Successful": "Berhasil Keluar",
|
||||
"warning": "peringatan",
|
||||
"Created___Expired": "Dibuat \/ Kedaluwarsa",
|
||||
"Login___Activate_Voucher": "Masuk \/ Aktifkan Voucher",
|
||||
@ -538,7 +538,6 @@
|
||||
"Zip_Code": "Kode Pos",
|
||||
"Phone": "Telepon",
|
||||
"Customer_Geo_Location_Information": "Informasi Lokasi Geo Pelanggan",
|
||||
"": "",
|
||||
"Code": "Kode",
|
||||
"Send_Personal_Message": "Kirim Pesan Pribadi",
|
||||
"Send_Via": "Kirim melalui",
|
||||
@ -547,7 +546,7 @@
|
||||
"Customer_Name": "Nama Pelanggan",
|
||||
"Customer_Username": "Nama Pengguna Pelanggan",
|
||||
"Customer_Phone": "Telepon Pelanggan",
|
||||
"Your_Company_Name": "Nama perusahaan Anda",
|
||||
"Your_Company_Name": "Nama Perusahaan Anda",
|
||||
"Change": "Mengubah",
|
||||
"Change_Phone_Number": "Ubah Nomor Telepon",
|
||||
"Current_Number": "Nomor Saat Ini",
|
||||
@ -566,6 +565,349 @@
|
||||
"This_account_status": "Status akun ini",
|
||||
"Hotspot_Auth_Method": "Metode Otentikasi Hotspot",
|
||||
"Api": "Api",
|
||||
"Http_Chap": "Http-Bab",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "Metode Otentikasi Hotspot. Pastikan Anda telah mengubah halaman login hotspot Anda."
|
||||
"Http_Chap": "Http-Chap",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "Metode Otentikasi Hotspot. Pastikan Anda telah mengubah halaman login hotspot Anda.",
|
||||
"Languge_set_to_indonesia": "Language set to indonesia",
|
||||
"Enable": "Aktifkan",
|
||||
"Diable": "Nonaktifkan",
|
||||
"Verification_code": "Kod3 V3r1fik@s1",
|
||||
"Registration_code": "Kod3 R3g1str@s1",
|
||||
"TX": "TX",
|
||||
"RX": "RX",
|
||||
"Database": "Database",
|
||||
"Additional_Billing": "Penagihan Tambahan",
|
||||
"paid_off": "terbayar lunas",
|
||||
"Sync_account_if_you_failed_login_to_internet": "Sinkronkan akun jika Anda gagal masuk ke internet",
|
||||
"_Are_You_Sure_": "Apa kamu yakin?",
|
||||
"Send_your_balance___": "Kirim saldo Anda?",
|
||||
"_": "-",
|
||||
"Search_Users": "Pencarian Pengguna",
|
||||
"Routers_Maps": "Peta Router",
|
||||
"Theme_Voucher": "Voucher Tema",
|
||||
"Payment_Info": "Info Pembayaran",
|
||||
"Documentation": "Dokumentasi",
|
||||
"Customers": "Pelanggan",
|
||||
"Package_Name": "Nama Paket",
|
||||
"Routers_Offline": "Router Offline",
|
||||
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Cron tampaknya belum disiapkan, silakan periksa pengaturan cron Anda.",
|
||||
"Buy": "Membeli",
|
||||
"You_are_already_logged_in": "Anda sudah masuk",
|
||||
"PPPOE_Package": "Paket PPPoE",
|
||||
"Prepaid": "Prabayar",
|
||||
"Postpaid": "Pascabayar",
|
||||
"Enabled": "Diaktifkan",
|
||||
"Disable": "Nonaktifkan",
|
||||
"Create_expired_Internet_Plan": "Buat Paket Internet yang Kedaluwarsa",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "Ketika pelanggan kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
|
||||
"Price_Before_Discount": "Harga Sebelum Diskon",
|
||||
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Untuk Discount Rate, ini adalah harga sebelum mendapat diskon, pasti lebih mahal dari harga sebenarnya",
|
||||
"on_login___on_up": "saat masuk \/ saat mendaftar",
|
||||
"on_logout___on_down": "saat keluar \/ saat turun",
|
||||
"Get_Directions": "Dapatkan Petunjuk Arah",
|
||||
"Not_Working_with_Freeradius_Mysql": "Tidak Bekerja dengan Freeradius Mysql",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "Pengguna tidak dapat mengubah ini, hanya admin. Jika Kosong, maka akan menggunakan Kredensial Pelanggan",
|
||||
"Buy_this__your_active_package_will_be_overwritten": "Beli ini? Paket aktif Anda akan ditimpa",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
|
||||
"Error": "Kesalahan",
|
||||
"Internal_Error": "Kesalahan Internal",
|
||||
"Sorry__the_software_failed_to_process_the_request__if_it_still_happening__please_tell": "Maaf, perangkat lunak gagal memproses permintaan, jika masih terjadi, mohon beri tahu",
|
||||
"Try_Again": "Coba Lagi",
|
||||
"Make_sure_you_use_API_Port__Default_8728": "Pastikan Anda menggunakan Port API, Default 8728",
|
||||
"Make_sure_Username_and_Password_are_correct": "Pastikan Username dan Password sudah benar",
|
||||
"Make_sure_your_hosting_not_blocking_port_to_external": "Pastikan hosting Anda tidak memblokir port ke eksternal",
|
||||
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Pastikan Mikrotik Anda dapat diakses dari PHPNuxBill",
|
||||
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "Jika Anda baru saja memperbarui PHPNuxBill dari mengunggah file, coba klik Perbarui",
|
||||
"Update_PHPNuxBill": "Perbarui PHPNuxBill",
|
||||
"Ask_Github_Community": "Tanya Komunitas Github",
|
||||
"Ask_Telegram_Community": "Tanya Komunitas Telegram",
|
||||
"Token_has_expired__Please_log_in_again_": "Token telah kedaluwarsa. Silakan masuk lagi.",
|
||||
"danger": "bahaya",
|
||||
"Application_Name___Company_Name": "Nama Aplikasi \/ Nama Perusahaan",
|
||||
"For_PDF_Reports___Best_size_1078_x_200___uploaded_image_will_be_autosize": "Untuk Laporan PDF | Ukuran terbaik 1078 x 200 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Print_Max_Char": "Cetak Max Char",
|
||||
"For_invoice_print_using_Thermal_Printer": "Untuk cetak faktur menggunakan Printer Thermal",
|
||||
"Theme": "Tema",
|
||||
"Default": "Bawaan",
|
||||
"Theme_Info": "Info Tema",
|
||||
"This_used_for_admin_to_select_payment_in_recharge__using_comma_for_every_new_options": "Ini digunakan untuk admin untuk memilih pembayaran dalam pengisian ulang, menggunakan koma untuk setiap opsi baru",
|
||||
"Income_will_reset_every_this_day": "Pendapatan akan direset setiap hari ini",
|
||||
"edit_at_config_php": "edit di config.php",
|
||||
"Hide_Dashboard_Content": "Sembunyikan Konten Dasbor",
|
||||
"Redirect_URL_after_Activation": "Pengalihan URL setelah Aktivasi",
|
||||
"Enable_Radius": "Aktifkan Radius",
|
||||
"Radius_Instructions": "Petunjuk Radius",
|
||||
"Customer_can_request_to_extend_expirations": "Pelanggan dapat meminta perpanjangan masa berlaku",
|
||||
"i_agree_to_extends_and_will_paid_full_after_this": "Saya setuju untuk memperpanjang dan akan membayar penuh setelah ini",
|
||||
"Customer_Balance_System": "Sistem Saldo Pelanggan",
|
||||
"Telegram_Bot_Token": "Token Bot Telegram",
|
||||
"Telegram_User_Channel_Group_ID": "ID Pengguna\/Saluran\/Grup Telegram",
|
||||
"You_will_get_Payment_and_Error_notification": "Anda akan mendapatkan pemberitahuan Pembayaran dan Kesalahan",
|
||||
"Test_SMS": "Tes SMS",
|
||||
"SMS_Server_URL": "URL Server SMS",
|
||||
"Must_include": "Harus menyertakan",
|
||||
"it_will_be_replaced_": "itu akan diganti.",
|
||||
"Or_use_Mikrotik_SMS": "Atau gunakan Mikrotik SMS",
|
||||
"Select_Router": "Pilih Router",
|
||||
"You_can_use": "Anda dapat menggunakan",
|
||||
"in_here_too_": "di sini juga.",
|
||||
"Free_Server": "Server Gratis",
|
||||
"WhatsApp_Server_URL": "URL Server WhatsApp",
|
||||
"Empty_this_to_use_internal_mail___PHP": "Kosongkan ini untuk menggunakan internal mail() PHP",
|
||||
"SMTP_Username": "Nama Pengguna SMTP",
|
||||
"SMTP_Password": "Kata Sandi SMTP",
|
||||
"SMTP_Security": "Keamanan SMTP",
|
||||
"Mail_Reply_To": "Balas Email Ke",
|
||||
"Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "Pelanggan akan membalas email ke alamat ini, kosong jika Anda ingin menggunakan Alamat Dari",
|
||||
"None": "Tidak ada",
|
||||
"By_WhatsApp": "Melalui WhatsApp",
|
||||
"By_SMS": "Melalui SMS",
|
||||
"By_Email": "Melalui Email",
|
||||
"From_Direct_Chat_Link_": "Dari Tautan Obrolan Langsung.",
|
||||
"Access_Token": "Token Akses",
|
||||
"Empty_this_to_randomly_created_API_key": "Kosongkan ini ke kunci API yang dibuat secara acak",
|
||||
"Enable_Session_Timeout": "Aktifkan Batas Waktu Sesi",
|
||||
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Logout Admin jika tidak tersedia\/Online dalam jangka waktu tertentu",
|
||||
"Timeout_Duration": "Durasi Waktu Habis",
|
||||
"Enter_the_session_timeout_duration__minutes_": "Masukkan durasi batas waktu sesi (menit)",
|
||||
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Waktu Habis Idle, Keluar dari Admin jika Idle selama xx menit",
|
||||
"New_Version_Notification": "Pemberitahuan Versi Baru",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "Ini untuk memberi tahu Anda ketika pembaruan baru tersedia",
|
||||
"Router_Check": "Pemeriksaan Router",
|
||||
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Jika diaktifkan, sistem akan memberitahu Admin ketika router Offline, Jika admin memiliki 10 atau lebih router dan banyak pelanggan, maka akan terjadi tumpang tindih, Anda dapat menonaktifkannya",
|
||||
"Phone_OTP_Required": "Diperlukan OTP Telepon",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "OTP diperlukan ketika pengguna ingin mengubah nomor telepon dan registrasi",
|
||||
"by_WhatsApp": "melalui WhatsApp",
|
||||
"By_WhatsApp_and_SMS": "Melalui WhatsApp dan SMS",
|
||||
"Email_OTP_Required": "Email OTP Diperlukan",
|
||||
"OTP_is_required_when_user_want_to_change_Email_Address": "OTP diperlukan ketika pengguna ingin mengubah Alamat Email",
|
||||
"Show_Bandwidth_Plan": "Tampilkan Paket Bandwidth",
|
||||
"_for_Customer": "untuk Pelanggan",
|
||||
"Custome": "Pelanggan",
|
||||
"Custome_Tax_Rate": "Tarif Pajak Bea Cukai",
|
||||
"Enter_Custome_Tax_Rate": "Masukkan Tarif Pajak Pelanggan",
|
||||
"Authentication": "Autentikasi",
|
||||
"Github_Username": "Nama Pengguna Github",
|
||||
"Github_Token": "Token Github",
|
||||
"Create_GitHub_personal_access_token": "Buat token akses pribadi GitHub",
|
||||
"only_need_repo_scope": "hanya butuh cakupan repo",
|
||||
"This_will_allow_you_to_download_plugin_from_private_paid_repository": "Ini akan memungkinkan Anda mengunduh plugin dari repositori pribadi\/berbayar",
|
||||
"Expired_Cronjob_Every_5_Minutes": "Cronjob Kedaluwarsa Setiap 5 Menit",
|
||||
"Expired_Cronjob_Every_1_Hour": "Cronjob Kedaluwarsa Setiap 1 Jam",
|
||||
"Reminder_Cronjob_Every_7_AM": "Pengingat Cronjob Setiap Jam 7 Pagi",
|
||||
"Check_if_Customer_Online": "Periksa apakah Pelanggan Online",
|
||||
"Active_Customers": "Pelanggan Aktif",
|
||||
"This_will_show_is_Customer_currently_is_online_or_not": "Ini akan menunjukkan apakah Pelanggan sedang online atau tidak",
|
||||
"3_Months": "3 Bulan",
|
||||
"Used_Date": "Tanggal Penggunaan",
|
||||
"Plugin_Installer": "Pemasang Plugin",
|
||||
"Upload_Zip_Plugin_Theme_Device": "Unggah Plugin\/Tema\/Perangkat Zip",
|
||||
"Install": "Memasang",
|
||||
"via_SMS": "melalui SMS",
|
||||
"Via_WhatsApp": "Melalui WhatsApp",
|
||||
"Via_WhatsApp_and_SMS": "Melalui WhatsApp dan SMS",
|
||||
"Send_Bulk_Message": "Kirim Pesan Massal",
|
||||
"Group": "Kelompok",
|
||||
"All_Customers": "Semua Pelanggan",
|
||||
"New_Customers": "Pelanggan Baru",
|
||||
"Expired_Customers": "Pelanggan yang Kedaluwarsa",
|
||||
"Message_per_time": "Pesan per waktu",
|
||||
"5_Messages": "5 Pesan",
|
||||
"10_Messages": "10 Pesan",
|
||||
"15_Messages": "15 Pesan",
|
||||
"20_Messages": "20 Pesan",
|
||||
"30_Messages": "30 Pesan",
|
||||
"40_Messages": "40 Pesan",
|
||||
"50_Messages": "50 Pesan",
|
||||
"60_Messages": "60 Pesan",
|
||||
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Gunakan 20 dan di atasnya jika Anda mengirim ke semua pelanggan untuk menghindari waktu server habis",
|
||||
"Delay": "Menunda",
|
||||
"No_Delay": "Tidak Ada Penundaan",
|
||||
"5_Seconds": "5 Detik",
|
||||
"10_Seconds": "10 Detik",
|
||||
"15_Seconds": "15 Detik",
|
||||
"20_Seconds": "20 Detik",
|
||||
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Gunakan setidaknya 5 detik jika Anda mengirim ke semua pelanggan untuk menghindari pemblokiran oleh penyedia pesan Anda",
|
||||
"Testing__if_checked_no_real_message_is_sent_": "Pengujian [jika dicentang, tidak ada pesan nyata yang dikirim]",
|
||||
"Message_Results": "Hasil Pesan",
|
||||
"VPN_Plans": "Paket VPN",
|
||||
"VPN_Package": "Paket VPN",
|
||||
"Balance_Package": "Paket Saldo",
|
||||
"New_Service_Package": "Paket Layanan Baru",
|
||||
"Package_Price": "Harga Paket",
|
||||
"Radius_Package": "Paket Radius",
|
||||
"Hotspot_Package": "Paket Hotspot",
|
||||
"Maintenance_Mode_Settings": "Pengaturan Mode Pemeliharaan",
|
||||
"Status_": "Status:",
|
||||
"Force_Logout_": "Paksa Keluar:",
|
||||
"End_Date_": "Tanggal Berakhir:",
|
||||
"Save": "Menyimpan",
|
||||
"Not_Active": "Tidak Aktif",
|
||||
"Limit": "Membatasi",
|
||||
"Create_expired_Internet_Package": "Buat Paket Internet yang Kedaluwarsa",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "Ketika pelanggan telah kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
|
||||
"Miscellaneous_Settings": "Pengaturan Lain-Lain",
|
||||
"Minute": "Menit",
|
||||
"Hour": "Jam",
|
||||
"Buy_Balance_Plans": "Beli Paket Saldo",
|
||||
"New_Voucher_for_10mbps_Created": "Voucher Baru untuk 10mbps Dibuat",
|
||||
"Previous": "Sebelumnya",
|
||||
"Share": "Membagikan",
|
||||
"Agent": "Agen",
|
||||
"Sub_District": "Kecamatan",
|
||||
"Ward": "Bangsal",
|
||||
"Profile": "Profil",
|
||||
"Credentials": "Kredensial",
|
||||
"Cron_has_not_run_for_over_1_hour__Please_check_your_setup_": "Cron tidak berjalan selama lebih dari 1 jam. Harap periksa pengaturan Anda.",
|
||||
"Photo": "Foto",
|
||||
"just_now": "baru saja",
|
||||
"Face_Detection": "Deteksi Wajah",
|
||||
"Password_should_be_minimum_6_characters": "Kata sandi minimal harus 6 karakter",
|
||||
"Username_should_be_between_3_to_45_characters": "Nama pengguna harus terdiri dari 3 hingga 45 karakter",
|
||||
"Single_session_Admin": "Sesi Tunggal Admin",
|
||||
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "Admin hanya dapat memiliki login satu sesi, maka akan keluar dari sesi berikutnya",
|
||||
"For_Registration_and_Update_Phone_Number": "Untuk Registrasi dan Update Nomor Telepon",
|
||||
"Login_as_Customer": "Masuk sebagai Pelanggan",
|
||||
"Invalid_or_Expired_CSRF_Token": "Token CSRF Tidak Valid atau Kedaluwarsa",
|
||||
"Edit_Service_Package": "Edit Paket Layanan",
|
||||
"Package_Type": "Tipe Paket",
|
||||
"Package_Validity": "Validitas Paket",
|
||||
"Expired_Internet_Package": "Paket Internet Kedaluwarsa",
|
||||
"Default___Remove_Customer": "Default - Hapus Pelanggan",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_package": "Jika masa berlaku habis, pelanggan akan dipindahkan ke paket internet yang dipilih",
|
||||
"Data_Change": "Perubahan Data",
|
||||
"Home_Address": "Alamat Rumah",
|
||||
"Email_Address": "Alamat Email",
|
||||
"Custom_Balance": "Saldo Kustom",
|
||||
"Input_Desired_Amount": "Masukkan Jumlah yang Diinginkan",
|
||||
"Advanced_Hotspot_System": "Sistem Hotspot Canggih",
|
||||
"Successful_Payments": "Pembayaran Berhasil",
|
||||
"More_Info": "Info lebih lanjut",
|
||||
"Failed_Payments": "Pembayaran Gagal",
|
||||
"Pending_Payments": "Pembayaran Tertunda",
|
||||
"Cancelled_Payments": "Pembayaran yang Dibatalkan",
|
||||
"Daily_Sales": "Penjualan Harian",
|
||||
"Monthly_Sales": "Penjualan Bulanan",
|
||||
"Weekly_Sales": "Penjualan Mingguan",
|
||||
"How_its_Works": "Cara kerjanya",
|
||||
"_Click_this": "Klik ini",
|
||||
"_to_visit_the_hotspot_login_page": "untuk mengunjungi halaman login hotspot",
|
||||
"_Choose_your_desired_plan__enter_your_phone_number_and_click_Pay_Now__you_will_be_redirected_to_payment_portal_": "Pilih paket yang Anda inginkan, masukkan nomor telepon Anda dan klik Bayar Sekarang, Anda akan diarahkan ke portal pembayaran.",
|
||||
"_Pay_with_Demo_Success_": "Bayar dengan Demo Sukses.",
|
||||
"_After_Successful_Payment_you_will_be_awarded_the_package_and_you_will_received_your_Voucher_Code_for_login_": "Setelah Pembayaran Berhasil, Anda akan diberikan paket dan Anda akan menerima Kode Voucher untuk login.",
|
||||
"_Come_back_here_to_see_your_hotspot_performance_at_a_glance_": "Kembali ke sini untuk melihat sekilas kinerja hotspot Anda.",
|
||||
"Hotspot_Payment_History": "Riwayat Pembayaran Hotspot",
|
||||
"Search_Phone_Number_____": "Cari Nomor Telepon.....",
|
||||
"Transaction_ID": "ID Transaksi",
|
||||
"Transaction_Ref": "Referensi Transaksi",
|
||||
"Voucher_Code": "Kode Voucher",
|
||||
"Amount": "Jumlah",
|
||||
"Transaction_Status": "Status Transaksi",
|
||||
"Payment_Method": "Metode Pembayaran",
|
||||
"Payment_Date": "Tanggal Pembayaran",
|
||||
"Plan_Expiry_Date": "Tanggal Kedaluwarsa Paket",
|
||||
"Created_on": "Dibuat pada",
|
||||
"Expires_on": "Kedaluwarsa pada",
|
||||
"Package_Details": "Rincian Paket",
|
||||
"Summary": "Ringkasan",
|
||||
"Allow_Balance_custom_amount": "Izinkan Saldo jumlah khusus",
|
||||
"Allow_Customer_buy_balance_with_any_amount": "Izinkan Pelanggan membeli saldo dengan jumlah berapa pun",
|
||||
"Or": "Atau",
|
||||
"Filter": "Menyaring",
|
||||
"Show_chart": "Tampilkan grafik",
|
||||
"Start_Date": "Tanggal Mulai",
|
||||
"Start_time": "Waktu Mulai",
|
||||
"End_Date": "Tanggal Akhir",
|
||||
"End_Time": "Waktu berakhir",
|
||||
"Internet_Plans": "Paket Internet",
|
||||
"Methods": "Metode",
|
||||
"Hap_Lite": "Hap Lite",
|
||||
"balance": "saldo",
|
||||
"radius": "radius",
|
||||
"Max_30_days": "Maksimal 30 hari",
|
||||
"Information": "Informasi",
|
||||
"Export_and_Print_will_show_all_data_without_pagination": "Ekspor dan Cetak akan menampilkan semua data tanpa pagination",
|
||||
"First_Name": "Nama Depan",
|
||||
"Last_Name": "Nama Belakang",
|
||||
"General": "Umum",
|
||||
"Registration": "Pendaftaran",
|
||||
"Allow_Registration": "Izinkan Registrasi",
|
||||
"Voucher_Only": "Hanya Voucher",
|
||||
"No_Registration": "Tidak Ada Registrasi",
|
||||
"Registration_Username": "Nama Pengguna Registrasi",
|
||||
"Customer_Registration_need_to_validate_using_OTP": "Registrasi Pelanggan perlu divalidasi menggunakan OTP",
|
||||
"SMS_Notification": "Pemberitahuan SMS",
|
||||
"Tax_Rates_by_percentage": "Tarif Pajak Berdasarkan Persentase",
|
||||
"Settings_For_Mikrotik": "Pengaturan Untuk Mikrotik",
|
||||
"Settings_For_Cron_Expired": "Pengaturan Untuk Cron Kedaluwarsa",
|
||||
"Choose_one__above_or_below": "Pilih salah satu, di atas atau di bawah",
|
||||
"Settings_For_Cron_Reminder": "Pengaturan Untuk Pengingat Cron",
|
||||
"Security": "Keamanan",
|
||||
"Enable_CSRF_Validation": "Aktifkan Validasi CSRF",
|
||||
"Cross_site_request_forgery": "Pemalsuan permintaan lintas situs",
|
||||
"Forgot_Password": "Lupa Kata Sandi",
|
||||
"Validity_Periode": "Periode Validitas",
|
||||
"Transaction_History_List": "Daftar Riwayat Transaksi",
|
||||
"plan": "paket",
|
||||
"package": "paket",
|
||||
"Cards": "Kartu",
|
||||
"CRM": "CRM",
|
||||
"Coupons": "Kupon",
|
||||
"Custom_Fields": "Bidang Kustom",
|
||||
"Search_Coupons": "Cari Kupon",
|
||||
"Add_Coupon": "Tambahkan Kupon",
|
||||
"Value": "Nilai",
|
||||
"Max_Usage": "Penggunaan Maksimal",
|
||||
"Usage_Count": "Jumlah Pemakaian",
|
||||
"Min_Order": "Pesanan Min",
|
||||
"Max_Discount": "Diskon Maksimal",
|
||||
"Updated_Date": "Tanggal Diperbarui",
|
||||
"Action": "Tindakan",
|
||||
"No_coupons_found_": "Tidak ada kupon yang ditemukan.",
|
||||
"Delete_Selected": "Hapus yang Dipilih",
|
||||
"Coupon_Code": "Kode Kupon",
|
||||
"Random": "Acak",
|
||||
"Unique_code_for_the_coupon": "Kode unik untuk kupon",
|
||||
"Fixed_Discount": "Diskon Tetap",
|
||||
"Percent_Discount": "Diskon Persen",
|
||||
"Discount_Value": "Nilai Diskon",
|
||||
"Value_of_the_discount__amount_or_percentage_": "Nilai diskon (jumlah atau persentase)",
|
||||
"Brief_explanation_of_the_coupon": "Penjelasan singkat tentang kupon",
|
||||
"Maximum_number_of_times_this_coupon_can_be_used_0_is_Unlimited": "Jumlah maksimum penggunaan kupon ini 0 adalah Tidak Terbatas",
|
||||
"Minimum_Order_Amount": "Jumlah Pesanan Minimum",
|
||||
"Minimum_cart_total_required_to_use_this_coupon": "Total keranjang minimum yang diperlukan untuk menggunakan kupon ini",
|
||||
"Max_Discount_Amount": "Jumlah Diskon Maksimum",
|
||||
"Maximum_discount_amount_applicable__for_percent_type_": "Jumlah diskon maksimum yang berlaku (untuk jenis persen)",
|
||||
"Value_of_the_discount__percentage__max_100_": "Nilai diskon (persentase, maks 100)",
|
||||
"Value_of_the_discount__amount_": "Nilai diskon (jumlah)",
|
||||
"Voucher_Cards": "Kartu Voucher",
|
||||
"Create_Date": "Tanggal Pembuatan",
|
||||
"Postpaid_Recharge_for_the_first_time_use": "Isi Ulang Pascabayar untuk penggunaan pertama kali",
|
||||
"Select_Balance_Package_or_Custom_Amount": "Pilih Paket Saldo atau Jumlah Kustom",
|
||||
"Or_custom_balance_amount_below": "Atau jumlah saldo khusus di bawah ini",
|
||||
"Balance_Amount": "Jumlah Saldo",
|
||||
"Input_custom_balance__will_ignore_plan_above": "Masukkan saldo khusus, akan mengabaikan rencana di atas",
|
||||
"Note": "Catatan",
|
||||
"Customer_Login_Page_Settings": "Pengaturan Halaman Login Pelanggan",
|
||||
"Choose_Template": "Pilih Template",
|
||||
"Select_your_login_template_type": "Pilih jenis template login Anda",
|
||||
"Select_Login_Page": "Pilih Halaman Login",
|
||||
"Select_your_preferred_login_template": "Pilih template login pilihan Anda",
|
||||
"Page_Heading___Company_Name": "Judul Halaman \/ Nama Perusahaan",
|
||||
"This_Name_will_be_shown_on_the_login_wallpaper": "Nama ini akan ditampilkan pada wallpaper login",
|
||||
"Page_Description": "Deskripsi Halaman",
|
||||
"This_will_also_display_on_wallpaper__You_can_use_html_tag": "Ini juga akan ditampilkan di wallpaper, Anda dapat menggunakan tag html",
|
||||
"Favicon": "Ikon favicon",
|
||||
"Best_size_30_x_30___uploaded_image_will_be_autosize": "Ukuran terbaik 30 x 30 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Login_Page_Logo": "Logo Halaman Login",
|
||||
"Best_size_300_x_60___uploaded_image_will_be_autosize": "Ukuran terbaik 300 x 60 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Login_Page_Wallpaper": "Wallpaper Halaman Login",
|
||||
"Best_size_1920_x_1080___uploaded_image_will_be_autosize": "Ukuran terbaik 1920 x 1080 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Photo_Required": "Foto Diperlukan",
|
||||
"Customer_Registration_need_to_upload_their_photo": "Registrasi Pelanggan perlu mengunggah foto mereka",
|
||||
"Notify_Admin": "Beritahu Admin",
|
||||
"Notify_Admin_upon_self_registration": "Beritahu Admin saat registrasi mandiri",
|
||||
"Mandatory_Fields": "Bidang yang wajib diisi",
|
||||
"Single_Admin_Session": "Sesi Admin Tunggal",
|
||||
"Mikrotik_SMS_Command": "Perintah SMS Mikrotik",
|
||||
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob Kedaluwarsa Setiap 5 Menit [Direkomendasikan]"
|
||||
}
|
@ -5,10 +5,10 @@
|
||||
"Registration_Info": "Informaci\u00f3n de registro",
|
||||
"Voucher_not_found__please_buy_voucher_befor_register": "Cup\u00f3n no encontrado, compre el cup\u00f3n antes de registrarse",
|
||||
"Register_Success__You_can_login_now": "\u00a1Registro exitoso! Puedes iniciar sesi\u00f3n ahora",
|
||||
"Log_in_to_Member_Panel": "Log in to Member Panel",
|
||||
"Log_in_to_Member_Panel": "Iniciar sesi\u00f3n en el panel de miembros",
|
||||
"Register_as_Member": "Reg\u00edstrese como miembro",
|
||||
"Enter_Admin_Area": "Panel de administraci\u00f3n",
|
||||
"PHPNuxBill": "DIGITAL-RED",
|
||||
"PHPNuxBill": "WENJEI",
|
||||
"Username": "Usuario",
|
||||
"Password": "Contrase\u00f1a",
|
||||
"Passwords_does_not_match": "Las contrase\u00f1as no coinciden",
|
||||
@ -27,7 +27,7 @@
|
||||
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "No se pudo guardar la p\u00e1gina, aseg\u00farese de que pueda escribir en las p\u00e1ginas de la carpeta, <i>chmod 664 pages\/*.html<i>",
|
||||
"Saving_page_success": "Guardando el \u00e9xito de la p\u00e1gina",
|
||||
"Sometimes_you_need_to_refresh_3_times_until_content_change": "A veces es necesario actualizar 3 veces hasta que cambie el contenido",
|
||||
"Dashboard": "Dashboard",
|
||||
"Dashboard": "Panel",
|
||||
"Search_Customers___": "Buscar clientes...",
|
||||
"My_Account": "Mi cuenta",
|
||||
"My_Profile": "Mi perfil",
|
||||
@ -140,7 +140,7 @@
|
||||
"Administrator_Users": "Usuarios administradores",
|
||||
"Manage_Administrator": "Administrar administrador",
|
||||
"Add_New_Administrator": "Agregar nuevo administrador",
|
||||
"Localisation": "Localizaci\u00f3n",
|
||||
"Localisation": "Idioma y Fecha",
|
||||
"Backup_Restore": "Copia de seguridad\/restauracion",
|
||||
"General_Settings": "Configuraci\u00f3n general",
|
||||
"Date": "Fecha",
|
||||
@ -213,165 +213,357 @@
|
||||
"Folder_Name": "Nombre de la carpeta",
|
||||
"Translator": "Traducir",
|
||||
"Language_Name_Already_Exist": "El nombre del idioma ya existe",
|
||||
"Payment_Gateway": "Payment Gateway",
|
||||
"Community": "Community",
|
||||
"1_user_can_be_used_for_many_devices_": "1 user can be used for many devices?",
|
||||
"Cannot_be_change_after_saved": "Cannot be change after saved",
|
||||
"Explain_Coverage_of_router": "Jelaskan Cakupan wilayah hotspot",
|
||||
"Name_of_Area_that_router_operated": "Nama Lokasi\/Wilayah Router beroperasi",
|
||||
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "Payment Notification URL, Recurring Notification URL, Pay Account Notification URL",
|
||||
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Finish Redirect URL, Unfinish Redirect URL, Error Redirect URL",
|
||||
"Status": "Status",
|
||||
"Plan_Not_found": "Plan Not found",
|
||||
"Failed_to_create_transaction_": "Failed to create transaction.",
|
||||
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Seller has not yet setup Xendit payment gateway",
|
||||
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin has not yet setup Xendit payment gateway, please tell admin",
|
||||
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
|
||||
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "You already have unpaid transaction, cancel it or pay it.",
|
||||
"Transaction_Not_found": "Transaction Not found",
|
||||
"Cancel_it_": "Cancel it?",
|
||||
"expired": "expired",
|
||||
"Check_for_Payment": "Check for Payment",
|
||||
"Transaction_still_unpaid_": "Transaction still unpaid.",
|
||||
"Paid_Date": "Paid Date",
|
||||
"Transaction_has_been_paid_": "Transaction has been paid.",
|
||||
"PAID": "PAID",
|
||||
"CANCELED": "CANCELED",
|
||||
"UNPAID": "UNPAID",
|
||||
"PAY_NOW": "PAY NOW",
|
||||
"Buy_Hotspot_Plan": "Buy Hotspot Plan",
|
||||
"Buy_PPOE_Plan": "Buy PPOE Plan",
|
||||
"Package": "Package",
|
||||
"Order_Internet_Package": "Order Internet Package",
|
||||
"Unknown_Command_": "Unknown Command.",
|
||||
"Checking_payment": "Checking payment",
|
||||
"Create_Transaction_Success": "Create Transaction Success",
|
||||
"You_have_unpaid_transaction": "You have unpaid transaction",
|
||||
"TripayPayment_Channel": "TripayPayment Channel",
|
||||
"Payment_Channel": "Payment Channel",
|
||||
"Payment_check_failed_": "Payment check failed.",
|
||||
"Order_Package": "Order Package",
|
||||
"Transactions": "Transactions",
|
||||
"Payments": "Payments",
|
||||
"History": "History",
|
||||
"Order_History": "Order History",
|
||||
"Gateway": "Gateway",
|
||||
"Date_Done": "Date Done",
|
||||
"Unpaid_Order": "Unpaid Order",
|
||||
"Payment_Gateway_Not_Found": "Payment Gateway Not Found",
|
||||
"Payment_Gateway_saved_successfully": "Payment Gateway saved successfully",
|
||||
"ORDER": "ORDER",
|
||||
"Package_History": "Package History",
|
||||
"Buy_History": "Buy History",
|
||||
"Activation_History": "Activation History",
|
||||
"Buy_Package": "Buy Package",
|
||||
"Email": "Email",
|
||||
"Company_Footer": "Company Footer",
|
||||
"Will_show_below_user_pages": "Will show below user pages",
|
||||
"Request_OTP": "Request OTP",
|
||||
"Verification_Code": "Verification Code",
|
||||
"SMS_Verification_Code": "SMS Verification Code",
|
||||
"Please_enter_your_email_address": "Please enter your email address",
|
||||
"Failed_to_create_Paypal_transaction_": "Failed to create Paypal transaction.",
|
||||
"Payment_Gateway": "Pasarela de Pago",
|
||||
"Community": "Comunidad",
|
||||
"1_user_can_be_used_for_many_devices_": "1 usuario puede utilizarse para varios dispositivos?",
|
||||
"Cannot_be_change_after_saved": "No se puede cambiar despu\u00e9s de guardar",
|
||||
"Explain_Coverage_of_router": "Explicar la cobertura del enrutador",
|
||||
"Name_of_Area_that_router_operated": "Nombre del \u00e1rea que operaba el enrutador",
|
||||
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL de notificaci\u00f3n de pago, URL de notificaci\u00f3n recurrente, URL de notificaci\u00f3n de cuenta de pago",
|
||||
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "URL de redireccionamiento finalizada, URL de redireccionamiento incompleta, URL de redireccionamiento con error",
|
||||
"Status": "Estado",
|
||||
"Plan_Not_found": "Plan no encontrado",
|
||||
"Failed_to_create_transaction_": "No se pudo crear la transacci\u00f3n.",
|
||||
"Seller_has_not_yet_setup_Xendit_payment_gateway": "El vendedor a\u00fan no ha configurado la pasarela de pago Xendit",
|
||||
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "El administrador a\u00fan no ha configurado la pasarela de pago Xendit, inf\u00f3rmeselo al administrador.",
|
||||
"Buy_this__your_active_package_will_be_overwrite": "\u00bfCompraste esto? Tu paquete activo se sobrescribir\u00e1",
|
||||
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "Ya tienes transacci\u00f3n impaga, canc\u00e9lala o p\u00e1gala.",
|
||||
"Transaction_Not_found": "Transacci\u00f3n no encontrada",
|
||||
"Cancel_it_": "\u00bfCancelalo?",
|
||||
"expired": "Caducada",
|
||||
"Check_for_Payment": "Verificar pago",
|
||||
"Transaction_still_unpaid_": "Transacci\u00f3n a\u00fan impaga.",
|
||||
"Paid_Date": "Fecha de pago",
|
||||
"Transaction_has_been_paid_": "La transacci\u00f3n ha sido pagada.",
|
||||
"PAID": "PAGADA",
|
||||
"CANCELED": "CANCELADA",
|
||||
"UNPAID": "NO PAGADO",
|
||||
"PAY_NOW": "PAGAR AHORA",
|
||||
"Buy_Hotspot_Plan": "Comprar plan de hotspot",
|
||||
"Buy_PPOE_Plan": "Comprar Plan PPPoE",
|
||||
"Package": "Paquete",
|
||||
"Order_Internet_Package": "Solicitar paquete de Internet",
|
||||
"Unknown_Command_": "Comando desconocido.",
|
||||
"Checking_payment": "Comprobando el pago",
|
||||
"Create_Transaction_Success": "Crear transacciones exitosas",
|
||||
"You_have_unpaid_transaction": "Tienes transacci\u00f3n impaga",
|
||||
"TripayPayment_Channel": "Canal de pago Tripay",
|
||||
"Payment_Channel": "Canal de pago",
|
||||
"Payment_check_failed_": "El cheque de pago fall\u00f3.",
|
||||
"Order_Package": "Paquete de pedido",
|
||||
"Transactions": "Transacciones",
|
||||
"Payments": "Pagos",
|
||||
"History": "Historial",
|
||||
"Order_History": "Historial de pedidos",
|
||||
"Gateway": "Puerta",
|
||||
"Date_Done": "Fecha de finalizaci\u00f3n",
|
||||
"Unpaid_Order": "Orden no pagada",
|
||||
"Payment_Gateway_Not_Found": "Pasarela de pago no encontrada",
|
||||
"Payment_Gateway_saved_successfully": "Pasarela de pago guardada exitosamente",
|
||||
"ORDER": "ORDEN",
|
||||
"Package_History": "Historial de paquetes",
|
||||
"Buy_History": "Historial de compra",
|
||||
"Activation_History": "Historial de activaci\u00f3n",
|
||||
"Buy_Package": "Comprar paquete",
|
||||
"Email": "Correo",
|
||||
"Company_Footer": "Pie de p\u00e1gina",
|
||||
"Will_show_below_user_pages": "Se mostrar\u00e1n debajo de las p\u00e1ginas de usuario.",
|
||||
"Request_OTP": "Solicitar OTP",
|
||||
"Verification_Code": "Verificacion por codigo",
|
||||
"SMS_Verification_Code": "C\u00f3digo de verificaci\u00f3n por SMS",
|
||||
"Please_enter_your_email_address": "Por favor, introduzca su direcci\u00f3n de correo electr\u00f3nico",
|
||||
"Failed_to_create_Paypal_transaction_": "No se pudo crear la transacci\u00f3n de Paypal.",
|
||||
"Plugin": "Plugin",
|
||||
"Plugin_Manager": "Plugin Manager",
|
||||
"User_Notification": "User Notification",
|
||||
"Expired_Notification": "Expired Notification",
|
||||
"User_will_get_notification_when_package_expired": "User will get notification when package expired",
|
||||
"Expired_Notification_Message": "Expired Notification Message",
|
||||
"Payment_Notification": "Payment Notification",
|
||||
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "User will get invoice notification when buy package or package refilled",
|
||||
"Current_IP": "Current IP",
|
||||
"Current_MAC": "Current MAC",
|
||||
"Login_Status": "Login Status",
|
||||
"Login_Request_successfully": "Login Request successfully",
|
||||
"Logout_Request_successfully": "Logout Request successfully",
|
||||
"Disconnect_Internet_": "Disconnect Internet?",
|
||||
"Not_Online__Login_now_": "Not Online, Login now?",
|
||||
"You_are_Online__Logout_": "You are Online, Logout?",
|
||||
"Connect_to_Internet_": "Connect to Internet?",
|
||||
"Your_account_not_connected_to_internet": "Your account not connected to internet",
|
||||
"Balance": "Balance",
|
||||
"Balance_System": "Balance System",
|
||||
"Enable_System": "Enable System",
|
||||
"Allow_Transfer": "Allow Transfer",
|
||||
"Telegram_Notification": "Telegram Notification",
|
||||
"SMS_OTP_Registration": "SMS OTP Registration",
|
||||
"Whatsapp_Notification": "Whatsapp Notification",
|
||||
"Plugin_Manager": "Administraci\u00f3n de Plugins",
|
||||
"User_Notification": "Notificaci\u00f3n de usuario",
|
||||
"Expired_Notification": "Notificaci\u00f3n caducada",
|
||||
"User_will_get_notification_when_package_expired": "El usuario recibir\u00e1 una notificaci\u00f3n cuando el paquete caduque",
|
||||
"Expired_Notification_Message": "Mensaje de notificaci\u00f3n caducado",
|
||||
"Payment_Notification": "Notificacion de pago",
|
||||
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "El usuario recibir\u00e1 una notificaci\u00f3n de factura cuando compre el paquete o recargue el paquete.",
|
||||
"Current_IP": "IP actual",
|
||||
"Current_MAC": "MAC actual",
|
||||
"Login_Status": "Estado de inicio de sesi\u00f3n",
|
||||
"Login_Request_successfully": "Solicitud de inicio de sesi\u00f3n exitosa",
|
||||
"Logout_Request_successfully": "Solicitud de cierre de sesi\u00f3n exitosa",
|
||||
"Disconnect_Internet_": "\u00bfDesconectar Internet?",
|
||||
"Not_Online__Login_now_": "No en l\u00ednea, \u00bfiniciar sesi\u00f3n ahora?",
|
||||
"You_are_Online__Logout_": "Est\u00e1s en l\u00ednea, \u00bfcerrar sesi\u00f3n?",
|
||||
"Connect_to_Internet_": "\u00bfConectado a Internet?",
|
||||
"Your_account_not_connected_to_internet": "Su cuenta no est\u00e1 conectada a Internet",
|
||||
"Balance": "Saldo",
|
||||
"Balance_System": "Sistema de Saldo",
|
||||
"Enable_System": "Habilitar sistema",
|
||||
"Allow_Transfer": "Permitir transferencia",
|
||||
"Telegram_Notification": "Notificaci\u00f3n de Telegram",
|
||||
"SMS_OTP_Registration": "Registro OTP por SMS",
|
||||
"Whatsapp_Notification": "Notificaci\u00f3n de whatsapp",
|
||||
"Tawk_to_Chat_Widget": "Tawk.to Chat Widget",
|
||||
"Invoice": "Invoice",
|
||||
"Country_Code_Phone": "Country Code Phone",
|
||||
"Voucher_activation_menu_will_be_hidden": "Voucher activation menu will be hidden",
|
||||
"Customer_can_deposit_money_to_buy_voucher": "Customer can deposit money to buy voucher",
|
||||
"Allow_balance_transfer_between_customers": "Allow balance transfer between customers",
|
||||
"Refill_Balance": "Refill Balance",
|
||||
"Balance_Plans": "Balance Plans",
|
||||
"Failed_to_create_transaction__": "Failed to create transaction. ",
|
||||
"Failed_to_check_status_transaction__": "Failed to check status transaction. ",
|
||||
"Disable_Voucher": "Disable Voucher",
|
||||
"Reminder_Notification": "Reminder Notification",
|
||||
"Reminder_Notification_Message": "Reminder Notification Message",
|
||||
"Reminder_7_days": "Reminder 7 days",
|
||||
"Reminder_3_days": "Reminder 3 days",
|
||||
"Reminder_1_day": "Reminder 1 day",
|
||||
"PPPOE_Password": "PPPOE Password",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
|
||||
"Invoice_Balance_Message": "Invoice Balance Message",
|
||||
"Invoice_Notification_Payment": "Invoice Notification Payment",
|
||||
"Balance_Notification_Payment": "Balance Notification Payment",
|
||||
"Buy_Balance": "Buy Balance",
|
||||
"Price": "Price",
|
||||
"Validity": "Validity",
|
||||
"Disable_auto_renewal_": "Disable auto renewal?",
|
||||
"Auto_Renewal_On": "Auto Renewal On",
|
||||
"Enable_auto_renewal_": "Enable auto renewal?",
|
||||
"Auto_Renewal_Off": "Auto Renewal Off",
|
||||
"Invoice_Footer": "Invoice Footer",
|
||||
"Pay_With_Balance": "Pay With Balance",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Pay this with Balance? your active package will be overwrite",
|
||||
"Success_to_buy_package": "Success to buy package",
|
||||
"Auto_Renewal": "Auto Renewal",
|
||||
"View": "View",
|
||||
"Back": "Back",
|
||||
"Active": "Active",
|
||||
"Transfer_Balance": "Transfer Balance",
|
||||
"Send_your_balance_": "Send your balance?",
|
||||
"Send": "Send",
|
||||
"Cannot_send_to_yourself": "Cannot send to yourself",
|
||||
"Sending_balance_success": "Sending balance success",
|
||||
"From": "From",
|
||||
"To": "To",
|
||||
"insufficient_balance": "insufficient balance",
|
||||
"Send_Balance": "Send Balance",
|
||||
"Received_Balance": "Received Balance",
|
||||
"Minimum_Balance_Transfer": "Minimum Balance Transfer",
|
||||
"Minimum_Transfer": "Minimum Transfer",
|
||||
"Company_Logo": "Company Logo",
|
||||
"Expired_IP_Pool": "Expired IP Pool",
|
||||
"Invoice": "Factura",
|
||||
"Country_Code_Phone": "C\u00f3digo de pa\u00eds Tel\u00e9fono",
|
||||
"Voucher_activation_menu_will_be_hidden": "El men\u00fa de activaci\u00f3n del vale estar\u00e1 oculto",
|
||||
"Customer_can_deposit_money_to_buy_voucher": "El cliente puede depositar dinero para comprar un vale.",
|
||||
"Allow_balance_transfer_between_customers": "Permitir transferencia de saldo entre clientes",
|
||||
"Refill_Balance": "Saldo de recarga",
|
||||
"Balance_Plans": "Planes de Saldo",
|
||||
"Failed_to_create_transaction__": "No se pudo crear la transacci\u00f3n.",
|
||||
"Failed_to_check_status_transaction__": "No se pudo verificar el estado de la transacci\u00f3n.",
|
||||
"Disable_Voucher": "Desactivar Fichas",
|
||||
"Reminder_Notification": "Notificaci\u00f3n de recordatorio",
|
||||
"Reminder_Notification_Message": "Mensaje de notificaci\u00f3n de recordatorio",
|
||||
"Reminder_7_days": "Recordatorio 7 d\u00edas",
|
||||
"Reminder_3_days": "Recordatorio 3 d\u00edas",
|
||||
"Reminder_1_day": "Recordatorio 1 d\u00edas",
|
||||
"PPPOE_Password": "Contrase\u00f1a PPPOE",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "El usuario no puede cambiar esto, solo el administrador. si est\u00e1 vac\u00edo usar\u00e1 la contrase\u00f1a de usuario",
|
||||
"Invoice_Balance_Message": "Mensaje de saldo de factura",
|
||||
"Invoice_Notification_Payment": "Pago de notificaci\u00f3n de factura",
|
||||
"Balance_Notification_Payment": "Pago de notificaci\u00f3n de saldo",
|
||||
"Buy_Balance": "Comprar Saldo",
|
||||
"Price": "Precio",
|
||||
"Validity": "Validez",
|
||||
"Disable_auto_renewal_": "\u00bfDesactivar la renovaci\u00f3n autom\u00e1tica?",
|
||||
"Auto_Renewal_On": "Renovaci\u00f3n autom\u00e1tica activada",
|
||||
"Enable_auto_renewal_": "\u00bfHabilitar la renovaci\u00f3n autom\u00e1tica?",
|
||||
"Auto_Renewal_Off": "Renovaci\u00f3n autom\u00e1tica desactivada",
|
||||
"Invoice_Footer": "Pie de p\u00e1gina de factura",
|
||||
"Pay_With_Balance": "Pagar con saldo",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "\u00bfPagar esto con Saldo? su paquete activo ser\u00e1 sobrescrito",
|
||||
"Success_to_buy_package": "\u00c9xito al comprar el paquete.",
|
||||
"Auto_Renewal": "Auto renovaci\u00f3n",
|
||||
"View": "Vista",
|
||||
"Back": "Atras",
|
||||
"Active": "Activo",
|
||||
"Transfer_Balance": "Transferir saldo",
|
||||
"Send_your_balance_": "\u00bfEnviar tu saldo?",
|
||||
"Send": "Enviar",
|
||||
"Cannot_send_to_yourself": "No puedes enviarte a ti mismo",
|
||||
"Sending_balance_success": "Env\u00edo de saldo exitoso",
|
||||
"From": "De",
|
||||
"To": "A",
|
||||
"insufficient_balance": "Saldo Insuficiente",
|
||||
"Send_Balance": "Saldo Enviado",
|
||||
"Received_Balance": "Saldo Recibido",
|
||||
"Minimum_Balance_Transfer": "Transferencia de saldo m\u00ednimo",
|
||||
"Minimum_Transfer": "Transferencia m\u00ednima",
|
||||
"Company_Logo": "Logo de la compa\u00f1\u00eda",
|
||||
"Expired_IP_Pool": "Grupo de IP caducado",
|
||||
"Proxy": "Proxy",
|
||||
"Proxy_Server": "Proxy Server",
|
||||
"Proxy_Server_Login": "Proxy Server Login",
|
||||
"Proxy_Server": "Servidor Proxy",
|
||||
"Proxy_Server_Login": "Iniciar sesi\u00f3n en el servidor proxy",
|
||||
"Hotspot_Plan": "Hotspot Plan",
|
||||
"PPPOE_Plan": "PPPOE Plan",
|
||||
"UNKNOWN": "UNKNOWN",
|
||||
"Are_You_Sure_": "Are You Sure?",
|
||||
"Success_to_send_package": "Success to send package",
|
||||
"Target_has_active_plan__different_with_current_plant_": "Target has active plan, different with current plant.",
|
||||
"Recharge_a_friend": "Recharge a friend",
|
||||
"Buy_for_friend": "Buy for friend",
|
||||
"Buy_this_for_friend_account_": "Buy this for friend account?",
|
||||
"Review_package_before_recharge": "Review package before recharge",
|
||||
"Activate": "Activate",
|
||||
"Deactivate": "Deactivate",
|
||||
"Sync": "Sync",
|
||||
"Failed_to_create_PaymeTrust_transaction_": "Failed to create PaymeTrust transaction.",
|
||||
"Location": "Location",
|
||||
"Voucher_Format": "Voucher Format",
|
||||
"Service_Type": "Service Type",
|
||||
"Others": "Others",
|
||||
"PPPOE_Plan": "PPPoE Plan",
|
||||
"UNKNOWN": "DESCONOCIDO",
|
||||
"Are_You_Sure_": "Estas seguro\/a?",
|
||||
"Success_to_send_package": "\u00c9xito al enviar el paquete",
|
||||
"Target_has_active_plan__different_with_current_plant_": "Objetivo tiene plan activo, diferente con planta actual.",
|
||||
"Recharge_a_friend": "Recargar a un amigo\/a",
|
||||
"Buy_for_friend": "Comprar para amigo\/a",
|
||||
"Buy_this_for_friend_account_": "\u00bfCompra esto por cuenta de amigo\/a?",
|
||||
"Review_package_before_recharge": "Revisar paquete antes de recargar",
|
||||
"Activate": "Activado",
|
||||
"Deactivate": "Desactivado",
|
||||
"Sync": "Sincronizar",
|
||||
"Failed_to_create_PaymeTrust_transaction_": "No se pudo crear la transacci\u00f3n PaymeTrust.",
|
||||
"Location": "Localizacion",
|
||||
"Voucher_Format": "Formato de cup\u00f3n",
|
||||
"Service_Type": "Tipo de Servicios",
|
||||
"Others": "Otros",
|
||||
"PPPoE": "PPPoE",
|
||||
"Hotspot": "Hotspot",
|
||||
"Monthly_Registered_Customers": "Monthly Registered Customers",
|
||||
"Total_Monthly_Sales": "Total Monthly Sales",
|
||||
"Active_Users": "Active Users"
|
||||
"Monthly_Registered_Customers": "Clientes registrados mensualmente",
|
||||
"Total_Monthly_Sales": "Ventas mensuales totales",
|
||||
"Active_Users": "Usuarios activos",
|
||||
"Languge_set_to_spanish": "Idioma establecido en espa\u00f1ol",
|
||||
"Login": "Acceso",
|
||||
"Forgot_Password": "Has olvidado tu contrase\u00f1a",
|
||||
"success": "Logueado con Exito",
|
||||
"Click_Here": "Haga clic aqu\u00ed",
|
||||
"Search_Users": "Buscar usuarios",
|
||||
"SuperAdmin": "Superadministrador",
|
||||
"Lists": "Listas de Clientes",
|
||||
"Vouchers": "Fichas",
|
||||
"Refill_Customer": "Recarga de cliente",
|
||||
"Recharge_Customer": "Recargar Cliente",
|
||||
"Internet_Plan": "Plan de Internet",
|
||||
"Send_Message": "Enviar mensaje",
|
||||
"Single_Customer": "Cliente \u00fanico",
|
||||
"Bulk_Customers": "Clientes al por mayor",
|
||||
"Routers_Maps": "Mapas de enrutadores",
|
||||
"Theme_Voucher": "Cup\u00f3n tem\u00e1tico",
|
||||
"Customer_Announcement": "Anuncio para el cliente",
|
||||
"Payment_Info": "Informaci\u00f3n de pago",
|
||||
"Privacy_Policy": "Pol\u00edtica de Privacidad",
|
||||
"Terms_and_Conditions": "T\u00e9rminos y condiciones",
|
||||
"Maintenance_Mode": "Modo de mantenimiento",
|
||||
"Devices": "Dispositivos",
|
||||
"Logs": "Registros",
|
||||
"Documentation": "Documentaci\u00f3n",
|
||||
"Expired": "Venci\u00f3",
|
||||
"Customers": "Clientes",
|
||||
"Package_Name": "Nombre del paquete",
|
||||
"Created___Expired": "Creado \/ Expirado",
|
||||
"Internet_Package": "Paquete de Internet",
|
||||
"year": "A\u00f1o",
|
||||
"month": "Mes",
|
||||
"week": "Semana",
|
||||
"day": "D\u00eda",
|
||||
"hour": "Hora",
|
||||
"minute": "Minuto",
|
||||
"second": "Segundo",
|
||||
"ago": "Atr\u00e1s",
|
||||
"Prev": "Anterior",
|
||||
"Cron_Job_last_ran_on": "La \u00faltima ejecuci\u00f3n del trabajo cron se realiz\u00f3 el",
|
||||
"All_Users_Insights": "Informaci\u00f3n de todos los usuarios",
|
||||
"Created_Date": "Fecha de creaci\u00f3n",
|
||||
"Ascending": "Ascendente",
|
||||
"Descending": "Descendiendo",
|
||||
"Banned": "Prohibido",
|
||||
"Disabled": "Desactivado",
|
||||
"Inactive": "Inactivo",
|
||||
"Suspended": "Suspendido",
|
||||
"Add": "Agregar",
|
||||
"Account_Type": "Tipo de cuenta",
|
||||
"Contact": "Contacto",
|
||||
"Active_Customers": "Clientes activos",
|
||||
"Extend": "Extender",
|
||||
"Application_Name___Company_Name": "Nombre de la aplicaci\u00f3n \/ Nombre de la empresa",
|
||||
"For_PDF_Reports___Best_size_1078_x_200___uploaded_image_will_be_autosize": "Para informes en PDF | Tama\u00f1o \u00f3ptimo 1078 x 200 | La imagen cargada se ajustar\u00e1 autom\u00e1ticamente",
|
||||
"Print_Max_Char": "Imprimir Max Char",
|
||||
"For_invoice_print_using_Thermal_Printer": "Para imprimir facturas mediante impresora t\u00e9rmica",
|
||||
"Theme": "Tema",
|
||||
"Default": "Por defecto",
|
||||
"Theme_Info": "Informaci\u00f3n del tema",
|
||||
"Recharge_Using": "Recargar usando",
|
||||
"Cash": "Dinero",
|
||||
"Bank_Transfer": "Transferencia bancaria",
|
||||
"This_used_for_admin_to_select_payment_in_recharge__using_comma_for_every_new_options": "Esto se utiliza para que el administrador seleccione el pago en la recarga, utilizando una coma para cada nueva opci\u00f3n.",
|
||||
"Income_reset_date": "Fecha de reinicio de ingresos",
|
||||
"Income_will_reset_every_this_day": "Los ingresos se restablecer\u00e1n cada d\u00eda.",
|
||||
"edit_at_config_php": "editar en config.php",
|
||||
"Hide_Dashboard_Content": "Ocultar el contenido del panel",
|
||||
"No": "No",
|
||||
"Yes": "S\u00ed",
|
||||
"Disable_Registration": "Deshabilitar registro",
|
||||
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "El cliente solo debe iniciar sesi\u00f3n con su n\u00famero de tel\u00e9fono y el c\u00f3digo del cup\u00f3n. El cup\u00f3n ser\u00e1 su contrase\u00f1a.",
|
||||
"Redirect_URL_after_Activation": "Redireccionar URL despu\u00e9s de la activaci\u00f3n",
|
||||
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "Despu\u00e9s de que el Cliente active el cup\u00f3n o inicie sesi\u00f3n, ser\u00e1 redirigido a esta URL",
|
||||
"Enable_Radius": "Habilitar radio",
|
||||
"Radius_Instructions": "Instrucciones de radio",
|
||||
"Extend_Postpaid_Expiration": "Extender vencimiento de pospago",
|
||||
"Allow_Extend": "Permitir extender",
|
||||
"Customer_can_request_to_extend_expirations": "El cliente puede solicitar la extensi\u00f3n de los vencimientos.",
|
||||
"Extend_Days": "Extender d\u00edas",
|
||||
"Confirmation_Message": "Mensaje de confirmaci\u00f3n",
|
||||
"i_agree_to_extends_and_will_paid_full_after_this": "Acepto extender y pagar\u00e9 el total despu\u00e9s de esto.",
|
||||
"Customer_Balance_System": "Sistema de saldo de clientes",
|
||||
"Telegram_Bot_Token": "Token de bot de Telegram",
|
||||
"Telegram_User_Channel_Group_ID": "ID de usuario\/canal\/grupo de Telegram",
|
||||
"You_will_get_Payment_and_Error_notification": "Recibir\u00e1 una notificaci\u00f3n de pago y error.",
|
||||
"Test_SMS": "Prueba de SMS",
|
||||
"SMS_Server_URL": "URL del servidor SMS",
|
||||
"Must_include": "Debe incluir",
|
||||
"it_will_be_replaced_": "Ser\u00e1 reemplazado.",
|
||||
"Or_use_Mikrotik_SMS": "O utilice Mikrotik SMS",
|
||||
"Select_Router": "Seleccionar enrutador",
|
||||
"You_can_use": "Puedes utilizar",
|
||||
"in_here_too_": "Aqu\u00ed tambi\u00e9n.",
|
||||
"Free_Server": "Servidor gratuito",
|
||||
"WhatsApp_Server_URL": "URL del servidor de WhatsApp",
|
||||
"Email_Notification": "Notificaci\u00f3n por correo electr\u00f3nico",
|
||||
"Empty_this_to_use_internal_mail___PHP": "Vac\u00ede esto para usar el correo interno PHP",
|
||||
"SMTP_Username": "Nombre de usuario SMTP",
|
||||
"SMTP_Password": "Contrase\u00f1a SMTP",
|
||||
"SMTP_Security": "Seguridad SMTP",
|
||||
"Mail_Reply_To": "Responder a correo",
|
||||
"Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "El cliente responder\u00e1 el correo electr\u00f3nico a esta direcci\u00f3n; deje el campo vac\u00edo si desea utilizar la direcci\u00f3n de remitente.",
|
||||
"None": "Ninguno",
|
||||
"By_WhatsApp": "Por WhatsApp",
|
||||
"By_SMS": "Por SMS",
|
||||
"By_Email": "Por correo electr\u00f3nico",
|
||||
"From_Direct_Chat_Link_": "Desde el enlace de chat directo.",
|
||||
"Access_Token": "Token de acceso",
|
||||
"Empty_this_to_randomly_created_API_key": "Vac\u00ede esto para crear una clave API aleatoria",
|
||||
"This_Token_will_act_as_SuperAdmin_Admin": "Este token actuar\u00e1 como SuperAdmin\/Admin",
|
||||
"Miscellaneous": "Miscel\u00e1neas",
|
||||
"Enable_Session_Timeout": "Habilitar tiempo de espera de sesi\u00f3n",
|
||||
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Cerrar sesi\u00f3n como administrador si no est\u00e1 disponible o en l\u00ednea durante un per\u00edodo de tiempo",
|
||||
"Timeout_Duration": "Duraci\u00f3n del tiempo de espera",
|
||||
"Enter_the_session_timeout_duration__minutes_": "Introduzca la duraci\u00f3n del tiempo de espera de la sesi\u00f3n (minutos)",
|
||||
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Tiempo de espera inactivo, cerrar sesi\u00f3n como administrador si est\u00e1 inactivo durante xx minutos",
|
||||
"New_Version_Notification": "Notificaci\u00f3n de nueva versi\u00f3n",
|
||||
"Enabled": "Activado",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "Esto es para notificarle cuando haya nuevas actualizaciones disponibles.",
|
||||
"Router_Check": "Comprobaci\u00f3n del enrutador",
|
||||
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Si est\u00e1 habilitado, el sistema notificar\u00e1 al administrador cuando el enrutador se desconecte. Si el administrador tiene 10 o m\u00e1s enrutadores y muchos clientes, se superpondr\u00e1; puede deshabilitarlo.",
|
||||
"Phone_OTP_Required": "Se requiere OTP en el tel\u00e9fono",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "Se requiere OTP cuando el usuario desea cambiar el n\u00famero de tel\u00e9fono y el registro",
|
||||
"OTP_Method": "M\u00e9todo OTP",
|
||||
"by_WhatsApp": "por WhatsApp",
|
||||
"By_WhatsApp_and_SMS": "Por WhatsApp y SMS",
|
||||
"The_method_which_OTP_will_be_sent_to_user": "El m\u00e9todo mediante el cual se enviar\u00e1 la OTP al usuario",
|
||||
"Email_OTP_Required": "Se requiere OTP en el correo electr\u00f3nico",
|
||||
"OTP_is_required_when_user_want_to_change_Email_Address": "Se requiere OTP cuando el usuario desea cambiar la direcci\u00f3n de correo electr\u00f3nico",
|
||||
"Extend_Package_Expiry": "Extender la caducidad del paquete",
|
||||
"If_user_buy_same_internet_plan__expiry_date_will_extend": "Si el usuario compra el mismo plan de Internet, la fecha de vencimiento se extender\u00e1",
|
||||
"Show_Bandwidth_Plan": "Mostrar plan de ancho de banda",
|
||||
"_for_Customer": "Para el cliente",
|
||||
"Hotspot_Auth_Method": "M\u00e9todo de autenticaci\u00f3n de punto de acceso",
|
||||
"Api": "API",
|
||||
"Http_Chap": "Http-Chap",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "M\u00e9todo de autenticaci\u00f3n del punto de acceso. Aseg\u00farate de haber cambiado la p\u00e1gina de inicio de sesi\u00f3n del punto de acceso.",
|
||||
"Tax_System": "Sistema tributario",
|
||||
"Enable_Tax_System": "Habilitar el sistema tributario",
|
||||
"Tax_will_be_calculated_in_Internet_Plan_Price": "El impuesto se calcular\u00e1 en el precio del plan de Internet.",
|
||||
"Tax_Rate": "Tasa de impuesto",
|
||||
"Custome": "Personalizado",
|
||||
"Tax_Rates_in_percentage": "Tasas de impuestos en porcentaje",
|
||||
"Custome_Tax_Rate": "Tasa de impuesto al cliente",
|
||||
"Enter_Custome_Tax_Rate": "Introduzca la tasa de impuesto personalizada",
|
||||
"Enter_the_custom_tax_rate__e_g___3_75_for_3_75__": "Introduzca la tasa de impuesto personalizada (por ejemplo, 3,75 para 3,75 %)",
|
||||
"Authentication": "Autenticaci\u00f3n",
|
||||
"Github_Username": "Nombre de usuario de Github",
|
||||
"Github_Token": "Token de Github",
|
||||
"Create_GitHub_personal_access_token": "Crear un token de acceso personal de GitHub",
|
||||
"only_need_repo_scope": "Solo se necesita el \u00e1mbito del repositorio",
|
||||
"This_will_allow_you_to_download_plugin_from_private_paid_repository": "Esto le permitir\u00e1 descargar el complemento desde un repositorio privado\/pago.",
|
||||
"Expired_Cronjob_Every_5_Minutes": "Cronjob vencido cada 5 minutos",
|
||||
"Expired_Cronjob_Every_1_Hour": "Cronjob vencido cada 1 hora",
|
||||
"Reminder_Cronjob_Every_7_AM": "Recordatorio de Cronjob cada 7 a. m.",
|
||||
"Email_not_sent__Mailer_Error__": "Correo electr\u00f3nico no enviado, error de Mailer:",
|
||||
"Language_Editor": "Editor de idioma",
|
||||
"Radius_Package": "Paquete Radius",
|
||||
"Change_title_in_user_Plan_order": "Cambiar t\u00edtulo en el pedido del plan de usuario",
|
||||
"Hotspot_Package": "Paquete de punto de acceso",
|
||||
"PPPOE_Package": "Paquete PPPoE",
|
||||
"VPN_Package": "Paquete VPN",
|
||||
"Translation": "Traducci\u00f3n",
|
||||
"Agent": "Agente",
|
||||
"Session_has_expired__Please_log_in_again_": "La sesi\u00f3n ha expirado. Por favor, inicie sesi\u00f3n nuevamente.",
|
||||
"danger": "Peligro",
|
||||
"City": "Ciudad",
|
||||
"District": "Distrito",
|
||||
"State": "Estado",
|
||||
"Zip": "C\u00f3digo Postal",
|
||||
"Personal": "Personal",
|
||||
"Bandwidth": "Ancho de banda",
|
||||
"Translation_saved_Successfully": "La traducci\u00f3n se guard\u00f3 correctamente",
|
||||
"Filter": "Filtrar",
|
||||
"Show_chart": "Mostrar gr\u00e1fico",
|
||||
"Start_Date": "Fecha de inicio",
|
||||
"Start_time": "Hora de inicio",
|
||||
"End_Date": "Fecha de finalizaci\u00f3n",
|
||||
"End_Time": "Fin del tiempo",
|
||||
"Internet_Plans": "Planes de Internet",
|
||||
"Methods": "M\u00e9todos",
|
||||
"AREA1": "\u00c1REA 1",
|
||||
"AREA2": "\u00c1REA 2",
|
||||
"AREA4": "\u00c1REA 4",
|
||||
"AREA3": "\u00c1REA 3",
|
||||
"MK_ADMIN": "Administrador de MK",
|
||||
"AREA6": "\u00c1REA 6",
|
||||
"Max_30_days": "M\u00e1ximo 30 d\u00edas",
|
||||
"Total": "Total",
|
||||
"Information": "Informaci\u00f3n",
|
||||
"Export_and_Print_will_show_all_data_without_pagination": "Exportar e imprimir mostrar\u00e1 todos los datos sin paginaci\u00f3n"
|
||||
}
|
@ -59,75 +59,133 @@
|
||||
"2024.2.19": [
|
||||
"CREATE TABLE `tbl_customers_fields` (`id` INT PRIMARY KEY AUTO_INCREMENT, `customer_id` INT NOT NULL, `field_name` VARCHAR(255) NOT NULL, `field_value` VARCHAR(255) NOT NULL, FOREIGN KEY (customer_id) REFERENCES tbl_customers(id));"
|
||||
],
|
||||
"2024.2.20" : [
|
||||
"2024.2.20": [
|
||||
"ALTER TABLE `tbl_plans` ADD `list_expired` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'address list' AFTER `pool_expired`;",
|
||||
"ALTER TABLE `tbl_bandwidth` ADD `burst` VARCHAR(128) NOT NULL DEFAULT '' AFTER `rate_up_unit`;"
|
||||
],
|
||||
"2024.2.20.1" : [
|
||||
"2024.2.20.1": [
|
||||
"DROP TABLE IF EXISTS `tbl_customers_meta`;"
|
||||
],
|
||||
"2024.2.23" : [
|
||||
"2024.2.23": [
|
||||
"ALTER TABLE `tbl_transactions` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;",
|
||||
"ALTER TABLE `tbl_user_recharges` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;"
|
||||
],
|
||||
"2024.3.3" : [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `validity_unit` `validity_unit` ENUM('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
"2024.3.3": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `validity_unit` `validity_unit` ENUM('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2024.3.12" : [
|
||||
"2024.3.12": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';"
|
||||
],
|
||||
"2024.3.14" : [
|
||||
"2024.3.14": [
|
||||
"ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;"
|
||||
],
|
||||
"2024.3.19" : [
|
||||
"2024.3.19": [
|
||||
"ALTER TABLE `tbl_customers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates' AFTER `email`;"
|
||||
],
|
||||
"2024.3.19.1" : [
|
||||
"2024.3.19.1": [
|
||||
"ALTER TABLE `tbl_customers` ADD `account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' AFTER `coordinates`;"
|
||||
],
|
||||
"2024.3.19.2" : [
|
||||
"2024.3.19.2": [
|
||||
"ALTER TABLE `tbl_plans` ADD `plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' ;"
|
||||
],
|
||||
"2023.3.20": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
|
||||
],
|
||||
"2024.4.5" : [
|
||||
"2024.4.5": [
|
||||
"ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;"
|
||||
],
|
||||
"2024.5.17" : [
|
||||
"2024.5.17": [
|
||||
"ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.5.18" : [
|
||||
"2024.5.18": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';"
|
||||
],
|
||||
"2024.5.20" : [
|
||||
"2024.5.20": [
|
||||
"ALTER TABLE `tbl_customers` ADD `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `address`, ADD `district` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `city`, ADD `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `district`, ADD `zip` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `state`;"
|
||||
],
|
||||
"2024.6.5" : [
|
||||
"2024.6.5": [
|
||||
"ALTER TABLE `tbl_plans` ADD `price_old` VARCHAR(40) NOT NULL DEFAULT '' AFTER `price`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `device` VARCHAR(32) NOT NULL DEFAULT '' AFTER `plan_type`;"
|
||||
],
|
||||
"2024.6.10" : [
|
||||
"2024.6.10": [
|
||||
"ALTER TABLE `tbl_pool` ADD `local_ip` VARCHAR(40) NOT NULL DEFAULT '' AFTER `pool_name`;"
|
||||
],
|
||||
"2024.6.11" : [
|
||||
"2024.6.11": [
|
||||
"ALTER TABLE `tbl_plans` ADD `plan_expired` INT NOT NULL DEFAULT '0' AFTER `pool`;",
|
||||
"ALTER TABLE `tbl_plans` DROP `pool_expired`, DROP `list_expired`;"
|
||||
],
|
||||
"2024.6.19" : [
|
||||
"2024.6.19": [
|
||||
"ALTER TABLE `tbl_plans` ADD `expired_date` TINYINT(1) NOT NULL DEFAULT '20' AFTER `plan_expired`;"
|
||||
],
|
||||
"2024.6.21" : [
|
||||
"2024.6.21": [
|
||||
"ALTER TABLE `tbl_plans` ADD `on_login` TEXT NULL DEFAULT NULL AFTER `device`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `on_logout` TEXT NULL DEFAULT NULL AFTER `on_login`;"
|
||||
],
|
||||
"2024.7.6" : [
|
||||
"2024.7.6": [
|
||||
"CREATE TABLE IF NOT EXISTS `rad_acct` ( `id` bigint NOT NULL, `acctsessionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `realm` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasid` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `rad_acct` ADD PRIMARY KEY (`id`), ADD KEY `username` (`username`), ADD KEY `framedipaddress` (`framedipaddress`), ADD KEY `acctsessionid` (`acctsessionid`), ADD KEY `nasipaddress` (`nasipaddress`);",
|
||||
"ALTER TABLE `rad_acct` MODIFY `id` bigint NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2024.7.24" : [
|
||||
"2024.7.24": [
|
||||
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
|
||||
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
|
||||
],
|
||||
"2024.8.1": [
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
|
||||
],
|
||||
"2024.8.2": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_customers_inbox` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `date_created` datetime NOT NULL, `date_read` datetime DEFAULT NULL, `subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL, `body` TEXT NULL DEFAULT NULL, `from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2024.8.5": [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `pppoe_password`;"
|
||||
],
|
||||
"2024.8.5.1": [
|
||||
"ALTER TABLE `tbl_routers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' AFTER `description`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `coverage` VARCHAR(8) NOT NULL DEFAULT '0' AFTER `coordinates`;"
|
||||
],
|
||||
"2024.8.6": [
|
||||
"ALTER TABLE `rad_acct` ADD `acctinputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `framedipaddress`;",
|
||||
"ALTER TABLE `rad_acct` ADD `acctoutputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `acctinputoctets`;"
|
||||
],
|
||||
"2024.8.7": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `coordinates` `coordinates` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates';"
|
||||
],
|
||||
"2024.8.28": [
|
||||
"ALTER TABLE `tbl_routers` ADD `status` ENUM('Online', 'Offline') DEFAULT 'Online' AFTER `coordinates`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `last_seen` DATETIME AFTER `status`;"
|
||||
],
|
||||
"2024.9.13": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_customers` CHANGE `service_type` `service_type` ENUM('Hotspot','PPPoE','VPN','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Others' COMMENT 'For selecting user type';",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_port_pool` ( `id` int(10) NOT NULL AUTO_INCREMENT , `public_ip` varchar(40) NOT NULL, `port_name` varchar(40) NOT NULL, `range_port` varchar(40) NOT NULL, `routers` varchar(40) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2024.10.10": [
|
||||
"ALTER TABLE `tbl_users` ADD `login_token` VARCHAR(40) AFTER `last_login`;"
|
||||
],
|
||||
"2024.10.17": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_meta` ( `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name', `tbl_id` int NOT NULL COMMENT 'table value id', `name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL, `value` mediumtext COLLATE utf8mb4_general_ci, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';"
|
||||
],
|
||||
"2024.10.30": [
|
||||
"ALTER TABLE `tbl_users` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png' AFTER `root`;",
|
||||
"ALTER TABLE `tbl_users` ADD `data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data' AFTER `status`;"
|
||||
],
|
||||
"2024.10.31": [
|
||||
"ALTER TABLE `tbl_customers` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg' AFTER `password`;"
|
||||
],
|
||||
"2024.12.5.1": [
|
||||
"ALTER TABLE `tbl_transactions` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;",
|
||||
"ALTER TABLE `tbl_payment_gateway` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;"
|
||||
],
|
||||
"2024.12.16": [
|
||||
"CREATE TABLE `tbl_coupons` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(50) NOT NULL UNIQUE, `type` ENUM('fixed', 'percent') NOT NULL, `value` DECIMAL(10,2) NOT NULL, `description` TEXT NOT NULL, `max_usage` INT NOT NULL DEFAULT 1,`usage_count` INT NOT NULL DEFAULT 0,`status` ENUM('active', 'inactive') NOT NULL, `min_order_amount` DECIMAL(10,2) NOT NULL, `max_discount_amount` DECIMAL(10,2) NOT NULL, `start_date` DATE NOT NULL,`end_date` DATE NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);"
|
||||
],
|
||||
"2024.12.20": [
|
||||
"ALTER TABLE `tbl_voucher` ADD `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;"
|
||||
],
|
||||
"2025.1.23": [
|
||||
"ALTER TABLE `rad_acct` ADD `acctsessiontime` BIGINT(12) NOT NULL DEFAULT '0' AFTER `framedipaddress`;"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
BIN
system/uploads/favicon.default.png
Normal file
BIN
system/uploads/favicon.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1002 B |
BIN
system/uploads/login-logo.default.png
Normal file
BIN
system/uploads/login-logo.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
@ -6,5 +6,7 @@
|
||||
"reminder_3_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 3 days.",
|
||||
"reminder_1_day": "Hello *[[name]]*,\r\n your internet package *[[package]]* will be expired tomorrow.",
|
||||
"invoice_paid": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\nUsername : *[[user_name]]*\r\nPassword : ***********\r\n\r\nExpired : *[[expired_date]]*\r\n\r\n====================\r\n[[footer]]",
|
||||
"invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]"
|
||||
"invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]",
|
||||
"welcome_message": "Welcome aboard, [[name]]! \r\nWe're excited to have you as a new [[company]] customer. \r\nYour account is all set up and ready to go.\r\n\r\nHere's a quick overview:\r\n\r\nPortal: [[url]]\r\nYour login is [[Username]]\r\nYour temporary password is [[Password]] (please change this on your first login)\r\n\r\nNeed help? Reach out to our support team at anytime.\r\n\r\nWe're here to ensure you have an amazing experience with our services. Let us know how we can best support you.\r\n\r\nWelcome to the [[company]] family!"
|
||||
|
||||
}
|
||||
|
BIN
system/uploads/wallpaper.default.png
Normal file
BIN
system/uploads/wallpaper.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
2
system/vendor/composer/autoload_classmap.php
vendored
2
system/vendor/composer/autoload_classmap.php
vendored
@ -176,4 +176,6 @@ return array(
|
||||
'Smarty_Variable' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_variable.php',
|
||||
'TPC_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php',
|
||||
'TP_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php',
|
||||
'svay\\Exception\\NoFaceException' => $vendorDir . '/yosiazwan/php-facedetection/Exception/NoFaceException.php',
|
||||
'svay\\FaceDetector' => $vendorDir . '/yosiazwan/php-facedetection/FaceDetector.php',
|
||||
);
|
||||
|
2
system/vendor/composer/autoload_real.php
vendored
2
system/vendor/composer/autoload_real.php
vendored
@ -22,8 +22,6 @@ class ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367', 'loadClassLoader'));
|
||||
|
2
system/vendor/composer/autoload_static.php
vendored
2
system/vendor/composer/autoload_static.php
vendored
@ -229,6 +229,8 @@ class ComposerStaticInit405fa5c7a0972c286ef93b1161b83367
|
||||
'Smarty_Variable' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_variable.php',
|
||||
'TPC_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php',
|
||||
'TP_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php',
|
||||
'svay\\Exception\\NoFaceException' => __DIR__ . '/..' . '/yosiazwan/php-facedetection/Exception/NoFaceException.php',
|
||||
'svay\\FaceDetector' => __DIR__ . '/..' . '/yosiazwan/php-facedetection/FaceDetector.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
45
system/vendor/composer/installed.json
vendored
45
system/vendor/composer/installed.json
vendored
@ -494,6 +494,51 @@
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.5.3"
|
||||
},
|
||||
"install-path": "../smarty/smarty"
|
||||
},
|
||||
{
|
||||
"name": "yosiazwan/php-facedetection",
|
||||
"version": "0.1.0",
|
||||
"version_normalized": "0.1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yosiazwan/php-facedetection.git",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yosiazwan/php-facedetection/zipball/b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"time": "2016-01-26T22:10:00+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "source",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"FaceDetector.php",
|
||||
"Exception/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maurice Svay",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to detect one face in images. A pure PHP port of an existing JS code from Karthik Tharavad.",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection",
|
||||
"support": {
|
||||
"source": "https://github.com/yosiazwan/php-facedetection/tree/0.1.0"
|
||||
},
|
||||
"install-path": "../yosiazwan/php-facedetection"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
|
13
system/vendor/composer/installed.php
vendored
13
system/vendor/composer/installed.php
vendored
@ -3,7 +3,7 @@
|
||||
'name' => '__root__',
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'a9c0e955937e3ccb2ff050c71b77353b298a982b',
|
||||
'reference' => '925c24cbd822f776eb913df987a063f95c6d9cc0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@ -13,7 +13,7 @@
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'a9c0e955937e3ccb2ff050c71b77353b298a982b',
|
||||
'reference' => '925c24cbd822f776eb913df987a063f95c6d9cc0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@ -91,5 +91,14 @@
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'yosiazwan/php-facedetection' => array(
|
||||
'pretty_version' => '0.1.0',
|
||||
'version' => '0.1.0.0',
|
||||
'reference' => 'b016273ceceacd85562bbc50384fbabc947fe525',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../yosiazwan/php-facedetection',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
26
system/vendor/composer/platform_check.php
vendored
26
system/vendor/composer/platform_check.php
vendored
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 70200)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
BIN
system/vendor/mpdf/mpdf/ttfonts/DejaVuSansMono.ttf
vendored
Normal file
BIN
system/vendor/mpdf/mpdf/ttfonts/DejaVuSansMono.ttf
vendored
Normal file
Binary file not shown.
@ -131,6 +131,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
|
||||
public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)
|
||||
{
|
||||
// display template
|
||||
$template = str_replace("section/user-",'customer/', $template);
|
||||
$this->_execute($template, $cache_id, $compile_id, $parent, 1);
|
||||
}
|
||||
|
||||
|
13
system/vendor/yosiazwan/php-facedetection/Exception/NoFaceException.php
vendored
Normal file
13
system/vendor/yosiazwan/php-facedetection/Exception/NoFaceException.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Throws exception if face was not detected in `faceDetect` call.
|
||||
*/
|
||||
|
||||
namespace svay\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NoFaceException extends Exception {
|
||||
|
||||
}
|
396
system/vendor/yosiazwan/php-facedetection/FaceDetector.php
vendored
Normal file
396
system/vendor/yosiazwan/php-facedetection/FaceDetector.php
vendored
Normal file
@ -0,0 +1,396 @@
|
||||
<?php
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// @Author Karthik Tharavaad
|
||||
// karthik_tharavaad@yahoo.com
|
||||
// @Contributor Maurice Svay
|
||||
// maurice@svay.Com
|
||||
|
||||
namespace svay;
|
||||
|
||||
use Exception;
|
||||
use svay\Exception\NoFaceException;
|
||||
|
||||
class FaceDetector
|
||||
{
|
||||
|
||||
protected $detection_data;
|
||||
protected $canvas;
|
||||
protected $face;
|
||||
private $reduced_canvas;
|
||||
protected $timeout = null;
|
||||
protected $time_start;
|
||||
|
||||
/**
|
||||
* Creates a face-detector with the given configuration
|
||||
*
|
||||
* Configuration can be either passed as an array or as
|
||||
* a filepath to a serialized array file-dump
|
||||
*
|
||||
* @param string|array $detection_data
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($detection_data = 'detection.json')
|
||||
{
|
||||
if (is_array($detection_data)) {
|
||||
$this->detection_data = $detection_data;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_file($detection_data)) {
|
||||
// fallback to same file in this class's directory
|
||||
$detection_data = dirname(__FILE__) . DIRECTORY_SEPARATOR . $detection_data;
|
||||
|
||||
if (!is_file($detection_data)) {
|
||||
throw new \Exception("Couldn't load detection data");
|
||||
}
|
||||
}
|
||||
|
||||
$this->detection_data = json_decode(file_get_contents($detection_data));
|
||||
}
|
||||
|
||||
public function setTimeout($micro_seconds)
|
||||
{
|
||||
$this->timeout = $micro_seconds;
|
||||
}
|
||||
|
||||
public function faceDetect($file)
|
||||
{
|
||||
$this->time_start = microtime();
|
||||
if (is_resource($file)) {
|
||||
|
||||
$this->canvas = $file;
|
||||
} elseif (is_file($file)) {
|
||||
|
||||
$this->canvas = imagecreatefromjpeg($file);
|
||||
} elseif (is_string($file)) {
|
||||
|
||||
$this->canvas = imagecreatefromstring($file);
|
||||
} else {
|
||||
|
||||
throw new Exception("Can not load $file");
|
||||
}
|
||||
|
||||
$sharpen = array(
|
||||
array(0.0, -1.0, 0.0),
|
||||
array(-1.0, 5.0, -1.0),
|
||||
array(0.0, -1.0, 0.0)
|
||||
);
|
||||
|
||||
$divisor = array_sum(array_map('array_sum', $sharpen));
|
||||
|
||||
imageconvolution($this->canvas, $sharpen, $divisor, 0);
|
||||
|
||||
$im_width = imagesx($this->canvas);
|
||||
$im_height = imagesy($this->canvas);
|
||||
|
||||
//Resample before detection?
|
||||
$diff_width = 320 - $im_width;
|
||||
$diff_height = 240 - $im_height;
|
||||
if ($diff_width > $diff_height) {
|
||||
$ratio = $im_width / 320;
|
||||
} else {
|
||||
$ratio = $im_height / 240;
|
||||
}
|
||||
|
||||
if ($ratio != 0) {
|
||||
$this->reduced_canvas = imagecreatetruecolor($im_width / $ratio, $im_height / $ratio);
|
||||
|
||||
imagecopyresampled(
|
||||
$this->reduced_canvas,
|
||||
$this->canvas,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$im_width / $ratio,
|
||||
$im_height / $ratio,
|
||||
$im_width,
|
||||
$im_height
|
||||
);
|
||||
|
||||
$stats = $this->getImgStats($this->reduced_canvas);
|
||||
|
||||
$this->face = $this->doDetectGreedyBigToSmall(
|
||||
$stats['ii'],
|
||||
$stats['ii2'],
|
||||
$stats['width'],
|
||||
$stats['height']
|
||||
);
|
||||
|
||||
if ($this->face['w'] > 0) {
|
||||
$this->face['x'] *= $ratio;
|
||||
$this->face['y'] *= $ratio;
|
||||
$this->face['w'] *= $ratio;
|
||||
}
|
||||
} else {
|
||||
$stats = $this->getImgStats($this->canvas);
|
||||
|
||||
$this->face = $this->doDetectGreedyBigToSmall(
|
||||
$stats['ii'],
|
||||
$stats['ii2'],
|
||||
$stats['width'],
|
||||
$stats['height']
|
||||
);
|
||||
}
|
||||
return ($this->face['w'] > 0);
|
||||
}
|
||||
|
||||
|
||||
public function toJpeg()
|
||||
{
|
||||
$color = imagecolorallocate($this->canvas, 255, 0, 0); //red
|
||||
|
||||
imagerectangle(
|
||||
$this->canvas,
|
||||
$this->face['x'],
|
||||
$this->face['y'],
|
||||
$this->face['x'] + $this->face['w'],
|
||||
$this->face['y'] + $this->face['w'],
|
||||
$color
|
||||
);
|
||||
|
||||
header('Content-type: image/jpeg');
|
||||
imagejpeg($this->canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the face from the photo.
|
||||
* Should be called after `faceDetect` function call
|
||||
* If file is provided, the face will be stored in file, other way it will be output to standard output.
|
||||
*
|
||||
* @param string|null $outFileName file name to store. If null, will be printed to output
|
||||
* @param boolean|false $resize resize crop image.
|
||||
* @param int $width widht of new crop image. $resize value must 'true'. default to 200
|
||||
* @param int $height height of new crop image. $resize value must 'true'. default to 200
|
||||
*
|
||||
* @throws NoFaceException
|
||||
*/
|
||||
public function cropFaceToJpeg($outFileName = null, $width = 200)
|
||||
{
|
||||
if (empty($this->face)) {
|
||||
throw new NoFaceException('No face detected');
|
||||
}
|
||||
// if (!$resize) {
|
||||
$x = ($a = $this->face['x'] - $this->face['w'] / 2) > 0 ? $a : 0;
|
||||
$y = ($b = $this->face['y'] - $this->face['w'] / 2) > 0 ? $b : 0;
|
||||
$im_width = imagesx($this->canvas);
|
||||
$im_height = imagesy($this->canvas);
|
||||
$w = ($w = $this->face['w'] * 2) > $im_width ? $im_width : $w;
|
||||
$h = ($h = $w) > $im_height ? $im_height : $h;
|
||||
|
||||
$canvas = imagecreatetruecolor($width, $width);
|
||||
imagecopy($canvas, $this->canvas, 0, 0, $x, $y, $w, $h);
|
||||
// $canvas = imagecreatetruecolor($this->face['w'], $this->face['w']);
|
||||
// imagecopy($canvas, $this->canvas, 0, 0, $this->face['x'], $this->face['y'], $this->face['w'], $this->face['w']);
|
||||
// } else {
|
||||
// $x = ($a = $this->face['x'] - $width / 2) > 0 ? $a : 0;
|
||||
// $y = ($b = $this->face['y'] - $width / 2) > 0 ? $b : 0;
|
||||
// $im_width = imagesx($this->canvas);
|
||||
// $im_height = imagesy($this->canvas);
|
||||
// $w = ($w = $width * 2) > $im_width ? $im_width : $w;
|
||||
// $h = ($h = $w) > $im_height ? $im_height : $h;
|
||||
|
||||
// $canvas = imagecreatetruecolor($w, $h);
|
||||
// imagecopy($canvas, $this->canvas, 0, 0, $width, $width, $w, $h);
|
||||
|
||||
// // $canvas = imagecreatetruecolor($width, $width);
|
||||
// // imagecopyresized($canvas, $this->canvas, 0, 0, $this->face['x'], $this->face['y'], $width, $width, $this->face['w'], $this->face['w']);
|
||||
// }
|
||||
|
||||
if ($outFileName === null) {
|
||||
header('Content-type: image/jpeg');
|
||||
}
|
||||
|
||||
imagejpeg($canvas, $outFileName);
|
||||
}
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
return json_encode($this->face);
|
||||
}
|
||||
|
||||
public function getFace()
|
||||
{
|
||||
return $this->face;
|
||||
}
|
||||
|
||||
protected function getImgStats($canvas)
|
||||
{
|
||||
$image_width = imagesx($canvas);
|
||||
$image_height = imagesy($canvas);
|
||||
$iis = $this->computeII($canvas, $image_width, $image_height);
|
||||
return array(
|
||||
'width' => $image_width,
|
||||
'height' => $image_height,
|
||||
'ii' => $iis['ii'],
|
||||
'ii2' => $iis['ii2']
|
||||
);
|
||||
}
|
||||
|
||||
protected function computeII($canvas, $image_width, $image_height)
|
||||
{
|
||||
$ii_w = $image_width + 1;
|
||||
$ii_h = $image_height + 1;
|
||||
$ii = array();
|
||||
$ii2 = array();
|
||||
|
||||
for ($i = 0; $i < $ii_w; $i++) {
|
||||
$ii[$i] = 0;
|
||||
$ii2[$i] = 0;
|
||||
}
|
||||
|
||||
for ($i = 1; $i < $ii_h - 1; $i++) {
|
||||
$ii[$i * $ii_w] = 0;
|
||||
$ii2[$i * $ii_w] = 0;
|
||||
$rowsum = 0;
|
||||
$rowsum2 = 0;
|
||||
for ($j = 1; $j < $ii_w - 1; $j++) {
|
||||
$rgb = ImageColorAt($canvas, $j, $i);
|
||||
$red = ($rgb >> 16) & 0xFF;
|
||||
$green = ($rgb >> 8) & 0xFF;
|
||||
$blue = $rgb & 0xFF;
|
||||
$grey = (0.2989 * $red + 0.587 * $green + 0.114 * $blue) >> 0; // this is what matlab uses
|
||||
$rowsum += $grey;
|
||||
$rowsum2 += $grey * $grey;
|
||||
|
||||
$ii_above = ($i - 1) * $ii_w + $j;
|
||||
$ii_this = $i * $ii_w + $j;
|
||||
|
||||
$ii[$ii_this] = $ii[$ii_above] + $rowsum;
|
||||
$ii2[$ii_this] = $ii2[$ii_above] + $rowsum2;
|
||||
}
|
||||
}
|
||||
return array('ii' => $ii, 'ii2' => $ii2);
|
||||
}
|
||||
|
||||
protected function doDetectGreedyBigToSmall($ii, $ii2, $width, $height)
|
||||
{
|
||||
$s_w = $width / 20.0;
|
||||
$s_h = $height / 20.0;
|
||||
$start_scale = $s_h < $s_w ? $s_h : $s_w;
|
||||
$scale_update = 1 / 1.2;
|
||||
for ($scale = $start_scale; $scale > 1; $scale *= $scale_update) {
|
||||
if ($this->timeout && microtime() - $this->time_start > $this->timeout) {
|
||||
throw new Exception("Face dectection has timed out");
|
||||
}
|
||||
$w = (20 * $scale) >> 0;
|
||||
$endx = $width - $w - 1;
|
||||
$endy = $height - $w - 1;
|
||||
$step = max($scale, 2) >> 0;
|
||||
$inv_area = 1 / ($w * $w);
|
||||
for ($y = 0; $y < $endy; $y += $step) {
|
||||
for ($x = 0; $x < $endx; $x += $step) {
|
||||
$passed = $this->detectOnSubImage($x, $y, $scale, $ii, $ii2, $w, $width + 1, $inv_area);
|
||||
if ($passed) {
|
||||
return array('x' => $x, 'y' => $y, 'w' => $w);
|
||||
}
|
||||
} // end x
|
||||
} // end y
|
||||
} // end scale
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function detectOnSubImage($x, $y, $scale, $ii, $ii2, $w, $iiw, $inv_area)
|
||||
{
|
||||
$mean = ($ii[($y + $w) * $iiw + $x + $w] + $ii[$y * $iiw + $x] - $ii[($y + $w) * $iiw + $x] - $ii[$y * $iiw + $x + $w]) * $inv_area;
|
||||
|
||||
$vnorm = ($ii2[($y + $w) * $iiw + $x + $w]
|
||||
+ $ii2[$y * $iiw + $x]
|
||||
- $ii2[($y + $w) * $iiw + $x]
|
||||
- $ii2[$y * $iiw + $x + $w]) * $inv_area - ($mean * $mean);
|
||||
|
||||
$vnorm = $vnorm > 1 ? sqrt($vnorm) : 1;
|
||||
|
||||
$count_data = count($this->detection_data);
|
||||
|
||||
for ($i_stage = 0; $i_stage < $count_data; $i_stage++) {
|
||||
$stage = $this->detection_data[$i_stage];
|
||||
$trees = $stage[0];
|
||||
|
||||
$stage_thresh = $stage[1];
|
||||
$stage_sum = 0;
|
||||
|
||||
$count_trees = count($trees);
|
||||
|
||||
for ($i_tree = 0; $i_tree < $count_trees; $i_tree++) {
|
||||
$tree = $trees[$i_tree];
|
||||
$current_node = $tree[0];
|
||||
$tree_sum = 0;
|
||||
while ($current_node != null) {
|
||||
$vals = $current_node[0];
|
||||
$node_thresh = $vals[0];
|
||||
$leftval = $vals[1];
|
||||
$rightval = $vals[2];
|
||||
$leftidx = $vals[3];
|
||||
$rightidx = $vals[4];
|
||||
$rects = $current_node[1];
|
||||
|
||||
$rect_sum = 0;
|
||||
$count_rects = count($rects);
|
||||
|
||||
for ($i_rect = 0; $i_rect < $count_rects; $i_rect++) {
|
||||
$s = $scale;
|
||||
$rect = $rects[$i_rect];
|
||||
$rx = ($rect[0] * $s + $x) >> 0;
|
||||
$ry = ($rect[1] * $s + $y) >> 0;
|
||||
$rw = ($rect[2] * $s) >> 0;
|
||||
$rh = ($rect[3] * $s) >> 0;
|
||||
$wt = $rect[4];
|
||||
|
||||
$r_sum = ($ii[($ry + $rh) * $iiw + $rx + $rw]
|
||||
+ $ii[$ry * $iiw + $rx]
|
||||
- $ii[($ry + $rh) * $iiw + $rx]
|
||||
- $ii[$ry * $iiw + $rx + $rw]) * $wt;
|
||||
|
||||
$rect_sum += $r_sum;
|
||||
}
|
||||
|
||||
$rect_sum *= $inv_area;
|
||||
|
||||
$current_node = null;
|
||||
|
||||
if ($rect_sum >= $node_thresh * $vnorm) {
|
||||
|
||||
if ($rightidx == -1) {
|
||||
|
||||
$tree_sum = $rightval;
|
||||
} else {
|
||||
|
||||
$current_node = $tree[$rightidx];
|
||||
}
|
||||
} else {
|
||||
|
||||
if ($leftidx == -1) {
|
||||
|
||||
$tree_sum = $leftval;
|
||||
} else {
|
||||
|
||||
$current_node = $tree[$leftidx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$stage_sum += $tree_sum;
|
||||
}
|
||||
if ($stage_sum < $stage_thresh) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
339
system/vendor/yosiazwan/php-facedetection/LICENSE.txt
vendored
Normal file
339
system/vendor/yosiazwan/php-facedetection/LICENSE.txt
vendored
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
14
system/vendor/yosiazwan/php-facedetection/README.md
vendored
Normal file
14
system/vendor/yosiazwan/php-facedetection/README.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
PHP Face Detection
|
||||
==================
|
||||
|
||||
This class can detect one face in images ATM.
|
||||
|
||||
This is a pure PHP port of an existing JS code from Karthik Tharavaad.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
PHP5 with GD
|
||||
|
||||
License
|
||||
-------
|
||||
GNU GPL v2 (See LICENSE.txt)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user