Compare commits
698
Commits
SupportBot
..
v8.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
753f432c95 | ||
|
|
c824bc51b2 | ||
|
|
39ee540b55 | ||
|
|
903b214051 | ||
|
|
ac0daf5fe7 | ||
|
|
80e38a07e9 | ||
|
|
d2598e09f7 | ||
|
|
28aab47150 | ||
|
|
81bda67ae4 | ||
|
|
25bbd1ff85 | ||
|
|
164d695a5f | ||
|
|
57e4a3e77c | ||
|
|
a6ac532b2b | ||
|
|
4f14722e14 | ||
|
|
9a6eece7a1 | ||
|
|
fd65d0a9a7 | ||
|
|
48500fe8a4 | ||
|
|
8d8d9e4bee | ||
|
|
dcbddf9f23 | ||
|
|
7449c0a61a | ||
|
|
c95b8ccb32 | ||
|
|
2c5bfe8e33 | ||
|
|
a3bbd97333 | ||
|
|
4ea488951d | ||
|
|
481424d5a6 | ||
|
|
fe82e96cc1 | ||
|
|
976258c959 | ||
|
|
83cf0689e2 | ||
|
|
c911cb4423 | ||
|
|
4eadef8b65 | ||
|
|
4e081358ff | ||
|
|
209ec0b435 | ||
|
|
6d363abb54 | ||
|
|
6f8b84aeda | ||
|
|
5b8c5da33a | ||
|
|
b6ef0f95cb | ||
|
|
cce1480a42 | ||
|
|
44fbe9f2d6 | ||
|
|
29db6c7d67 | ||
|
|
26e9b56961 | ||
|
|
979271cfb5 | ||
|
|
69f0b00ed3 | ||
|
|
c1a1839457 | ||
|
|
dd4b53800e | ||
|
|
1fc94528fc | ||
|
|
bb1a817980 | ||
|
|
53305acbc7 | ||
|
|
d0f1bae0bd | ||
|
|
c0cf3b1bb7 | ||
|
|
ce67b668d5 | ||
|
|
3273cfd0e1 | ||
|
|
fd992a6514 | ||
|
|
550d681fe1 | ||
|
|
7d29226953 | ||
|
|
38da72ca91 | ||
|
|
eab11361cb | ||
|
|
b281bba36f | ||
|
|
5e38573aed | ||
|
|
da7b6d487c | ||
|
|
6bf4e5f4bb | ||
|
|
213f532a3c | ||
|
|
45bd88e4d2 | ||
|
|
4eb8658459 | ||
|
|
b37118fee2 | ||
|
|
026caba68a | ||
|
|
2003f8801a | ||
|
|
473bacf13a | ||
|
|
8b3f2bc61a | ||
|
|
3aa373c33c | ||
|
|
9b6263e583 | ||
|
|
3e066d08ce | ||
|
|
aa48e28162 | ||
|
|
dc660ed94a | ||
|
|
e02ecf9553 | ||
|
|
23acc0926f | ||
|
|
3fc1cd18d5 | ||
|
|
ebe29b403e | ||
|
|
dcba3312dd | ||
|
|
7fddeeec37 | ||
|
|
b5341b023f | ||
|
|
bbb7443ef2 | ||
|
|
22df347bb9 | ||
|
|
9aed6b8f35 | ||
|
|
9e7ec9f1bd | ||
|
|
373f43eac5 | ||
|
|
6c91b2791a | ||
|
|
bde62a431f | ||
|
|
615a074540 | ||
|
|
09b335ac46 | ||
|
|
2701880c77 | ||
|
|
24c8f2fb38 | ||
|
|
c3ec158ac3 | ||
|
|
b3690222d0 | ||
|
|
4d7583785b | ||
|
|
17ad1a15db | ||
|
|
4c89de9e76 | ||
|
|
5f25af41f9 | ||
|
|
3a3ee357fc | ||
|
|
08a6d27903 | ||
|
|
33f7675aac | ||
|
|
1178a0a611 | ||
|
|
96ded77bec | ||
|
|
e83ca8cb2b | ||
|
|
e507176d39 | ||
|
|
4e554b8bee | ||
|
|
bc649caa99 | ||
|
|
f7a4c7b616 | ||
|
|
2c7be5882c | ||
|
|
6107d268f7 | ||
|
|
7760699155 | ||
|
|
acf349c72e | ||
|
|
8096e5b882 | ||
|
|
873cfc7dc2 | ||
|
|
038174bc7e | ||
|
|
14881096bb | ||
|
|
ed1905d8f4 | ||
|
|
72c0a2efa3 | ||
|
|
e599d48713 | ||
|
|
7f44634d4f | ||
|
|
44170caac6 | ||
|
|
adedfadd92 | ||
|
|
6b01d0c8fe | ||
|
|
d4d96f59ab | ||
|
|
a1bf7ed6bd | ||
|
|
306e20efc9 | ||
|
|
f593f6e0a8 | ||
|
|
74646a4318 | ||
|
|
8bfcba8832 | ||
|
|
4ba5621a4d | ||
|
|
1f928324c2 | ||
|
|
3771872cd2 | ||
|
|
f359a60343 | ||
|
|
f53afd7bc9 | ||
|
|
e7dcc2ab29 | ||
|
|
0118b9e591 | ||
|
|
ffe42f9777 | ||
|
|
5a467599e9 | ||
|
|
c56e78484a | ||
|
|
1ee0d4a09e | ||
|
|
ffdce5820b | ||
|
|
9fed504f37 | ||
|
|
6c5799be0d | ||
|
|
b6747a0340 | ||
|
|
cd6df02e30 | ||
|
|
edbef6a36f | ||
|
|
b6a0016f5f | ||
|
|
e740c17837 | ||
|
|
7eb949f109 | ||
|
|
02394e310d | ||
|
|
ef83832819 | ||
|
|
a82101ab30 | ||
|
|
007c78930e | ||
|
|
300c83512c | ||
|
|
b674872c56 | ||
|
|
12a7680275 | ||
|
|
c9cf7c942b | ||
|
|
8e0326c8f8 | ||
|
|
13972119a8 | ||
|
|
acf165a119 | ||
|
|
bdff7c6069 | ||
|
|
e2e3376c87 | ||
|
|
3c613088e5 | ||
|
|
7e9ece50a0 | ||
|
|
af81b6536a | ||
|
|
4cd3ecf81f | ||
|
|
31f6b9e08e | ||
|
|
02de920cb3 | ||
|
|
84c0905297 | ||
|
|
250583f859 | ||
|
|
ee7d42196d | ||
|
|
a397de2b9f | ||
|
|
0610df9400 | ||
|
|
ed583deb31 | ||
|
|
e039048fc6 | ||
|
|
f2ea9650c4 | ||
|
|
1e89057006 | ||
|
|
019bb4842f | ||
|
|
4cb45beded | ||
|
|
8a2059f087 | ||
|
|
a6b105a2e1 | ||
|
|
6c14a6a06c | ||
|
|
cddd5d0026 | ||
|
|
78dea91e1d | ||
|
|
3df591ec52 | ||
|
|
1c4032caa6 | ||
|
|
465c422171 | ||
|
|
284e8dc6f5 | ||
|
|
3fc905c82e | ||
|
|
55a42b88ae | ||
|
|
bd26162e4a | ||
|
|
62e7e33406 | ||
|
|
2f0ddcec3f | ||
|
|
7cdfa68e0e | ||
|
|
f8939a964d | ||
|
|
7830e5dda5 | ||
|
|
6aa2f22294 | ||
|
|
50b14e3d44 | ||
|
|
e09c2192c2 | ||
|
|
b725d2cc62 | ||
|
|
abf3f617a4 | ||
|
|
1eda7e66fe | ||
|
|
b5000531c4 | ||
|
|
d4f95e752b | ||
|
|
e31c611f70 | ||
|
|
085481bee6 | ||
|
|
cf610fbe49 | ||
|
|
b681eb3cd2 | ||
|
|
f8ffdf0e81 | ||
|
|
ba38bce1da | ||
|
|
3a39b05fe4 | ||
|
|
27d2982b28 | ||
|
|
33e4d97be5 | ||
|
|
654064d7c5 | ||
|
|
aeb0da9e0d | ||
|
|
cb1a2fe067 | ||
|
|
85667ddfad | ||
|
|
7ad5016966 | ||
|
|
45c3315fd0 | ||
|
|
c5f550dd00 | ||
|
|
37c870c7ab | ||
|
|
155b768f73 | ||
|
|
09f0873f27 | ||
|
|
19a12f6c8f | ||
|
|
79a498d1d6 | ||
|
|
12a03c36f3 | ||
|
|
ddc8bcab9b | ||
|
|
35dacfd48a | ||
|
|
611cef34ab | ||
|
|
8a8f9fe890 | ||
|
|
5a65b70c80 | ||
|
|
8bea3faa1f | ||
|
|
4125954d53 | ||
|
|
3d9c5a729e | ||
|
|
51d775ea6d | ||
|
|
e461c47c4b | ||
|
|
bbdb38e45a | ||
|
|
083e047aec | ||
|
|
84e0b504ab | ||
|
|
bedff6832c | ||
|
|
6c29e04de2 | ||
|
|
ba674323e1 | ||
|
|
6d756a161e | ||
|
|
66a5cd95ec | ||
|
|
9f70648264 | ||
|
|
b975b79691 | ||
|
|
3cab896954 | ||
|
|
b9680e5b35 | ||
|
|
43a003ca7d | ||
|
|
fbe1cf2009 | ||
|
|
fdee61cc11 | ||
|
|
8b51200d9c | ||
|
|
0631ab536a | ||
|
|
0d76e76519 | ||
|
|
9e9f83d211 | ||
|
|
0829d477d9 | ||
|
|
1b7109fa23 | ||
|
|
366669ccd8 | ||
|
|
e05edd89fa | ||
|
|
a405df66c9 | ||
|
|
28a57ead9f | ||
|
|
72bfacae75 | ||
|
|
10f8821b3b | ||
|
|
92a3745ce1 | ||
|
|
aff7ff1451 | ||
|
|
9e63e0ff09 | ||
|
|
2c5ebd8620 | ||
|
|
e6d63db3a9 | ||
|
|
2cc316aafb | ||
|
|
4f25cfa0dd | ||
|
|
0385de3882 | ||
|
|
2e1253c54e | ||
|
|
14df15caeb | ||
|
|
af481a2ec8 | ||
|
|
96c1d80844 | ||
|
|
57ea2e25bd | ||
|
|
cd17b0a6d7 | ||
|
|
c5dd8823f6 | ||
|
|
c27f16f753 | ||
|
|
4842610229 | ||
|
|
bd33669dba | ||
|
|
e81684d322 | ||
|
|
8209dfa26c | ||
|
|
0a82c62a4e | ||
|
|
4399dfe6b8 | ||
|
|
defd0cc78c | ||
|
|
fd5fc8294c | ||
|
|
10823b416c | ||
|
|
4490920ac6 | ||
|
|
e0b8ad4a32 | ||
|
|
e11063832b | ||
|
|
d598fdd753 | ||
|
|
157b93239a | ||
|
|
3d7058dccd | ||
|
|
1ec654d1ea | ||
|
|
8ce2d4269d | ||
|
|
49e8aa7869 | ||
|
|
0827f55d43 | ||
|
|
ba6ff8c342 | ||
|
|
c0b7dc2737 | ||
|
|
ab6abd453b | ||
|
|
77921aca75 | ||
|
|
a8f91c4814 | ||
|
|
7780fa792c | ||
|
|
41e4c376ec | ||
|
|
09aad61cfe | ||
|
|
31ac81428f | ||
|
|
60daab82d2 | ||
|
|
e7a0544004 | ||
|
|
ff0364bba8 | ||
|
|
a3b64be351 | ||
|
|
eae370e346 | ||
|
|
0d86b50a83 | ||
|
|
543b9028a3 | ||
|
|
867f12d11f | ||
|
|
462781ea6a | ||
|
|
c300ab6459 | ||
|
|
448d8f3007 | ||
|
|
faa53b0af1 | ||
|
|
8e53b8d9a6 | ||
|
|
5678567baa | ||
|
|
1c30f73bb1 | ||
|
|
bd3dbc3033 | ||
|
|
3c312ab8d3 | ||
|
|
7284785db0 | ||
|
|
4e543ea490 | ||
|
|
4d3540126f | ||
|
|
6c29f0d792 | ||
|
|
c85df7c40f | ||
|
|
4f6ff575ce | ||
|
|
aaf3890f71 | ||
|
|
4f9837d991 | ||
|
|
2e2eb008c6 | ||
|
|
fa7074bb59 | ||
|
|
18a7def050 | ||
|
|
40e9cf5fe5 | ||
|
|
6ce049a57e | ||
|
|
d4c4eac710 | ||
|
|
28ec96e5e8 | ||
|
|
a20fe8eb06 | ||
|
|
7d1d9b881d | ||
|
|
c116e6cbb0 | ||
|
|
a3ebf0a33b | ||
|
|
ea6ef022e7 | ||
|
|
683e29196a | ||
|
|
71694d7082 | ||
|
|
c5d5656fb6 | ||
|
|
b1fdbee5f8 | ||
|
|
70405a1cd0 | ||
|
|
3d7e81169f | ||
|
|
fa7c8c7219 | ||
|
|
358a25f522 | ||
|
|
690169a409 | ||
|
|
0ec4cc5a51 | ||
|
|
0b7dbaf368 | ||
|
|
940c445182 | ||
|
|
d8a90c9aa5 | ||
|
|
89ee8fceca | ||
|
|
68b55a2d33 | ||
|
|
8cc2e7747f | ||
|
|
4e6ac3a294 | ||
|
|
732e22ea7b | ||
|
|
ac0d9981f8 | ||
|
|
23f7310760 | ||
|
|
02a9ce6bac | ||
|
|
069665358f | ||
|
|
2cf6d69127 | ||
|
|
870435061d | ||
|
|
53ad906491 | ||
|
|
01399e343b | ||
|
|
a0bdec4c42 | ||
|
|
914f2057d8 | ||
|
|
ed9b9dca79 | ||
|
|
f6d4383ff6 | ||
|
|
b6ccf30ae4 | ||
|
|
48e44a0d38 | ||
|
|
735998b48c | ||
|
|
d94eefddb7 | ||
|
|
5a65b4df17 | ||
|
|
15a839a310 | ||
|
|
9730c61962 | ||
|
|
1805c041a6 | ||
|
|
f0bde93d5f | ||
|
|
1ed7412f92 | ||
|
|
1f5ea2d25b | ||
|
|
ff4c8f0e85 | ||
|
|
5c3dd878b8 | ||
|
|
20f0d91c75 | ||
|
|
894e48756f | ||
|
|
aef199b292 | ||
|
|
9b884cd941 | ||
|
|
b22d813cee | ||
|
|
0981566cbe | ||
|
|
0647aa435a | ||
|
|
58179f98e9 | ||
|
|
05fe62536b | ||
|
|
241d41e220 | ||
|
|
34d6134c24 | ||
|
|
702d1d1998 | ||
|
|
e43a5fd5a3 | ||
|
|
4ed9a7b7f5 | ||
|
|
d8ba76e395 | ||
|
|
448004abca | ||
|
|
7b0db34fb1 | ||
|
|
a7e7d5b372 | ||
|
|
9768628e8b | ||
|
|
6c0328b2fd | ||
|
|
6bf7d879e2 | ||
|
|
f25490f1ad | ||
|
|
31eee78535 | ||
|
|
4ed2aff1b7 | ||
|
|
6f05545be6 | ||
|
|
dfec8a0e4f | ||
|
|
47b730111b | ||
|
|
59ba27c36f | ||
|
|
b501164c38 | ||
|
|
1b795087bf | ||
|
|
7063edc10f | ||
|
|
c02abcb760 | ||
|
|
2d1a20dcc6 | ||
|
|
65156d4b20 | ||
|
|
951cedb190 | ||
|
|
11442f320d | ||
|
|
33df21f656 | ||
|
|
19ab208678 | ||
|
|
59b9651575 | ||
|
|
c1c1f1767a | ||
|
|
dda8a5180c | ||
|
|
34d558412f | ||
|
|
be77ee1903 | ||
|
|
fc571d6c73 | ||
|
|
7ca5a97535 | ||
|
|
730239ba8d | ||
|
|
9069e23188 | ||
|
|
366203fe21 | ||
|
|
f23f15c972 | ||
|
|
8432290a70 | ||
|
|
ceddd503f8 | ||
|
|
51ad35f72b | ||
|
|
5631b24a14 | ||
|
|
f9da25643d | ||
|
|
75bed3f5dd | ||
|
|
d4576dfc21 | ||
|
|
31bad3c2e5 | ||
|
|
a3c0e81e04 | ||
|
|
b5cf721efb | ||
|
|
95063398aa | ||
|
|
2da25c5566 | ||
|
|
a72c1ab380 | ||
|
|
87b9301e20 | ||
|
|
d0a6bed727 | ||
|
|
29881fbf28 | ||
|
|
4f05ad6546 | ||
|
|
36fc9aae6c | ||
|
|
fb3f87c685 | ||
|
|
a4c0eeb9b3 | ||
|
|
c64f249fd0 | ||
|
|
48b542293f | ||
|
|
95e92970c9 | ||
|
|
afdb16da07 | ||
|
|
0a230cfab9 | ||
|
|
c752a07ad0 | ||
|
|
cc5a6b7317 | ||
|
|
d93991ad86 | ||
|
|
5c98376a8c | ||
|
|
28699f0ff0 | ||
|
|
e3576b17b1 | ||
|
|
17c49b2b03 | ||
|
|
dcc00d8d1f | ||
|
|
05a772eee2 | ||
|
|
59dd291dc6 | ||
|
|
f0a791e354 | ||
|
|
94db6cff7b | ||
|
|
72a02bf6d2 | ||
|
|
cf99209887 | ||
|
|
ff7ed49905 | ||
|
|
ecd17a51df | ||
|
|
63b08f8c12 | ||
|
|
3077772aff | ||
|
|
f40aa9ed14 | ||
|
|
4ae6dc3a69 | ||
|
|
bdb8389d8d | ||
|
|
f7254c7ec7 | ||
|
|
3701156362 | ||
|
|
575d25f5ad | ||
|
|
698b82c7d3 | ||
|
|
eaa9da6d2e | ||
|
|
ca7294a0e3 | ||
|
|
5281ffce60 | ||
|
|
2f84fd3b33 | ||
|
|
bef270da74 | ||
|
|
bdf839ffca | ||
|
|
b1b2ead0d8 | ||
|
|
0b74473c64 | ||
|
|
2fb189cf5c | ||
|
|
24a29639e9 | ||
|
|
50258dc359 | ||
|
|
d9c6b7698f | ||
|
|
f042f34ae2 | ||
|
|
c087edc14f | ||
|
|
d96ccc3265 | ||
|
|
018ef19efd | ||
|
|
159317a15a | ||
|
|
34583c96bf | ||
|
|
887d3d3ab4 | ||
|
|
f2de39de33 | ||
|
|
8173c31a60 | ||
|
|
80a2871741 | ||
|
|
3b37e9c420 | ||
|
|
730ba561bc | ||
|
|
4d7ddc9d6f | ||
|
|
680f71a602 | ||
|
|
170a7b50b9 | ||
|
|
805c48c1bb | ||
|
|
7d92ed51bb | ||
|
|
f849897f29 | ||
|
|
75e0f1ad1e | ||
|
|
2f015aff2b | ||
|
|
bb322adb2f | ||
|
|
6ee0981885 | ||
|
|
877fb0f201 | ||
|
|
ded4b9094a | ||
|
|
36ab931998 | ||
|
|
20baddfcca | ||
|
|
d180c147db | ||
|
|
86fa91cc52 | ||
|
|
b8c12a0307 | ||
|
|
eff2f9c195 | ||
|
|
8a8597afef | ||
|
|
067e619488 | ||
|
|
f7f8bc8c55 | ||
|
|
0c71fd7e59 | ||
|
|
5b2bd21c06 | ||
|
|
9ac68f68e2 | ||
|
|
aa32f00b0d | ||
|
|
bd5f5dffad | ||
|
|
645ad63f4f | ||
|
|
c83c6afecc | ||
|
|
689a191d4c | ||
|
|
5767ba0de5 | ||
|
|
cdf78f2598 | ||
|
|
d23f46ad9e | ||
|
|
8453fa5007 | ||
|
|
0bd990a9e3 | ||
|
|
9c8ee1471b | ||
|
|
87262e82a3 | ||
|
|
953db88ed2 | ||
|
|
a44bb949eb | ||
|
|
9d11369059 | ||
|
|
8c92f39349 | ||
|
|
bce9d733d3 | ||
|
|
525c216401 | ||
|
|
c145e9f11d | ||
|
|
53700003f1 | ||
|
|
03094a4c35 | ||
|
|
934ebed24f | ||
|
|
9f469e1637 | ||
|
|
77fe39774d | ||
|
|
186d688ec8 | ||
|
|
de3181b5c7 | ||
|
|
6d53234f7a | ||
|
|
b0d3673f4b | ||
|
|
e40083f585 | ||
|
|
f7b702fa29 | ||
|
|
5089a19a56 | ||
|
|
d77e9842aa | ||
|
|
88ae76a25a | ||
|
|
9b0b0d10a1 | ||
|
|
68340a8b02 | ||
|
|
d14f0966d5 | ||
|
|
e4b83f28c4 | ||
|
|
1925deec90 | ||
|
|
e9ba960b29 | ||
|
|
821f0f5b60 | ||
|
|
8fa8915673 | ||
|
|
5405aa469e | ||
|
|
cfa50b4e8c | ||
|
|
c5014baeb4 | ||
|
|
c14f120ec2 | ||
|
|
b72fcf39da | ||
|
|
6da3b0cba0 | ||
|
|
752387a02d | ||
|
|
32d3e1b957 | ||
|
|
a029dff202 | ||
|
|
89e1b85a56 | ||
|
|
4350eb709c | ||
|
|
2b1b6e916e | ||
|
|
3f6f9045bd | ||
|
|
8294496faa | ||
|
|
9f58118ecd | ||
|
|
3ba9d42587 | ||
|
|
e496a5f3d0 | ||
|
|
04e2bb29b0 | ||
|
|
131a7a015c | ||
|
|
6f430f5f14 | ||
|
|
0154c106ef | ||
|
|
04de6e6fc0 | ||
|
|
2b17e5f842 | ||
|
|
0dc8c1e68a | ||
|
|
67b291eb09 | ||
|
|
d7865a5a4e | ||
|
|
d1809587a8 | ||
|
|
64ec4dfd53 | ||
|
|
6e07d21a3d | ||
|
|
018e47bd53 | ||
|
|
065a2e9347 | ||
|
|
b53307c7fd | ||
|
|
e4cc0d960e | ||
|
|
3336824df7 | ||
|
|
166173d53c | ||
|
|
45da2d7924 | ||
|
|
af14a65ef5 | ||
|
|
9049a4b9ad | ||
|
|
2f4873ab9a | ||
|
|
0fb25d71dc | ||
|
|
34b6901434 | ||
|
|
a90b43aba3 | ||
|
|
0ac5c2c300 | ||
|
|
6290fee7bd | ||
|
|
320992f3fa | ||
|
|
bd714f0c93 | ||
|
|
45d3867c1f | ||
|
|
deafa66565 | ||
|
|
ce8fcdaa7a | ||
|
|
b83965c144 | ||
|
|
2505a8cab8 | ||
|
|
21e598bb31 | ||
|
|
ee2f3c0dfc | ||
|
|
197bda14b8 | ||
|
|
d416c2e421 | ||
|
|
6bc2e669e4 | ||
|
|
9accb65256 | ||
|
|
d9212584ca | ||
|
|
1a7effb422 | ||
|
|
1480435f15 | ||
|
|
64c6a97657 | ||
|
|
7ae2ff9837 | ||
|
|
f19dec405d | ||
|
|
bbd4e9d162 | ||
|
|
58deff0869 | ||
|
|
628632f43e | ||
|
|
436586117c | ||
|
|
7234ec728c | ||
|
|
fc4d68be39 | ||
|
|
bcf2df4bff | ||
|
|
70a469a951 | ||
|
|
981995cb32 | ||
|
|
406c7d368b | ||
|
|
5c266d8b8d | ||
|
|
4f5b94a491 | ||
|
|
284c83cc1d | ||
|
|
23f06af202 | ||
|
|
82be317595 | ||
|
|
a43c76529f | ||
|
|
26065c2a5c | ||
|
|
6b1dfe01cf | ||
|
|
72443fb7c6 | ||
|
|
28cad23746 | ||
|
|
ebc0d4b137 | ||
|
|
4b198acda7 | ||
|
|
b84c3c75a5 | ||
|
|
de0ec97d9b | ||
|
|
a8302cd276 | ||
|
|
35d8d77f15 | ||
|
|
f853394d9d | ||
|
|
500c01dd1f | ||
|
|
71bfccfb0c | ||
|
|
71e1b64818 | ||
|
|
2118a00a36 | ||
|
|
1c69c21f21 | ||
|
|
31c76fc1c0 | ||
|
|
d31cdf8af2 | ||
|
|
29b5fd2c6f | ||
|
|
aa32525f8c | ||
|
|
f6a67a3373 | ||
|
|
4f78858641 | ||
|
|
c7e70bdaf8 | ||
|
|
5479e0957b | ||
|
|
8500554cfb | ||
|
|
368727cece | ||
|
|
742faf3805 | ||
|
|
7d08cbed84 | ||
|
|
f413bb5f3c | ||
|
|
2b3edc7b45 | ||
|
|
83f982f8d2 | ||
|
|
890a1d41b1 | ||
|
|
996a2c26ca | ||
|
|
fadf042101 | ||
|
|
a819078d7f | ||
|
|
2c9b4c663d | ||
|
|
22e6803e14 | ||
|
|
61cecb112f | ||
|
|
0c18aff34d | ||
|
|
599649a97f | ||
|
|
45194b82da | ||
|
|
570d0985d3 | ||
|
|
5eae625b28 | ||
|
|
fcc5460ff2 | ||
|
|
07d45e50de |
No files matched your search
@@ -1,2 +0,0 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a bug report to help us improve SupportBot.
|
|
||||||
title: "[BUG]"
|
|
||||||
labels: bug
|
|
||||||
assignees: EmeraldRusher
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of the bug you found and how you found it.
|
|
||||||
|
|
||||||
**How did you find it**
|
|
||||||
Please could explain what you did to find the bug?
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Feel free to notify with us with anything else about the problem here.
|
|
||||||
-76
@@ -1,76 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
|
||||||
typings/
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# next.js build output
|
|
||||||
.next
|
|
||||||
|
|
||||||
# nuxt.js build output
|
|
||||||
.nuxt
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
const Discord = require("discord.js");
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: "addon",
|
||||||
|
description: "This is a sample addon!",
|
||||||
|
options: [],
|
||||||
|
permissions: ["Administrator"],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const PingEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
`This is a sample addon.\n\nPong! \`${interaction.client.ws.ping} ms\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [PingEmbed],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
ChannelType,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.AddUser.Command,
|
||||||
|
description: cmdconfig.AddUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to add",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.AddUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const userToAdd = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketInviteEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Invite_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Invite_Description.replace("%username%", userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [ticketInviteEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dmEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.DM_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.DM_Description.replace("%channelname%", ticketChannel.name))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const acceptButton = new ButtonBuilder()
|
||||||
|
.setCustomId("accept_invite")
|
||||||
|
.setLabel(msgconfig.AddUser.Accept_Label)
|
||||||
|
.setEmoji("✅")
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const rejectButton = new ButtonBuilder()
|
||||||
|
.setCustomId("reject_invite")
|
||||||
|
.setLabel(msgconfig.AddUser.Reject_Label)
|
||||||
|
.setEmoji("❌")
|
||||||
|
.setStyle(ButtonStyle.Secondary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(acceptButton, rejectButton);
|
||||||
|
|
||||||
|
const dmMessage = await userToAdd.send({
|
||||||
|
embeds: [dmEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (i) => i.user.id === userToAdd.id;
|
||||||
|
const collector = dmMessage.createMessageComponentCollector({
|
||||||
|
filter,
|
||||||
|
time: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("collect", async (i) => {
|
||||||
|
if (i.customId === "accept_invite") {
|
||||||
|
try {
|
||||||
|
// Add user to thread or channel based on TicketType
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(userToAdd.id); // For threads
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(userToAdd.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
}); // For channels
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
const acceptedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Accepted_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Accepted_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [acceptedEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send the added user ticket message in the ticket channel
|
||||||
|
|
||||||
|
const addeduserTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Added_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Added_Description.replace('%username%', userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [addeduserTicket],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const addedToTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.AddedToTicket_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.AddedToTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const ticketLinkButton = new ButtonBuilder()
|
||||||
|
.setLabel(msgconfig.AddUser.ViewTicket_Label)
|
||||||
|
.setURL(`https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id}`)
|
||||||
|
.setStyle(ButtonStyle.Link);
|
||||||
|
|
||||||
|
await userToAdd.send({
|
||||||
|
embeds: [addedToTicketEmbed],
|
||||||
|
components: [new ActionRowBuilder().addComponents(ticketLinkButton)],
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Error_Adding)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const declinedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Declined_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Declined_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [declinedEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("end", (collected) => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
userToAdd.send({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.NoResponse_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.NoResponse_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warning),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 50007) {
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.DM_Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.DM_Error_Description.replace("%username%", userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Error sending DM:", error);
|
||||||
|
|
||||||
|
const unexpectedErrorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Unexpected_Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Unexpected_Error_Description.replace("%error%", error.message))
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [unexpectedErrorEmbed],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.CloseTicket.Command,
|
||||||
|
description: cmdconfig.CloseTicket.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "reason",
|
||||||
|
description: "Ticket Close Reason",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.CloseTicket.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
|
||||||
|
if (supportbot.Ticket.Close.StaffOnly) {
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
|
||||||
|
if (!SupportStaff || !Admin)
|
||||||
|
return interaction.reply("Some roles seem to be missing!\nPlease check for errors when starting the bot.");
|
||||||
|
|
||||||
|
const NoPerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id))
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a thread or channel based on config
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && interaction.channel.type !== Discord.ChannelType.PrivateThread) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && interaction.channel.type !== Discord.ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const NotTicketChannel = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Channel!")
|
||||||
|
.setDescription(`This command can only be used in a ${supportbot.Ticket.TicketType === "threads" ? "ticket thread" : "ticket channel"}.`)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [NotTicketChannel], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
let TicketData = tickets.tickets.findIndex((t) => t.id === interaction.channel.id);
|
||||||
|
let ticket = tickets.tickets[TicketData];
|
||||||
|
|
||||||
|
if (TicketData === -1) {
|
||||||
|
const Exists = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("No Ticket Found!")
|
||||||
|
.setDescription(msgconfig.Error.NoValidTicket)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
return interaction.followUp({ embeds: [Exists] });
|
||||||
|
}
|
||||||
|
|
||||||
|
let reason = interaction.options?.getString("reason") || "No Reason Provided.";
|
||||||
|
|
||||||
|
const CloseButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("confirmCloseTicket")
|
||||||
|
.setLabel(supportbot.Ticket.Close.Confirmation_Button)
|
||||||
|
.setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
|
||||||
|
.setStyle(supportbot.Ticket.Close.Confirmation_Style);
|
||||||
|
|
||||||
|
const row = new Discord.ActionRowBuilder().addComponents(CloseButton);
|
||||||
|
|
||||||
|
const CloseTicketRequest = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(`**${supportbot.Ticket.Close.Title}**`)
|
||||||
|
.setDescription(`${msgconfig.Ticket.ConfirmClose}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await interaction.followUp({
|
||||||
|
embeds: [CloseTicketRequest],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (btnInteraction) => btnInteraction.customId === "confirmCloseTicket" && btnInteraction.user.id === interaction.user.id;
|
||||||
|
|
||||||
|
interaction.channel.awaitMessageComponent({ filter, time: 20000 })
|
||||||
|
.then(async (btnInteraction) => {
|
||||||
|
await handleCloseTicket(interaction, reason, ticket, TicketData);
|
||||||
|
await btnInteraction.reply({ content: "Ticket successfully closed.", ephemeral: true });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
interaction.followUp(`${msgconfig.Ticket.CloseTimeout}`);
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleCloseTicket(interaction, reason, ticket, TicketData) {
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
let tUser = interaction.client.users.cache.get(ticket.user);
|
||||||
|
let transcriptChannel = await getChannel(supportbot.Ticket.Log.TicketDataLog, interaction.guild);
|
||||||
|
|
||||||
|
if (!transcriptChannel)
|
||||||
|
return interaction.followUp("Some Channels seem to be missing!");
|
||||||
|
|
||||||
|
try {
|
||||||
|
tickets.tickets[TicketData].open = false;
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/TicketData.json",
|
||||||
|
JSON.stringify(tickets, null, 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const transcriptEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketLog.Title)
|
||||||
|
.setColor(msgconfig.TicketLog.Colour)
|
||||||
|
.setFooter({
|
||||||
|
text: supportbot.Embed.Footer,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
})
|
||||||
|
.addFields(
|
||||||
|
{ name: "Ticket", value: `${interaction.channel.name} (${interaction.channel.id})` },
|
||||||
|
{ name: "User", value: `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${tUser?.id || ticket.user})` },
|
||||||
|
{ name: "Closed By", value: interaction.user.tag },
|
||||||
|
{ name: "Reason", value: reason }
|
||||||
|
);
|
||||||
|
|
||||||
|
let msgs = await interaction.channel.messages.fetch({ limit: 100 });
|
||||||
|
let html = `
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
color: white;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(0, 128, 0, 0.3);
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 1000px;
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.username {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.timestamp {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
.download-button {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Ticket Transcript</h1>
|
||||||
|
<p><strong>Server Name:</strong> ${interaction.guild.name}</p>
|
||||||
|
<p><strong>Ticket:</strong> ${interaction.channel.name}</p>
|
||||||
|
<p><strong>Messages:</strong> ${msgs.size} Messages</p>
|
||||||
|
<div class="mt-4">
|
||||||
|
`;
|
||||||
|
|
||||||
|
msgs = msgs.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
|
||||||
|
msgs.forEach((msg) => {
|
||||||
|
if (msg.content) {
|
||||||
|
html += `
|
||||||
|
<div class="message">
|
||||||
|
<img class="avatar" src="${msg.author.displayAvatarURL()}" alt="Avatar">
|
||||||
|
<div class="content">
|
||||||
|
<p class="username">${msg.author.tag}</p>
|
||||||
|
<p class="timestamp">${msg.createdAt.toLocaleString()}</p>
|
||||||
|
<p>${convertMarkdownToHTML(msg.content)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileName = `${interaction.channel.name}.html`;
|
||||||
|
|
||||||
|
html += `
|
||||||
|
</div>
|
||||||
|
<a href="${fileName}" download class="download-button">Download Transcript</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
let file = new Discord.AttachmentBuilder(
|
||||||
|
Buffer.from(html),
|
||||||
|
{ name: fileName }
|
||||||
|
);
|
||||||
|
|
||||||
|
await transcriptChannel
|
||||||
|
.send({ embeds: [transcriptEmbed], files: [file] })
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supportbot.Ticket.DMTranscripts) {
|
||||||
|
await tUser
|
||||||
|
?.send({ embeds: [transcriptEmbed], files: [file] })
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ticket.subUsers) {
|
||||||
|
ticket.subUsers.forEach(async (subUser) => {
|
||||||
|
await interaction.client.users.cache
|
||||||
|
.get(subUser)
|
||||||
|
?.send({ embeds: [transcriptEmbed], files: [file] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.delete().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
if (error.code !== Discord.Constants.APIErrors.UNKNOWN_CHANNEL) {
|
||||||
|
console.error("Failed to delete the interaction:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertMarkdownToHTML(text) {
|
||||||
|
// Convert **bold** to <strong>bold</strong>
|
||||||
|
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||||||
|
|
||||||
|
// Convert *italic* to <em>italic</em>
|
||||||
|
text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
|
||||||
|
|
||||||
|
// Convert __underline__ to <u>underline</u>
|
||||||
|
text = text.replace(/__(.*?)__/g, '<u>$1</u>');
|
||||||
|
|
||||||
|
// Convert ~~strikethrough~~ to <s>strikethrough</s>
|
||||||
|
text = text.replace(/~~(.*?)~~/g, '<s>$1</s>');
|
||||||
|
|
||||||
|
// Convert inline code `code` to <code>code</code>
|
||||||
|
text = text.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||||
|
|
||||||
|
// Convert blockquotes > quote to <blockquote>quote</blockquote>
|
||||||
|
text = text.replace(/^> (.*?$)/gm, '<blockquote>$1</blockquote>');
|
||||||
|
|
||||||
|
// Convert multiline code blocks ```code``` to <pre><code>code</code></pre>
|
||||||
|
text = text.replace(/```(.*?)```/gs, '<pre><code>$1</code></pre>');
|
||||||
|
|
||||||
|
// Convert line breaks to <br>
|
||||||
|
text = text.replace(/\n/g, '<br>');
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
// File path: ./commands/embed.js
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Embed.Command,
|
||||||
|
description: cmdconfig.Embed.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
description: "Embed Title",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "message",
|
||||||
|
description: "Embed Message",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "color",
|
||||||
|
description: "Embed HEX Color",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fields",
|
||||||
|
description: "Embed Fields (title|content;title|content;...)",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "thumbnail",
|
||||||
|
description: "Embed Thumbnail URL",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "image",
|
||||||
|
description: "Embed Image URL",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "footer",
|
||||||
|
description: "Embed Footer Text",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "footericon",
|
||||||
|
description: "Embed Footer Icon URL",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "author",
|
||||||
|
description: "Embed Author Name",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "authoricon",
|
||||||
|
description: "Embed Author Icon URL",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "authorurl",
|
||||||
|
description: "Embed Author URL",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "timestamp",
|
||||||
|
description: "Include Timestamp",
|
||||||
|
type: Discord.ApplicationCommandOptionType.Boolean,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "inline",
|
||||||
|
description: "Make Fields Inline",
|
||||||
|
type: Discord.ApplicationCommandOptionType.Boolean,
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Embed.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply("Some roles seem to be missing!\nPlease check for errors when starting the bot.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
interaction.member.roles.cache.has(SupportStaff.id) ||
|
||||||
|
interaction.member.roles.cache.has(Admin.id)
|
||||||
|
) {
|
||||||
|
const EmbedTitle = interaction.options.getString("title").replace(/\\n/g, '\n');
|
||||||
|
const EmbedSubject = interaction.options.getString("message").replace(/\\n/g, '\n');
|
||||||
|
const GeneralColour = interaction.options.getString("color") || supportbot.Embed.Colours.Default;
|
||||||
|
const EmbedThumbnail = interaction.options.getString("thumbnail");
|
||||||
|
const EmbedImage = interaction.options.getString("image");
|
||||||
|
const EmbedFields = interaction.options.getString("fields");
|
||||||
|
const EmbedFooter = interaction.options.getString("footer")?.replace(/\\n/g, '\n');
|
||||||
|
const EmbedFooterIcon = interaction.options.getString("footericon");
|
||||||
|
const EmbedAuthor = interaction.options.getString("author")?.replace(/\\n/g, '\n');
|
||||||
|
const EmbedAuthorIcon = interaction.options.getString("authoricon");
|
||||||
|
const EmbedAuthorURL = interaction.options.getString("authorurl");
|
||||||
|
const EmbedTimestamp = interaction.options.getBoolean("timestamp");
|
||||||
|
const InlineFields = interaction.options.getBoolean("inline");
|
||||||
|
|
||||||
|
const EmbedMsg = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(EmbedTitle)
|
||||||
|
.setDescription(EmbedSubject)
|
||||||
|
.setColor(GeneralColour)
|
||||||
|
.setThumbnail(EmbedThumbnail)
|
||||||
|
.setImage(EmbedImage);
|
||||||
|
|
||||||
|
if (EmbedFields) {
|
||||||
|
const fieldsArray = EmbedFields.split(';');
|
||||||
|
fieldsArray.forEach(field => {
|
||||||
|
const [title, value] = field.split('|');
|
||||||
|
if (title && value) {
|
||||||
|
EmbedMsg.addFields({ name: title.replace(/\\n/g, '\n'), value: value.replace(/\\n/g, '\n'), inline: InlineFields || false });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EmbedFooter) {
|
||||||
|
EmbedMsg.setFooter({ text: EmbedFooter, iconURL: EmbedFooterIcon });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EmbedAuthor) {
|
||||||
|
EmbedMsg.setAuthor({ name: EmbedAuthor, iconURL: EmbedAuthorIcon, url: EmbedAuthorURL });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EmbedTimestamp) {
|
||||||
|
EmbedMsg.setTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [EmbedMsg],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.ForceAddUser.Command,
|
||||||
|
description: cmdconfig.ForceAddUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to forcefully add",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.ForceAddUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const userToAdd = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.ForceAddUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
try {
|
||||||
|
// Explicitly ensure the bot is in the thread
|
||||||
|
const botMember = await ticketChannel.members.fetch(interaction.client.user.id).catch(() => null);
|
||||||
|
if (!botMember) {
|
||||||
|
await ticketChannel.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay to ensure API has processed the bot's membership
|
||||||
|
await new Promise(res => setTimeout(res, 1000));
|
||||||
|
|
||||||
|
// Attempt to add the user to the thread
|
||||||
|
await ticketChannel.members.add(userToAdd.id);
|
||||||
|
|
||||||
|
console.log("User successfully added to the thread.");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the thread:", err.message);
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Error_Title)
|
||||||
|
.setDescription(`An error occurred: ${err.message}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(userToAdd.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
const addedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Added_Title)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.ForceAddUser.Added_Description.replace("%username%", userToAdd.username)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [addedEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addedToTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.AddedToTicket_Title)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.ForceAddUser.AddedToTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await userToAdd.send({
|
||||||
|
embeds: [addedToTicketEmbed],
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.ForceAddUser.Error_Adding)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Help.Command,
|
||||||
|
description: cmdconfig.Help.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Help.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate regular commands and addon commands
|
||||||
|
let botCommands = "";
|
||||||
|
let addonCommands = "";
|
||||||
|
|
||||||
|
interaction.client.commands.forEach((command) => {
|
||||||
|
if (command.permissions) {
|
||||||
|
if (command.addon) {
|
||||||
|
addonCommands += `\`${command.name}\` `;
|
||||||
|
} else {
|
||||||
|
botCommands += `\`${command.name}\` `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create embed
|
||||||
|
const HelpEmbed1 = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(supportbot.General.Name + " Commands")
|
||||||
|
.setThumbnail(interaction.user.displayAvatarURL())
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.addFields({
|
||||||
|
name: "🖥️ Commands\n",
|
||||||
|
value: botCommands || "No commands available.",
|
||||||
|
inline: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
HelpEmbed1.setFooter({
|
||||||
|
text: supportbot.Embed.Footer,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
});
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
embeds: [HelpEmbed1],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Info Command
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const cmdconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Info.Command,
|
||||||
|
description: cmdconfig.Info.Description,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Info.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const InfoButton = new Discord.ButtonBuilder()
|
||||||
|
.setLabel(msgconfig.Info.Button)
|
||||||
|
.setURL(msgconfig.Info.URL)
|
||||||
|
.setStyle("Link");
|
||||||
|
|
||||||
|
const inforow = new Discord.ActionRowBuilder().addComponents(InfoButton);
|
||||||
|
|
||||||
|
const InfoEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setURL(msgconfig.Info.URL)
|
||||||
|
.setTitle(msgconfig.Info.Title)
|
||||||
|
.setDescription(msgconfig.Info.Description)
|
||||||
|
.setColor(msgconfig.Info.Colour)
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [InfoEmbed],
|
||||||
|
components: [inforow],
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ping Command
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Ping.Command,
|
||||||
|
description: cmdconfig.Ping.Description,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Ping.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const PingEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
`:ping_pong: **Ping:** \`${interaction.client.ws.ping} ms\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [PingEmbed],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
const { EmbedBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ApplicationCommandType, ActionRowBuilder, ButtonBuilder, ButtonStyle, ApplicationCommandOptionType } = require("discord.js");
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
const clockedInUsers = new Set();
|
||||||
|
|
||||||
|
// async function getRole(roleName, guild) {
|
||||||
|
// return guild.roles.cache.find(role => role.name === roleName);
|
||||||
|
// }
|
||||||
|
|
||||||
|
function updateClockedInStatus(profileEmbed, clockedIn) {
|
||||||
|
profileEmbed.data.fields = profileEmbed.data.fields.map(field => {
|
||||||
|
if (field.name === 'Clocked In Status') {
|
||||||
|
field.value = clockedIn ? '✅ Clocked In' : '❌ Clocked Out';
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
});
|
||||||
|
return profileEmbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Profile.Command,
|
||||||
|
description: cmdconfig.Profile.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
permissions: cmdconfig.Profile.Permission,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
description: 'The user to view the profile of',
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
await interaction.deferReply({ ephemeral: true }); // Acknowledge the interaction immediately
|
||||||
|
|
||||||
|
const userOption = interaction.options.getUser('user');
|
||||||
|
const viewingUser = userOption || interaction.user;
|
||||||
|
const viewingUserId = viewingUser.id;
|
||||||
|
const interactionUserId = interaction.user.id;
|
||||||
|
|
||||||
|
const user = interaction.guild.members.cache.get(viewingUserId);
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
|
||||||
|
const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
|
||||||
|
if (!Staff || !Admin) {
|
||||||
|
return interaction.editReply({
|
||||||
|
content: "Some roles seem to be missing!\nPlease check for errors when starting the bot.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStaff = user.roles.cache.has(Staff.id) || user.roles.cache.has(Admin.id);
|
||||||
|
const isOwnProfile = interactionUserId === viewingUserId;
|
||||||
|
|
||||||
|
const profilePath = `./Data/Profiles/${viewingUserId}.json`;
|
||||||
|
let profileData;
|
||||||
|
|
||||||
|
if (fs.existsSync(profilePath)) {
|
||||||
|
profileData = JSON.parse(fs.readFileSync(profilePath, "utf8"));
|
||||||
|
} else {
|
||||||
|
profileData = {
|
||||||
|
bio: "",
|
||||||
|
timezone: "",
|
||||||
|
clockedIn: false
|
||||||
|
};
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { bio, timezone, clockedIn } = profileData;
|
||||||
|
|
||||||
|
let profileEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(`${viewingUser.username}'s Profile`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.setThumbnail(viewingUser.displayAvatarURL())
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Bio', value: bio || 'No bio set.', inline: false },
|
||||||
|
{ name: 'Timezone', value: timezone || 'No timezone set.', inline: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
profileEmbed.addFields({ name: 'Clocked In Status', value: clockedIn ? '✅ Clocked In' : '❌ Clocked Out', inline: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonRow = new ActionRowBuilder();
|
||||||
|
if (isOwnProfile) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('editProfile')
|
||||||
|
.setLabel('Edit Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('clockInOut')
|
||||||
|
.setLabel(clockedIn ? 'Clock Out' : 'Clock In')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStaff && supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('viewTicketStats')
|
||||||
|
.setLabel('View Ticket Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.editReply({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
|
||||||
|
|
||||||
|
const filter = i => (
|
||||||
|
['editProfile', 'clockInOut', 'viewTicketStats', 'showOpenTickets', 'backToStats', 'backToProfile'].includes(i.customId)
|
||||||
|
&& i.user.id === interactionUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const collector = interaction.channel.createMessageComponentCollector({ filter, time: 60000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
if (i.customId === 'editProfile') {
|
||||||
|
const modal = new ModalBuilder()
|
||||||
|
.setCustomId('editProfileModal')
|
||||||
|
.setTitle('Edit Profile')
|
||||||
|
.addComponents(
|
||||||
|
new ActionRowBuilder().addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('bio')
|
||||||
|
.setLabel('Bio')
|
||||||
|
.setStyle(TextInputStyle.Paragraph)
|
||||||
|
.setPlaceholder('Enter your bio')
|
||||||
|
.setValue(String(bio))
|
||||||
|
.setRequired(false)
|
||||||
|
),
|
||||||
|
new ActionRowBuilder().addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('timezone')
|
||||||
|
.setLabel('Timezone')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setPlaceholder('Enter your timezone')
|
||||||
|
.setValue(String(timezone))
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'clockInOut') {
|
||||||
|
profileData.clockedIn = !profileData.clockedIn;
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
profileEmbed = updateClockedInStatus(profileEmbed, profileData.clockedIn);
|
||||||
|
|
||||||
|
if (profileData.clockedIn) {
|
||||||
|
clockedInUsers.add(viewingUserId);
|
||||||
|
} else {
|
||||||
|
clockedInUsers.delete(viewingUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('editProfile')
|
||||||
|
.setLabel('Edit Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
updatedButtonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('clockInOut')
|
||||||
|
.setLabel(profileData.clockedIn ? 'Clock Out' : 'Clock In')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
updatedButtonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('viewTicketStats')
|
||||||
|
.setLabel('View Ticket Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await i.update({ embeds: [profileEmbed], components: [updatedButtonRow] });
|
||||||
|
|
||||||
|
let clockedinout = new EmbedBuilder()
|
||||||
|
.setTitle(profileData.clockedIn ? 'Clocked In!' : 'Clocked Out!')
|
||||||
|
.setDescription(profileData.clockedIn ? 'You have successfully clocked in.' : 'You have successfully clocked out.')
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
|
||||||
|
await interaction.followUp({ embeds: [clockedinout], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'viewTicketStats') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
|
||||||
|
const ticketsOpen = ticketsClaimed.filter(t => t.open);
|
||||||
|
const totalTickets = ticketsClaimed.length;
|
||||||
|
|
||||||
|
let totalResponseTime = 0;
|
||||||
|
let responseCount = 0;
|
||||||
|
|
||||||
|
ticketsClaimed.forEach(ticket => {
|
||||||
|
if (ticket.claimedAt && ticket.createdAt) {
|
||||||
|
const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt);
|
||||||
|
totalResponseTime += responseTime;
|
||||||
|
responseCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0;
|
||||||
|
const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000);
|
||||||
|
|
||||||
|
const statsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketStats.Title)
|
||||||
|
.setDescription(`> Ticket stats for <@${viewingUserId}>`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.addFields(
|
||||||
|
{ name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true },
|
||||||
|
{ name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true },
|
||||||
|
{ name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const statsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('showOpenTickets')
|
||||||
|
.setLabel('Show Open Tickets')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToProfile')
|
||||||
|
.setLabel('Back to Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'showOpenTickets') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsOpen = TicketData.tickets.filter(t => t.claimedBy === viewingUserId && t.open);
|
||||||
|
|
||||||
|
const openTicketsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle('Active Tickets')
|
||||||
|
.setDescription(ticketsOpen.map(t => `<#${t.id}>`).join('\n') || 'No active tickets.')
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const openTicketsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToStats')
|
||||||
|
.setLabel('Back to Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [openTicketsEmbed], components: [openTicketsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'backToStats') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
|
||||||
|
const ticketsOpen = ticketsClaimed.filter(t => t.open);
|
||||||
|
const totalTickets = ticketsClaimed.length;
|
||||||
|
|
||||||
|
let totalResponseTime = 0;
|
||||||
|
let responseCount = 0;
|
||||||
|
|
||||||
|
ticketsClaimed.forEach(ticket => {
|
||||||
|
if (ticket.claimedAt && ticket.createdAt) {
|
||||||
|
const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt);
|
||||||
|
totalResponseTime += responseTime;
|
||||||
|
responseCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0;
|
||||||
|
const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000);
|
||||||
|
|
||||||
|
const statsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketStats.Title)
|
||||||
|
.setDescription(`> Ticket stats for <@${viewingUserId}>`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.addFields(
|
||||||
|
{ name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true },
|
||||||
|
{ name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true },
|
||||||
|
{ name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const statsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('showOpenTickets')
|
||||||
|
.setLabel('Show Open Tickets')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToProfile')
|
||||||
|
.setLabel('Back to Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'backToProfile') {
|
||||||
|
await i.update({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.clockedInUsers = clockedInUsers;
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.RemoveUser.Command,
|
||||||
|
description: cmdconfig.RemoveUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to remove",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.RemoveUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPerms = new EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)
|
||||||
|
) {
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const userToRemove = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
// Check if the channel is a ticket thread or text channel based on TicketType
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Remove user from thread or channel based on TicketType
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.remove(userToRemove.id); // For threads
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.delete(userToRemove.id); // For channels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the ticket data
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
const subUsers = ticketData.tickets[ticketIndex].subUsers;
|
||||||
|
const userIndex = subUsers.indexOf(userToRemove.id);
|
||||||
|
if (userIndex !== -1) {
|
||||||
|
subUsers.splice(userIndex, 1);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.Removed_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.Removed_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [removedEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedFromTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.RemovedFromTicket_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.RemovedFromTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await userToRemove.send({
|
||||||
|
embeds: [removedFromTicketEmbed],
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error removing user from the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.Error_Removing)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
const { Command } = require('../Structures/Addon.js');
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const settingsFilePath = path.resolve(__dirname, '../Data/settings.json');
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(settingsFilePath)) {
|
||||||
|
const data = fs.readFileSync(settingsFilePath, 'utf8');
|
||||||
|
return JSON.parse(data);
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error reading settings file:", error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSettings(settings) {
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(settingsFilePath, JSON.stringify(settings, null, 2), 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error writing settings file:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Settings.Command,
|
||||||
|
description: cmdconfig.Settings.Description,
|
||||||
|
permissions: cmdconfig.Settings.Permission,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'setstatus',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot status',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'status',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Choose the bot status',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'Online 🟢', value: 'online' },
|
||||||
|
{ name: 'Idle 🌙', value: 'idle' },
|
||||||
|
{ name: 'Do Not Disturb ⛔', value: 'dnd' },
|
||||||
|
{ name: 'Invisible 👻', value: 'invisible' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'setactivity',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot activity',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Choose the activity type',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'Playing 🎮', value: 'PLAYING' },
|
||||||
|
{ name: 'Watching 👀', value: 'WATCHING' },
|
||||||
|
{ name: 'Listening 🎧', value: 'LISTENING' },
|
||||||
|
{ name: 'Competing 🏆', value: 'COMPETING' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'The activity message',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'streammode',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot streaming status',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'toggle',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Turn streaming mode on or off',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'On', value: 'on' },
|
||||||
|
{ name: 'Off', value: 'off' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitchurl',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Twitch stream URL (Required if turning on)',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'setnickname',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot nickname',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'nickname',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'The new nickname for the bot',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const subcommand = interaction.options.getSubcommand();
|
||||||
|
const settings = loadSettings();
|
||||||
|
|
||||||
|
if (subcommand === 'setstatus') {
|
||||||
|
const status = interaction.options.getString('status');
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
status: status,
|
||||||
|
activities: interaction.client.user.presence.activities || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.status = status;
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Status set to **${status.charAt(0).toUpperCase() + status.slice(1)}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set status: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subcommand === 'setactivity') {
|
||||||
|
const activityType = interaction.options.getString('type');
|
||||||
|
const activityMessage = interaction.options.getString('message');
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: [{ name: activityMessage, type: Discord.ActivityType[activityType] }],
|
||||||
|
status: interaction.client.user.presence.status || 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.activity = { type: activityType, message: activityMessage };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Activity set to **${activityType.toLowerCase()} ${activityMessage}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set activity: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else if (subcommand === 'streammode') {
|
||||||
|
const toggle = interaction.options.getString('toggle');
|
||||||
|
const twitchUrl = interaction.options.getString('twitchurl');
|
||||||
|
|
||||||
|
if (toggle === 'on') {
|
||||||
|
if (!twitchUrl) {
|
||||||
|
return interaction.reply({ content: 'Please provide a Twitch URL to stream.', ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: [{ name: 'Streaming', type: Discord.ActivityType.Streaming, url: twitchUrl }],
|
||||||
|
status: 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.streaming = { active: true, url: twitchUrl };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`**Streaming mode enabled!**\nStreaming: [Twitch](${twitchUrl})`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to enable streaming mode: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else if (toggle === 'off') {
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: interaction.client.user.presence.activities.filter(a => a.type !== Discord.ActivityType.Streaming),
|
||||||
|
status: settings.status || 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.streaming = { active: false };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`**Streaming mode disabled!**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to disable streaming mode: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (subcommand === 'setnickname') {
|
||||||
|
const nickname = interaction.options.getString('nickname');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const guild = interaction.guild;
|
||||||
|
const botMember = guild.members.cache.get(interaction.client.user.id);
|
||||||
|
await botMember.setNickname(nickname);
|
||||||
|
|
||||||
|
settings.nickname = nickname;
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Bot nickname set to **${nickname}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set nickname: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return interaction.reply({ content: 'Invalid command usage.', ephemeral: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
// Load configurations
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
// Ensure suggestions file exists and is correctly loaded
|
||||||
|
let suggestions;
|
||||||
|
try {
|
||||||
|
suggestions = require("../Data/SuggestionData.json");
|
||||||
|
} catch (error) {
|
||||||
|
suggestions = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Suggestion.Command,
|
||||||
|
description: cmdconfig.Suggestion.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "suggestion",
|
||||||
|
description: "Create a Suggestion",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Suggestion.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
const suggestChannel = await getChannel(
|
||||||
|
supportbot.Suggestions.Channel,
|
||||||
|
interaction.guild
|
||||||
|
);
|
||||||
|
|
||||||
|
const NoChannel = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Missing Channel!")
|
||||||
|
.setDescription(msgconfig.Error.InvalidChannel)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!suggestChannel) return interaction.reply({ embeds: [NoChannel] });
|
||||||
|
|
||||||
|
let suggestion = interaction.options.getString("suggestion");
|
||||||
|
|
||||||
|
const SuggestEmbed = new Discord.EmbedBuilder()
|
||||||
|
.addFields(
|
||||||
|
{ name: "Suggestion", value: suggestion, inline: true },
|
||||||
|
{ name: "From", value: `<@${interaction.user.id}>` },
|
||||||
|
{ name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`, value: "0", inline: true },
|
||||||
|
{ name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`, value: "0", inline: true }
|
||||||
|
)
|
||||||
|
.setThumbnail(interaction.user.displayAvatarURL())
|
||||||
|
.setFooter({
|
||||||
|
text: supportbot.Embed.Footer,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
})
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const UpvoteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("upvote")
|
||||||
|
.setEmoji(supportbot.Suggestions.UpvoteEmoji)
|
||||||
|
.setStyle(supportbot.Suggestions.Buttons.Upvote);
|
||||||
|
|
||||||
|
const DownvoteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("downvote")
|
||||||
|
.setEmoji(supportbot.Suggestions.DownvoteEmoji)
|
||||||
|
.setStyle(supportbot.Suggestions.Buttons.Downvote);
|
||||||
|
|
||||||
|
const RemoveVoteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("removevote")
|
||||||
|
.setLabel(supportbot.Suggestions.Buttons.RemoveVote_Title)
|
||||||
|
.setStyle(supportbot.Suggestions.Buttons.RemoveVote); // Red button
|
||||||
|
|
||||||
|
const row = new Discord.ActionRowBuilder().addComponents(UpvoteButton, DownvoteButton, RemoveVoteButton);
|
||||||
|
|
||||||
|
const suggestionMsg = await suggestChannel.send({ embeds: [SuggestEmbed], components: [row] });
|
||||||
|
|
||||||
|
suggestions[suggestionMsg.id] = {
|
||||||
|
suggestion: suggestion,
|
||||||
|
author: interaction.user.id,
|
||||||
|
upvotes: [],
|
||||||
|
downvotes: []
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2));
|
||||||
|
|
||||||
|
if (supportbot.Suggestions.Threads.Enabled) {
|
||||||
|
await suggestionMsg.startThread({
|
||||||
|
name: supportbot.Suggestions.Threads.Title,
|
||||||
|
autoArchiveDuration: 60,
|
||||||
|
type: Discord.ChannelType.PublicThread,
|
||||||
|
reason: supportbot.Suggestions.Threads.Reason,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Submitted = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(`${msgconfig.Suggestions.Sent_Title}`)
|
||||||
|
.setDescription(`${msgconfig.Suggestions.Sent}`)
|
||||||
|
.addFields(
|
||||||
|
{ name: "Sent to:", value: `<#${suggestChannel.id}>` },
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
embeds: [Submitted]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,470 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
StringSelectMenuBuilder,
|
||||||
|
StringSelectMenuOptionBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const panelconfig = yaml.load(fs.readFileSync("./Configs/ticket-panel.yml", "utf8"));
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
const TicketNumberID = require("../Structures/TicketID.js");
|
||||||
|
|
||||||
|
async function getClockedInUsers(guild) {
|
||||||
|
const clockedInUsers = new Set();
|
||||||
|
|
||||||
|
const profilesDir = './Data/Profiles';
|
||||||
|
const profileFiles = fs.readdirSync(profilesDir);
|
||||||
|
|
||||||
|
for (const file of profileFiles) {
|
||||||
|
const profileData = JSON.parse(fs.readFileSync(`${profilesDir}/${file}`, "utf8"));
|
||||||
|
if (profileData.clockedIn) {
|
||||||
|
const userId = file.replace('.json', '');
|
||||||
|
const member = await guild.members.fetch(userId);
|
||||||
|
if (member) clockedInUsers.add(member.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clockedInUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts = 0) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const clockedInUsers = await getClockedInUsers(interaction.guild);
|
||||||
|
|
||||||
|
if (clockedInUsers.size === 0 || attempts >= 2) {
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
if (claimChannel) {
|
||||||
|
const claimEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const claimButton = new ButtonBuilder()
|
||||||
|
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||||
|
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle || 'Claim Ticket')
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
content: `<@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.member.roles.cache.has(Staff.id);
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
await ticketChannel.send({ content: `<@${i.user.id}> has claimed the ticket.` });
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `Ticket is still unclaimed. \nCC: [<@&${Staff.id}> <@&${Admin.id}]`,
|
||||||
|
embeds: [new EmbedBuilder().setDescription(`Ticket is still unclaimed: <#${ticketChannel.id}>`).setColor(supportbot.Embed.Colours.Warn)],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
console.error("Claim channel not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clockedInArray = Array.from(clockedInUsers);
|
||||||
|
const assignedUserId = clockedInArray[Math.floor(Math.random() * clockedInArray.length)];
|
||||||
|
const assignedUser = await interaction.guild.members.fetch(assignedUserId);
|
||||||
|
|
||||||
|
const claimEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage.replace('%user%', interaction.user.id))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const claimButton = new ButtonBuilder()
|
||||||
|
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||||
|
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle || 'Claim Ticket')
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
if (!claimChannel) {
|
||||||
|
console.error("Claim channel not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
content: `${assignedUser}`,
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.user.id === assignedUserId;
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
await ticketChannel.send({ content: `<@${assignedUserId}>` }).then(msg => setTimeout(() => msg.delete(), 5000));
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
if (attempts >= 1) {
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `No one claimed the ticket. Tagging roles: <@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
embeds: [new EmbedBuilder().setDescription(`Ticket is still unclaimed: <#${ticketChannel.id}>`).setColor(supportbot.Embed.Colours.Warn)],
|
||||||
|
});
|
||||||
|
|
||||||
|
const claimEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const claimButton = new ButtonBuilder()
|
||||||
|
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||||
|
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle)
|
||||||
|
.setEmoji(supportbot.Ticket.ClaimTickets.ButtonEmoji)
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.member.roles.cache.has(Staff.id);
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
console.log(`Ticket ${ticketChannel.id} claimed by user ${i.user.id}`);
|
||||||
|
await ticketChannel.member.add(i.user.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
console.log(`No one claimed the ticket (${ticketChannel.id}), notifying all staff`);
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `No one claimed the ticket. Tagging roles: <@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const ReassigningEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ReassigningTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ReassigningMessage.replace('%user%', assignedUserId))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await claimChannel.send({ embeds: [ReassigningEmbed], components: [] });
|
||||||
|
await assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return assignedUserId;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in assignTicketToUser function:", error);
|
||||||
|
if (error instanceof CombinedError) {
|
||||||
|
console.error("CombinedError details:", error.errors);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.OpenTicket.Command,
|
||||||
|
description: cmdconfig.OpenTicket.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "reason",
|
||||||
|
description: "Ticket Reason",
|
||||||
|
type: ApplicationCommandOptionType.String,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.OpenTicket.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
try {
|
||||||
|
let TicketReason = null;
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
TicketReason = interaction.reason || null; // Retrieve the reason from the interaction object
|
||||||
|
}
|
||||||
|
|
||||||
|
let TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
let User = interaction.guild.members.cache.get(interaction.user.id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
supportbot.Ticket.TicketsPerUser &&
|
||||||
|
TicketData.tickets.filter((t) => t.user === interaction.user.id && t.open).length >= supportbot.Ticket.TicketsPerUser
|
||||||
|
) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
{
|
||||||
|
title: "Too Many Tickets!",
|
||||||
|
description: `You can't have more than ${supportbot.Ticket.TicketsPerUser} open tickets!`,
|
||||||
|
color: supportbot.Embed.Colours.Warn,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (User.roles.cache.has(supportbot.Roles.ModRoles.Blacklisted)) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: msgconfig.Ticket.Blacklisted,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (User.roles.cache.has(supportbot.Roles.ModRoles.Muted)) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: msgconfig.Ticket.Muted,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let ticketNumberID = await TicketNumberID.pad();
|
||||||
|
const TicketSubject = TicketReason || msgconfig.Ticket.InvalidSubject;
|
||||||
|
|
||||||
|
const TicketExists = new EmbedBuilder()
|
||||||
|
.setTitle("Ticket Exists!")
|
||||||
|
.setDescription(msgconfig.Ticket.TicketExists);
|
||||||
|
|
||||||
|
if (
|
||||||
|
await interaction.guild.channels.cache.find(
|
||||||
|
(ticketChannel) => ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}`
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return await interaction.reply({
|
||||||
|
embeds: [TicketExists],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!Staff || !Admin)
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Some roles seem to be missing!\nPlease check for errors when starting the bot.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let ticketChannel;
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
const TicketHome = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketHome || c.id === supportbot.Ticket.TicketHome
|
||||||
|
);
|
||||||
|
|
||||||
|
const channel = await getChannel(supportbot.Ticket.TicketHome, interaction.guild);
|
||||||
|
ticketChannel = await channel.threads.create({
|
||||||
|
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||||
|
type: ChannelType.PrivateThread,
|
||||||
|
parent: TicketHome,
|
||||||
|
autoArchiveDuration: 60,
|
||||||
|
reason: 'support ticket',
|
||||||
|
});
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const category = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketChannelsCategory || c.id === supportbot.Ticket.TicketChannelsCategory
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "The ticket category does not exist!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketChannel = await interaction.guild.channels.create({
|
||||||
|
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||||
|
type: ChannelType.GuildText,
|
||||||
|
parent: category.id,
|
||||||
|
reason: 'support ticket',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move to secondary category if the primary one is full
|
||||||
|
if (category.children.size >= 50) {
|
||||||
|
const secondaryCategory = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketChannelsCategory2 || c.id === supportbot.Ticket.TicketChannelsCategory2
|
||||||
|
);
|
||||||
|
|
||||||
|
if (secondaryCategory) {
|
||||||
|
await ticketChannel.setParent(secondaryCategory.id);
|
||||||
|
} else {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "The secondary ticket category does not exist!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign ticket to a user if claiming tickets is enabled
|
||||||
|
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
const assignedUserId = await assignTicketToUser(ticketChannel, Staff, Admin, interaction);
|
||||||
|
if (!assignedUserId) {
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(interaction.user.id);
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(Admin, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.guild.roles.everyone, {
|
||||||
|
ViewChannel: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save ticket data
|
||||||
|
TicketData.tickets.push({
|
||||||
|
id: ticketChannel.id,
|
||||||
|
name: ticketChannel.name,
|
||||||
|
user: interaction.user.id,
|
||||||
|
number: ticketNumberID,
|
||||||
|
reason: TicketSubject,
|
||||||
|
open: true,
|
||||||
|
subUsers: [],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
claimedAt: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/TicketData.json",
|
||||||
|
JSON.stringify(TicketData, null, 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notify the user that the ticket was created
|
||||||
|
const CreatedTicket = new EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.TicketCreatedAlert.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
.replace(/%ticketreason%/g, TicketSubject)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
await interaction.reply({ embeds: [CreatedTicket], ephemeral: true });
|
||||||
|
|
||||||
|
// Create the ticket message
|
||||||
|
const TicketMessage = new EmbedBuilder()
|
||||||
|
.setAuthor({
|
||||||
|
name: msgconfig.Ticket.TicketAuthorTitle.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username),
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
})
|
||||||
|
.setTitle(
|
||||||
|
msgconfig.Ticket.TicketTitle.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.TicketMessage.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
.replace(/%ticketreason%/g, TicketSubject)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
// Add reason field if ticket reason is enabled
|
||||||
|
if (supportbot.Ticket.TicketReason && TicketReason) {
|
||||||
|
TicketMessage.addFields(
|
||||||
|
{ name: "Reason", value: TicketReason, inline: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the control panel
|
||||||
|
const SelectMenus = new StringSelectMenuBuilder()
|
||||||
|
.setCustomId("ticketcontrolpanel")
|
||||||
|
.setPlaceholder("Ticket Control Panel")
|
||||||
|
.addOptions(
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Close")
|
||||||
|
.setDescription("Close the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
|
||||||
|
.setValue("ticketclose"),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Archive")
|
||||||
|
.setDescription("Archive the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.ArchiveEmoji)
|
||||||
|
.setValue("archiveticket"),
|
||||||
|
...(supportbot.Ticket.TicketType === "threads" ? [
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Lock Ticket")
|
||||||
|
.setDescription("Lock the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.LockEmoji)
|
||||||
|
.setValue("lockticket")
|
||||||
|
] : []),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Rename Ticket")
|
||||||
|
.setDescription("Rename the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.RenameEmoji)
|
||||||
|
.setValue("renameticket")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
SelectMenus.addOptions(
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Enable Invites")
|
||||||
|
.setDescription("Enable invites.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.EnableInvitesEmoji)
|
||||||
|
.setValue("enableinvites"),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Disable Invites")
|
||||||
|
.setDescription("Disable invites.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.DisableInvitesEmoji)
|
||||||
|
.setValue("disableinvites"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const row2 = new ActionRowBuilder().addComponents(SelectMenus);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [TicketMessage],
|
||||||
|
components: [row2],
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in run method:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// ticketpanel.js
|
||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const panelconfig = yaml.load(fs.readFileSync("./Configs/ticket-panel.yml", "utf8"));
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.TicketPanel.Command,
|
||||||
|
description: cmdconfig.TicketPanel.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.TicketPanel.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
if (!panelconfig.Panel) {
|
||||||
|
console.log(
|
||||||
|
"\u001b[31m",
|
||||||
|
`[TICKET PANEL]`,
|
||||||
|
"\u001b[33m",
|
||||||
|
"Ticket Panel is not setup, You can set this in", `\u001b[31m`, '/Configs/ticket-panel.yml', `\n `,
|
||||||
|
);
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket Panel is not set up. Please configure it in `/Configs/ticket-panel.yml`.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
const channel = await getChannel(
|
||||||
|
supportbot.Ticket.TicketHome,
|
||||||
|
interaction.guild
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
console.log(`[TICKET PANEL] ${channelName} channel not found. Please check your config file.`);
|
||||||
|
return interaction.reply({
|
||||||
|
content: `${channelName} channel not found. Please check your config file.`,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelid = JSON.parse(fs.readFileSync("./Data/ticket-panel-id.json", "utf8"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await channel.messages.fetch(panelid.TicketPanelID);
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket panel message already exists.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
let embed = new EmbedBuilder()
|
||||||
|
.setTitle(panelconfig.PanelTitle)
|
||||||
|
.setColor(panelconfig.PanelColour)
|
||||||
|
.setFooter({
|
||||||
|
text: supportbot.Embed.Footer,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (panelconfig.TicketPanel_Description) {
|
||||||
|
embed.setDescription(panelconfig.PanelMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panelconfig.TicketPanel_Thumbnail) {
|
||||||
|
embed.setThumbnail(panelconfig.PanelThumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panelconfig.TicketPanel_Image) {
|
||||||
|
embed.setImage(panelconfig.PanelImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const createTicketButton = new ButtonBuilder()
|
||||||
|
.setCustomId("createticket")
|
||||||
|
.setLabel(panelconfig.Button.Text)
|
||||||
|
.setEmoji(panelconfig.Button.Emoji)
|
||||||
|
.setStyle(panelconfig.Button.Color);
|
||||||
|
|
||||||
|
let row = new ActionRowBuilder().addComponents(createTicketButton);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = await channel.send({
|
||||||
|
embeds: [embed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
id: panelid.id,
|
||||||
|
TicketPanelID: message.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/ticket-panel-id.json",
|
||||||
|
JSON.stringify(data),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket panel message has been sent!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error sending message:", e);
|
||||||
|
return interaction.reply({
|
||||||
|
content: "An error occurred while sending the ticket panel message.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Translate Command
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const cmdconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||||
|
)
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
const translate = require("@vitalets/google-translate-api");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Translate.Command,
|
||||||
|
description: cmdconfig.Translate.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
name: "language",
|
||||||
|
description: "A 2 letter language code",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
name: "text",
|
||||||
|
description: "The text to translate",
|
||||||
|
required: true,
|
||||||
|
}, // The input text for the translation
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Translate.Permission, // The permission the user/role at least requires
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin)
|
||||||
|
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
|
||||||
|
const NoPerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)
|
||||||
|
)
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
let lang = interaction.options.getString("language"); // Grab choice of language code by user
|
||||||
|
let url = "https://www.science.co.il/language/Codes.php"; // URL to all available language codes
|
||||||
|
let text = await interaction.options.getString("text"); // Grab the text to translate by the user
|
||||||
|
let translatelog = await getChannel(
|
||||||
|
supportbot.Translate.TranslateLog,
|
||||||
|
interaction.guild
|
||||||
|
); // Grab the set logging channel for translations
|
||||||
|
|
||||||
|
|
||||||
|
// Return message if user has provided an invalid language code
|
||||||
|
const result = await translate(text, { to: lang }).catch(async (err) => {
|
||||||
|
if (err && err.code == 400) {
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new Discord.EmbedBuilder()
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn)
|
||||||
|
.setTitle("Valid Language Codes")
|
||||||
|
.setURL(url)
|
||||||
|
.setDescription(
|
||||||
|
"Click the title to see which 2 letter language codes are valid."
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
// Embed containing language code, original text and translated text
|
||||||
|
let transembed = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL({ dynamic: true }) })
|
||||||
|
.setColor(supportbot.Embed.Colours.Success)
|
||||||
|
.setDescription(`**Translation to ${lang}**`)
|
||||||
|
.addFields(
|
||||||
|
{ name: "Original text", value: text },
|
||||||
|
{ name: "Translated text", value: result.text },
|
||||||
|
)
|
||||||
|
.setFooter({ text: `Author: ${interaction.user.id}` })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
// Send embed [transembed] with translated message to channel
|
||||||
|
await interaction.reply({ embeds: [transembed] });
|
||||||
|
|
||||||
|
// Send embed [transembed] to logging channel
|
||||||
|
await translatelog.send({ embeds: [transembed] });
|
||||||
|
},
|
||||||
|
|
||||||
|
})
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://dsc.gg/emerald-dev
|
||||||
|
# Official Documentation: https://emeraldsrv.dev/wiki
|
||||||
|
# Third-Party Documentation: https://emeraldsrv.dev/third-party
|
||||||
|
#
|
||||||
|
# Command Configuration
|
||||||
|
|
||||||
|
# If you don't want to mess with this configuration, You can manage commands via Discord Settings the Intregations.
|
||||||
|
|
||||||
|
Help:
|
||||||
|
Command: "help"
|
||||||
|
Description: "Get a list of all the commands."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Info:
|
||||||
|
Command: "info"
|
||||||
|
Description: "Get information about the **ServerName**."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
TicketPanel:
|
||||||
|
Command: "ticketpanel"
|
||||||
|
Description: "Create the ticket creation panel"
|
||||||
|
Permission: ["Administrator"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Profile:
|
||||||
|
Command: "profile"
|
||||||
|
Description: "Shows the profile for a discord member."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
# Command is automatically disabled when the TicketClaims is disabled.
|
||||||
|
|
||||||
|
OpenTicket:
|
||||||
|
Command: "ticket"
|
||||||
|
Description: "Create a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
AddUser:
|
||||||
|
Command: "add"
|
||||||
|
Description: "Add a user to a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
ForceAddUser:
|
||||||
|
Command: "forceadd"
|
||||||
|
Description: "Add a user to a support ticket by bypassing the invite system."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
RemoveUser:
|
||||||
|
Command: "remove"
|
||||||
|
Description: "Remove a user from a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
CloseTicket:
|
||||||
|
Command: "close"
|
||||||
|
Description: "Close a support ticket"
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Suggestion:
|
||||||
|
Command: "suggest"
|
||||||
|
Description: "Create a suggestion."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Embed:
|
||||||
|
Command: "embed"
|
||||||
|
Description: "Build a discord embed."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Translate:
|
||||||
|
Command: "translate"
|
||||||
|
Description: "Translate something to english"
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
UserInfo:
|
||||||
|
Command: "userinfo"
|
||||||
|
Description: "Get info about a user."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Ping:
|
||||||
|
Command: "ping"
|
||||||
|
Description: "Pong."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Bot Administrator Commands
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
Command: "settings"
|
||||||
|
Description: "Update bot settings."
|
||||||
|
Permission: ["Administrator"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Command Description Configuration
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
BlacklistDesc: "Blacklist a user from creating Tickets."
|
||||||
|
TicketAddDesc: "Add a user to a support ticket."
|
||||||
|
TicketRemoveDesc: "Remove a user from a support ticket."
|
||||||
|
TranslateCommandDesc: "Translates the language provided, along with the abbreviation (2 char) long language code"
|
||||||
|
OpenTicketDesc: "Open a new support ticket."
|
||||||
|
CloseTicketDesc: "Close your support ticket."
|
||||||
|
InfoCommandDesc: "Get information about the brand."
|
||||||
|
PingCommandDesc: "Pong!"
|
||||||
|
HelpCommandDesc: "Get a list of all the commands."
|
||||||
|
EmbedCommandDesc: "Send a message as an embed."
|
||||||
|
SuggestCommandDesc: "Suggest a feature for the server."
|
||||||
|
UserInfoCommandDesc: "Get info about a user."
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://dsc.gg/emerald-dev
|
||||||
|
# Official Documentation: https://emeraldsrv.com/wiki
|
||||||
|
# Third-Party Documentation: https://emeraldsrv.com/third-party
|
||||||
|
#
|
||||||
|
# Messages Configuration
|
||||||
|
|
||||||
|
Info:
|
||||||
|
Title: "About Us"
|
||||||
|
Description: "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand."
|
||||||
|
Button: "Visit Site"
|
||||||
|
URL: "https://docs.emeraldsrv.com"
|
||||||
|
Colour: "#f74343"
|
||||||
|
|
||||||
|
Welcome:
|
||||||
|
Embed:
|
||||||
|
Colour: "#f74343"
|
||||||
|
Title: "Welcome to ServerName"
|
||||||
|
Message: ":smile: %joined_user% has just landed!"
|
||||||
|
Thumbnail: "BOT"
|
||||||
|
|
||||||
|
ImageEnabled: false
|
||||||
|
ImageURL: "https://animagelink.png/"
|
||||||
|
|
||||||
|
Leave:
|
||||||
|
Embed:
|
||||||
|
Colour: "#f74343"
|
||||||
|
Title: "Goodbye!"
|
||||||
|
Message: ":slight_frown: %joined_user% has recently dropped out!"
|
||||||
|
Thumbnail: "BOT"
|
||||||
|
|
||||||
|
ImageEnabled: false
|
||||||
|
ImageURL: "https://animagelink.png/"
|
||||||
|
|
||||||
|
Suggestions:
|
||||||
|
Sent_Title: "Suggestion Sent!"
|
||||||
|
Sent: ":white_check_mark: **You have successfully sent a suggestion.**"
|
||||||
|
NoSelfVote: ":x: **You cannot vote on your own suggestion.**"
|
||||||
|
RemoveVoteButton: "Remove Vote"
|
||||||
|
|
||||||
|
Ticket:
|
||||||
|
|
||||||
|
# Available Placeholders:
|
||||||
|
|
||||||
|
# %ticketusername% - User who created the ticket.
|
||||||
|
# <@%ticketauthor%> - Tags the user who created the ticket.
|
||||||
|
# <#%ticketid%> - Mentions the ticket channel.
|
||||||
|
|
||||||
|
TicketAuthorTitle: "%ticketusername%'s Ticket"
|
||||||
|
TicketTitle: "Support Ticket"
|
||||||
|
TicketMessage: "Hello <@%ticketauthor%>, Thank you for creating a support ticket\nPlease wait patiently whilst a member of our team reaches out to you."
|
||||||
|
TicketThumbnail: "https://images.emojiterra.com/google/android-pie/512px/1f39f.png"
|
||||||
|
TicketCreatedAlert: ":ticket: Ticked Created: <#%ticketid%>"
|
||||||
|
TicketExists: "❌ Ticket already exists"
|
||||||
|
TicketClaim: ":white_check_mark: Ticket claimed by" #The user who claimed the ticket will be added to the end of this message
|
||||||
|
TicketUnclaim: ":white_check_mark: Ticket unclaimed by" #The user who claimed the ticket will be added to the end of this message
|
||||||
|
|
||||||
|
TicketArchived: ":white_check_mark: Ticket archived."
|
||||||
|
TicketUnarchived: ":white_check_mark: Ticket unarchived."
|
||||||
|
TicketLocked: ":lock: Ticket is locked."
|
||||||
|
DisableInvites: "🔒 Invites have been disabled for this ticket."
|
||||||
|
EnableInvites: "🔓 Invites have been enabled for this ticket."
|
||||||
|
|
||||||
|
# Available Placeholders:
|
||||||
|
|
||||||
|
# <@%user%> - Tags the user who was added to the ticket.
|
||||||
|
|
||||||
|
Blacklisted: ":x: You are not allowed to open a ticket"
|
||||||
|
Muted: ":x: You are `Muted` and therefore not allowed to open any tickets"
|
||||||
|
InvalidSubject: "No Reason Provided!"
|
||||||
|
|
||||||
|
ConfirmClose: "Please confirm closing the ticket by clicking the button below."
|
||||||
|
CloseTimeout: "Ticket close confirmation timed out."
|
||||||
|
|
||||||
|
RenamedSuccess: "🏷️ Ticket renamed successfully!"
|
||||||
|
|
||||||
|
ClaimTickets:
|
||||||
|
ClaimTitle: "Incoming Support Request!"
|
||||||
|
ClaimMessage: "A new ticket has been created by <@!%user%>. Click the button below to claim this ticket."
|
||||||
|
ClaimMessage_Edit: "<#%channel%> was claimed by <@!%user%>."
|
||||||
|
|
||||||
|
ClaimedTitle: "Ticket Claimed!"
|
||||||
|
Claimed: "You have successfully claimed this ticket. <#%channel%>"
|
||||||
|
NoPermsToClaimTitle: "Error, no permissions!"
|
||||||
|
NoPermsToClaim: ":x: **Err!** You do not permissions to claim this ticket."
|
||||||
|
|
||||||
|
ReassigningTitle: "Reassigning!..."
|
||||||
|
ReassigningMessage: "<@%user%> did not claim the ticket. **Reassigning...**"
|
||||||
|
|
||||||
|
TicketStats:
|
||||||
|
OpenTickets: "✅ Open Tickets"
|
||||||
|
TotalTickets: "🎫 Total Tickets"
|
||||||
|
ResponseTime: "⏱️ Average Response Time"
|
||||||
|
|
||||||
|
Title: "Your Ticket Stats"
|
||||||
|
|
||||||
|
TicketLog:
|
||||||
|
Title: "Ticket Log"
|
||||||
|
Colour: "#0cc559"
|
||||||
|
|
||||||
|
AddUser:
|
||||||
|
NotInTicket_Title: "Ticket Invitation"
|
||||||
|
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||||
|
|
||||||
|
Invite_Title: "User Invited"
|
||||||
|
Invite_Description: "%username% has been invited to join the ticket."
|
||||||
|
|
||||||
|
DM_Title: "Ticket Invitation"
|
||||||
|
DM_Description: "You have been invited to join the ticket %channelname%. Do you accept?"
|
||||||
|
|
||||||
|
Accept_Label: "Accept"
|
||||||
|
Reject_Label: "Reject"
|
||||||
|
ViewTicket_Label: "Go to Ticket"
|
||||||
|
|
||||||
|
Accepted_Title: "Invitation Accepted"
|
||||||
|
Accepted_Message: "You have been added to the ticket."
|
||||||
|
AddedToTicket_Title: "Added to Ticket"
|
||||||
|
AddedToTicket_Description: "You have been added to the ticket %channel_link%."
|
||||||
|
|
||||||
|
# Added Message for inside the ticket, this informs everyone inside the ticket that the user has been added.
|
||||||
|
Added_Title: "User Added"
|
||||||
|
Added_Description: "Successfully added **%username%** to the ticket."
|
||||||
|
|
||||||
|
Declined_Title: "Invitation Declined"
|
||||||
|
Declined_Message: "You have declined the invitation."
|
||||||
|
|
||||||
|
NoResponse_Title: "No Response"
|
||||||
|
NoResponse_Message: "You did not respond in time. Please contact staff if you wish to join the ticket."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Adding: "There was an error adding you to the ticket. Please try again."
|
||||||
|
|
||||||
|
DM_Error_Title: "Error"
|
||||||
|
DM_Error_Description: "Unable to send a DM to %username%. Please ensure your DMs are enabled."
|
||||||
|
|
||||||
|
Unexpected_Error_Title: "Error"
|
||||||
|
Unexpected_Error_Description: "An unexpected error occurred: %error%"
|
||||||
|
|
||||||
|
RemoveUser:
|
||||||
|
NotInTicket_Title: "Error"
|
||||||
|
NotInTicket_Description: "This command can only be used in ticket threads."
|
||||||
|
|
||||||
|
Removed_Title: "User Removed"
|
||||||
|
Removed_Message: "The user has been successfully removed from the ticket."
|
||||||
|
|
||||||
|
RemovedFromTicket_Title: "Removed from Ticket"
|
||||||
|
RemovedFromTicket_Description: "You have been removed from the ticket channel %channel_link%."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Removing: "There was an error removing the user from the ticket."
|
||||||
|
|
||||||
|
ForceAddUser:
|
||||||
|
NotInTicket_Title: "Not a Ticket"
|
||||||
|
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||||
|
|
||||||
|
Added_Title: "User Added"
|
||||||
|
Added_Description: "Successfully added %username% to the ticket."
|
||||||
|
|
||||||
|
AddedToTicket_Title: "You have been added to a Ticket"
|
||||||
|
AddedToTicket_Description: "You have been added to the ticket channel [%channel_link%]."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Adding: "There was an error adding the user to the ticket."
|
||||||
|
|
||||||
|
Error:
|
||||||
|
IncorrectPerms: ":x: **Err!** You do not have the correct permissions to use this."
|
||||||
|
InvalidChannel: ":x: **Err!** Channel not found. Please create it!"
|
||||||
|
UserNotFound: ":x: **Err!** This user doesn't exist, Are they in this server?"
|
||||||
|
NoValidTicket: ":warning: You cannot execute this command here."
|
||||||
|
TicketExists: ":warning: This ticket cannot be opened, It already exists!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# -------------------------
|
||||||
|
# SupportBot AI
|
||||||
|
#
|
||||||
|
# In order to use the SupportBot AI, You need to setup an OpenAI Account.
|
||||||
|
# this can be done at https://platform.openai.com/
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
General:
|
||||||
|
Name: "SupportBot AI"
|
||||||
|
# What would you like to call your AI
|
||||||
|
Model: "gpt-4o-mini"
|
||||||
|
# You can see a list of OpenAI Models here: https://platform.openai.com/docs/models
|
||||||
|
|
||||||
|
Tokens: 400
|
||||||
|
# Max tokens you can set is 400
|
||||||
|
# For more information about tokens, go to https://openai.com/api/pricing/
|
||||||
|
OpenAI_Key: "OPEN_AI_API_KEY"
|
||||||
|
# To create an OpenAI API key, go to https://platform.openai.com/api-keys
|
||||||
|
|
||||||
|
|
||||||
|
PastebinAPI_Key: "PASTEBIN_API_KEY"
|
||||||
|
# You can get your Pastebin API Key from https://pastebin.com
|
||||||
|
PastebinAPI_URL: "https://pastebin.com/api/api_post.php"
|
||||||
|
|
||||||
|
Channels:
|
||||||
|
AIChannel: "AI_BOT_CHANNEL"
|
||||||
|
# This is the channel where AI will respond in without needing to mention the bot.
|
||||||
|
|
||||||
|
Embed:
|
||||||
|
Color: 0x0cc559 # 0x<hexcode>
|
||||||
|
Footer: "SupportBot | Developed by Emerald Development"
|
||||||
|
|
||||||
|
Messages:
|
||||||
|
MessageTooLong: "The response was too long, so I've posted it here: {pastebin}"
|
||||||
|
ErrorResponse: "I didn't receive a proper response from OpenAI. Please try again later."
|
||||||
|
OpenAIError: "I'm having some trouble talking to SupportBot AI's Model, OpenAI. Please try again later."
|
||||||
|
AIDisabled: "I am disabled, You have enable me in `supportbot-ai.yml`"
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Development
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://dsc.gg/emerald-dev
|
||||||
|
# Official Documentation: https://github.com/Emerald-Services/SupportBot/wiki
|
||||||
|
# Third-Party Documentation: COMING SOON
|
||||||
|
|
||||||
|
SupportBot_Version: "v8.2"
|
||||||
|
# Do not change the version number
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# General
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
General:
|
||||||
|
Name: "SupportBot"
|
||||||
|
Token: "BOT_TOKEN_HERE"
|
||||||
|
# To get your Discord Bot Token, Go to https://discord.com/developers/applications
|
||||||
|
|
||||||
|
Addons:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Activity
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Activity:
|
||||||
|
Status: "SupportBot v8"
|
||||||
|
Type: "Competing"
|
||||||
|
# The Type can either be Playing, Watching, Listening or Competing
|
||||||
|
StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME"
|
||||||
|
# Set The Type to "Streaming" for a streaming status!
|
||||||
|
|
||||||
|
# You can update the activity via Discord using: /settings
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Embeds
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Embed:
|
||||||
|
Colours:
|
||||||
|
General: 0x0cc559 # 0x<hexcode>
|
||||||
|
Success: 0x04b545 # 0x<hexcode>
|
||||||
|
Error: 0xd13030 # 0x<hexcode>
|
||||||
|
Warn: 0xfca117 # 0x<hexcode>
|
||||||
|
|
||||||
|
Footer: "SupportBot | Developed by Emerald Development"
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Roles
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Roles:
|
||||||
|
AutoRole:
|
||||||
|
Enabled: true
|
||||||
|
Role: "ROLE_ID"
|
||||||
|
|
||||||
|
StaffMember:
|
||||||
|
Staff: "STAFF_ROLE_ID"
|
||||||
|
Admin: "ADMIN_ROLE_ID"
|
||||||
|
|
||||||
|
ModRoles:
|
||||||
|
Muted: "MUTED_ROLE_ID"
|
||||||
|
Blacklisted: "BLACKLISTED_ROLE_ID"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# System Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Welcome:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "WELCOME_CHANNEL_ID"
|
||||||
|
|
||||||
|
Leave:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "LEAVE_CHANNEL_ID"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Suggestions
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Suggestions:
|
||||||
|
Channel: "SUGGEST_CHANNEL_ID"
|
||||||
|
UpvoteEmoji: "✅"
|
||||||
|
DownvoteEmoji: "❌"
|
||||||
|
|
||||||
|
UpvoteTitle: "Yes"
|
||||||
|
DownvoteTitle: "No"
|
||||||
|
|
||||||
|
OwnSuggestion: true
|
||||||
|
# If false this will not allow the user to vote for a suggestion they created
|
||||||
|
# If true this will allow the user to vote for a suggestion they created
|
||||||
|
|
||||||
|
ShowUsers: true
|
||||||
|
|
||||||
|
Threads:
|
||||||
|
Enabled: true
|
||||||
|
Title: "Suggestion-releated Thread"
|
||||||
|
Reason: "A thread releted to this suggestion"
|
||||||
|
|
||||||
|
Buttons:
|
||||||
|
Upvote: "2"
|
||||||
|
Downvote: "2"
|
||||||
|
RemoveVote: "4"
|
||||||
|
RemoveVote_Title: "Remove Vote"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Tickets
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Ticket:
|
||||||
|
TicketType: "channels" # Choose how you want tickets to be created.
|
||||||
|
# Options:
|
||||||
|
# channels - Tickets will be created as channels in the
|
||||||
|
# threads - Tickets will be created as threads through the "TicketHome"
|
||||||
|
|
||||||
|
# For TicketType "Threads"
|
||||||
|
TicketHome: "TICKETHOME_CHANNEL_ID"
|
||||||
|
# What is TicketHome?
|
||||||
|
# - Channel where the Ticket creation panel is sent.
|
||||||
|
# - Channel where ticket threads are made. (only if ticket threads is enabled above.)
|
||||||
|
|
||||||
|
# For TicketType "Channels"
|
||||||
|
TicketChannelsCategory: "TICKET_CATEGORY_ID" # if Type is set to channels
|
||||||
|
TicketChannelsCategory2: "BACKUP_TICKET_CATEGORY_ID" # This will be used if the first category has reached the max channel limit.
|
||||||
|
TicketArchiveCategory: "ARCHIVE_TICKET_CATEGORY_ID"
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
Channel: "ticket-" # The prefix for ticket channel names
|
||||||
|
TicketsPerUser: 100
|
||||||
|
DMTranscripts: true
|
||||||
|
TicketReason: true
|
||||||
|
# If ticket reason is set to false, It will not prompt to create a reason
|
||||||
|
TicketSubject: "description"
|
||||||
|
# "description" will display the ticket reason within the channel description
|
||||||
|
# "embed" will display the ticket reason within the ticket embed
|
||||||
|
Timeout: 5
|
||||||
|
# Set to true to allow all staff to access the ticket
|
||||||
|
|
||||||
|
Log:
|
||||||
|
TicketDataLog: "TICKET_LOG_ID"
|
||||||
|
TickeDataTitle: "Ticket Data"
|
||||||
|
|
||||||
|
Close:
|
||||||
|
StaffOnly: true
|
||||||
|
# Set to false is anyone is able to close a ticket.
|
||||||
|
|
||||||
|
Confirmation_Button: "Confirm Close"
|
||||||
|
Confirmation_Emoji: "🗑️"
|
||||||
|
Confirmation_Style: "2"
|
||||||
|
|
||||||
|
Title: "Are you sure you want to close this ticket?"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
Invites:
|
||||||
|
StaffOnly: true
|
||||||
|
|
||||||
|
ClaimTickets:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "CLAIM_TICKETS_CHANNEL_ID"
|
||||||
|
# Channel name or Channel ID
|
||||||
|
|
||||||
|
ClaimAcceptTime: 120000
|
||||||
|
# How long the assigned user has to accept the ticket before it gets re-assigned to someone else.
|
||||||
|
# 120000 = 2 Minutes
|
||||||
|
# 180000 = 3 Minutes
|
||||||
|
# 240000 = 4 Minutes
|
||||||
|
# 300000 = 5 Minutes
|
||||||
|
# Time in Mliseconds
|
||||||
|
|
||||||
|
ButtonTitle: "Claim Ticket"
|
||||||
|
ButtonEmoji: "🎫"
|
||||||
|
Button: "1"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Buttons
|
||||||
|
# -------------------------
|
||||||
|
Buttons:
|
||||||
|
Tickets:
|
||||||
|
ClaimEmoji: "🧑💻"
|
||||||
|
ClaimStyle: "1"
|
||||||
|
|
||||||
|
Unarchive: "Unarchive Ticket"
|
||||||
|
Unarchive_Emoji: "♻️"
|
||||||
|
Unarchive_Style: "2"
|
||||||
|
|
||||||
|
Unlock: "Unlock Ticket"
|
||||||
|
Unlock_Emoji: "🔓"
|
||||||
|
Unlock_Style: "2"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Select Menus
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
SelectMenus:
|
||||||
|
Tickets:
|
||||||
|
PanelEmoji: "⚙️"
|
||||||
|
|
||||||
|
CloseEmoji: "🗑️"
|
||||||
|
ArchiveEmoji: "♻️"
|
||||||
|
LockEmoji: "🔐"
|
||||||
|
RenameEmoji: "🏷️"
|
||||||
|
|
||||||
|
EnableInvitesEmoji: "📤"
|
||||||
|
DisableInvitesEmoji: "📥"
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Misc
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Translate:
|
||||||
|
TranslateLog: "TRANSLATE_LOG_ID"
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://emeraldsrv.dev/discord
|
||||||
|
# Community Resources: https://emeraldsrv.dev/resources
|
||||||
|
|
||||||
|
# -------------------------------
|
||||||
|
# Ticket Panel Configuration
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
Panel: true
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Ticket Panel Message Configuration #2b2d31
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
PanelTitle: "SupportBot"
|
||||||
|
PanelColour: "#0cc559"
|
||||||
|
|
||||||
|
Button:
|
||||||
|
Text: "Create Ticket"
|
||||||
|
Emoji: "🎫"
|
||||||
|
Color: "2"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Red
|
||||||
|
# 4 - Green
|
||||||
|
|
||||||
|
TicketPanel_Description: true
|
||||||
|
TicketPanel_Thumbnail: false
|
||||||
|
TicketPanel_Image: true
|
||||||
|
|
||||||
|
PanelMessage: "Click on the button to file a `Ticket` and our team will try their best to assist you in the best way we can!"
|
||||||
|
PanelThumbnail: "https://i.imgur.com/ieeZejl.png"
|
||||||
|
PanelImage: "https://i.imgur.com/dejQvkg.png"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"tickets": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"bio": "",
|
||||||
|
"timezone": "",
|
||||||
|
"clockedIn": false
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"TicketPanelID": "0000000000000000000"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
module.exports = new Event("guildCreate", async (client) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31m`,
|
||||||
|
`${client.user.username} is not in the correct server set in your config. Please leave all other servers and restart the bot.`
|
||||||
|
);
|
||||||
|
console.log(`\u001b[31m`, `${client.user.username} will now exit.`);
|
||||||
|
return process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
module.exports = new Event("guildDelete", async (client) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31m`,
|
||||||
|
`${client.user.username} is not in the correct server set in your config. Please join the server and restart the bot.`
|
||||||
|
);
|
||||||
|
console.log(`\u001b[31m`, `${client.user.username} will now exit.`);
|
||||||
|
return process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
const Discord = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const cmdconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = new Event("guildMemberAdd", async (client, member, interaction, guild) => {
|
||||||
|
|
||||||
|
if (supportbot.Welcome.Enabled) {
|
||||||
|
const WelcomeChannel = member.guild.channels.cache.get(supportbot.Welcome.Channel) ||
|
||||||
|
member.guild.channels.cache.find(channel => channel.name === supportbot.Welcome.Channel);
|
||||||
|
|
||||||
|
const WelcomeEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setColor(msgconfig.Welcome.Embed.Colour)
|
||||||
|
.setTitle(msgconfig.Welcome.Embed.Title)
|
||||||
|
.setDescription(msgconfig.Welcome.Embed.Message.replace(/%joined_user%/g, member.user))
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (msgconfig.Welcome.Embed.Thumbnail === "BOT") {
|
||||||
|
WelcomeEmbed.setThumbnail(client.user.displayAvatarURL())
|
||||||
|
} else if (msgconfig.Welcome.Embed.Thumbnail === "USER") {
|
||||||
|
WelcomeEmbed.setThumbnail(member.user.displayAvatarURL())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msgconfig.Welcome.Embed.ImageEnabled) {
|
||||||
|
WelcomeEmbed.setImage(msgconfig.Welcome.Embed.ImageURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WelcomeChannel) {
|
||||||
|
WelcomeChannel.send({ embeds: [WelcomeEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Roles.AutoRole.Enabled) {
|
||||||
|
const role = member.guild.roles.cache.get(supportbot.Roles.AutoRole.Role) ||
|
||||||
|
member.guild.roles.cache.find(role => role.name === supportbot.Roles.AutoRole.Role);
|
||||||
|
if (role) {
|
||||||
|
member.roles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\u001b[32m`, `[+]`, `\u001b[33m`, `${member.user.username} joined the server!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
const Discord = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const cmdconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = new Event("guildMemberRemove", async (client, member, interaction, guild) => {
|
||||||
|
|
||||||
|
if (supportbot.Leave.Enabled) {
|
||||||
|
const LeaveChannel = member.guild.channels.cache.get(supportbot.Leave.Channel) ||
|
||||||
|
member.guild.channels.cache.find(channel => channel.name === supportbot.Leave.Channel);
|
||||||
|
|
||||||
|
const LeaveEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setColor(msgconfig.Leave.Embed.Colour)
|
||||||
|
.setTitle(msgconfig.Leave.Embed.Title)
|
||||||
|
.setDescription(msgconfig.Leave.Embed.Message.replace(/%left_user%/g, member.user))
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (msgconfig.Leave.Embed.Thumbnail === "BOT") {
|
||||||
|
LeaveEmbed.setThumbnail(client.user.displayAvatarURL());
|
||||||
|
} else if (msgconfig.Leave.Embed.Thumbnail === "USER") {
|
||||||
|
LeaveEmbed.setThumbnail(member.user.displayAvatarURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msgconfig.Leave.Embed.ImageEnabled) {
|
||||||
|
LeaveEmbed.setImage(msgconfig.Leave.Embed.ImageURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LeaveChannel) {
|
||||||
|
LeaveChannel.send({
|
||||||
|
embeds: [LeaveEmbed]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\u001b[31m`, `[-]`, `\u001b[33m`, `${member.user.username} left the server!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,691 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
let suggestions;
|
||||||
|
try {
|
||||||
|
suggestions = require("../Data/SuggestionData.json");
|
||||||
|
} catch (error) {
|
||||||
|
suggestions = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||||
|
|
||||||
|
if (interaction.type === Discord.InteractionType.ApplicationCommand) {
|
||||||
|
const command = client.commands.find(
|
||||||
|
(cmd) => cmd.name.toLowerCase() === interaction.commandName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (interaction.user.bot || !interaction.guild) return;
|
||||||
|
|
||||||
|
const NotValid = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`:x: \`Invalid Command\``)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!command)
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [NotValid],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const permission = interaction.member.permissions.has(command.permissions);
|
||||||
|
|
||||||
|
const ValidPerms = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
"> :x: `Invalid Permissions` Do you have the correct permissions to execute this command?"
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!permission)
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [ValidPerms],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (command.name === cmdconfig.OpenTicket.Command && supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
console.log("\u001b[32m", "[Executed]", "\u001b[37;1m", `${interaction.user.username} has executed ${command.name}`);
|
||||||
|
await command.run(interaction);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error executing command:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "An error occurred while executing the command.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isModalSubmit()) {
|
||||||
|
if (interaction.customId === "ticketReasonModal") {
|
||||||
|
const reason = interaction.fields.getTextInputValue("reasonInput");
|
||||||
|
interaction.customId = `createticket-${reason}`;
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (cmd) {
|
||||||
|
interaction.reason = reason; // Attach the reason to the interaction object
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} else {
|
||||||
|
console.error("Command not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "renameTicketModal") {
|
||||||
|
const newTicketName = interaction.fields.getTextInputValue("renameTicket");
|
||||||
|
|
||||||
|
// Fixing the ticketChannelId extraction and lookup
|
||||||
|
const ticketChannelId = interaction.channel.id;
|
||||||
|
|
||||||
|
let ticketChannel;
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ticketChannel) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket channel not found.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ticketChannel.setName(newTicketName);
|
||||||
|
|
||||||
|
const renamedsuccess = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.RenamedSuccess)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [renamedsuccess],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error renaming the ticket:", error);
|
||||||
|
return interaction.reply({
|
||||||
|
content: "There was an error renaming the ticket.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isStringSelectMenu()) {
|
||||||
|
if (interaction.customId === "ticketcontrolpanel") {
|
||||||
|
const selectedOption = interaction.values[0];
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
switch (selectedOption) {
|
||||||
|
|
||||||
|
case "ticketclose":
|
||||||
|
const closeCommand = client.commands.get(cmdconfig.CloseTicket.Command);
|
||||||
|
if (closeCommand) {
|
||||||
|
await closeCommand.run(interaction);
|
||||||
|
} else {
|
||||||
|
console.error("[X] Close Command Not Found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "archiveticket":
|
||||||
|
const arcembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketArchived)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const CloseButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("confirmCloseTicket")
|
||||||
|
.setLabel(supportbot.Ticket.Close.Confirmation_Button)
|
||||||
|
.setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
|
||||||
|
.setStyle(supportbot.Ticket.Close.Confirmation_Style);
|
||||||
|
|
||||||
|
const unarchiveButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("unarchiveTicket")
|
||||||
|
.setLabel(supportbot.Buttons.Tickets.Unarchive)
|
||||||
|
.setEmoji(supportbot.Buttons.Tickets.Unarchive_Emoji)
|
||||||
|
.setStyle(supportbot.Buttons.Tickets.Unarchive_Style);
|
||||||
|
|
||||||
|
const ArchivedOptions = new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(CloseButton, unarchiveButton);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [arcembed],
|
||||||
|
components: [ArchivedOptions],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setArchived(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
await interaction.channel.setParent(supportbot.Ticket.TicketArchiveCategory);
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo) {
|
||||||
|
const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
|
||||||
|
const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
|
||||||
|
const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
|
||||||
|
const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
|
||||||
|
|
||||||
|
if (user && user.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(user.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === true) {
|
||||||
|
if (claimedBy && claimedBy.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === false) {
|
||||||
|
if (Staff && Staff.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Admin && Admin.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(Admin.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.permissionOverwrites.edit(interaction.guild.roles.everyone.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
ReadMessageHistory: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "lockticket":
|
||||||
|
const lockembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketLocked)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const unlockButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("unlockTicket")
|
||||||
|
.setLabel(supportbot.Buttons.Tickets.Unlock)
|
||||||
|
.setEmoji(supportbot.Buttons.Tickets.Unlock_Emoji)
|
||||||
|
.setStyle(supportbot.Buttons.Tickets.Unlock_Style);
|
||||||
|
|
||||||
|
const LockedOptions = new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(unlockButton);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [lockembed],
|
||||||
|
components: [LockedOptions],
|
||||||
|
ephemeral: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setLocked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "unlockTicket":
|
||||||
|
const unlockEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketUnlocked)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [unlockEmbed],
|
||||||
|
ephemeral: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setLocked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "enableinvites":
|
||||||
|
await handleInvites(interaction, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "disableinvites":
|
||||||
|
await handleInvites(interaction, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "renameticket":
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("renameTicketModal")
|
||||||
|
.setTitle("Rename Channel")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("renameTicket")
|
||||||
|
.setLabel("New Channel Name")
|
||||||
|
.setStyle(Discord.TextInputStyle.Short)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isButton()) {
|
||||||
|
if (interaction.customId === "unarchiveTicket") {
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setArchived(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
await interaction.channel.setParent(supportbot.Ticket.TicketChannelsCategory);
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo) {
|
||||||
|
const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
|
||||||
|
const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
|
||||||
|
const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
|
||||||
|
const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
|
||||||
|
|
||||||
|
if (user && user.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === true) {
|
||||||
|
if (claimedBy && claimedBy.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === false) {
|
||||||
|
if (Staff && Staff.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Admin && Admin.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(Admin.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.permissionOverwrites.edit(interaction.guild.roles.everyone.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
ReadMessageHistory: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unrcembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketUnarchived)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [unrcembed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "createticket") {
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (!cmd) return;
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error executing the ticket command:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "An error occurred while creating the ticket.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "openticket") {
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (!cmd) return;
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId.startsWith("claimticket-")) {
|
||||||
|
const ticketChannelId = interaction.customId.split("-")[1];
|
||||||
|
const ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
if (!ticketChannel) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket channel not found.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
|
||||||
|
const RolePerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (!Staff || !Admin) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [RolePerms],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPermsClaim = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.NoPermsToClaimTitle)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace("%channel%", ticketChannel.name)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!interaction.member.roles.cache.has(Staff.id) && !interaction.member.roles.cache.has(Admin.id)) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [NoPermsClaim],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(interaction.user.id);
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(Admin, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.guild.roles.everyone, {
|
||||||
|
ViewChannel: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const pingclaimedstaff = await ticketChannel.send(`<@${interaction.user.id}>`);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
pingclaimedstaff.delete();
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketIndex = TicketData.tickets.findIndex((t) => t.id === ticketChannelId);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
TicketData.tickets[ticketIndex].claimedBy = interaction.user.id;
|
||||||
|
TicketData.tickets[ticketIndex].claimedAt = new Date().toISOString();
|
||||||
|
fs.writeFileSync("./Data/TicketData.json", JSON.stringify(TicketData, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
const claimMessage = await interaction.message.fetch();
|
||||||
|
const claimedEmbed = new Discord.EmbedBuilder(claimMessage.embeds[0].data)
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.ClaimTickets.ClaimMessage_Edit.replace("%user%", interaction.user.id).replace("%channel%", ticketChannel.id)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const successfullyClaimed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.Claimed.replace("%channel%", ticketChannel.id))
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await claimMessage.edit({ embeds: [claimedEmbed], components: [] });
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [successfullyClaimed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUGGESTION INTERACTIONS [START]
|
||||||
|
|
||||||
|
if (
|
||||||
|
interaction.customId === "upvote" ||
|
||||||
|
interaction.customId === "downvote" ||
|
||||||
|
interaction.customId === "removevote"
|
||||||
|
) {
|
||||||
|
const suggestion = suggestions[interaction.message.id];
|
||||||
|
if (!suggestion)
|
||||||
|
return interaction.reply({ content: "Suggestion not found.", ephemeral: true });
|
||||||
|
|
||||||
|
const userId = interaction.user.id;
|
||||||
|
const hasUpvoted = suggestion.upvotes.includes(userId);
|
||||||
|
const hasDownvoted = suggestion.downvotes.includes(userId);
|
||||||
|
|
||||||
|
if (interaction.customId === "upvote") {
|
||||||
|
if (hasUpvoted) {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
} else {
|
||||||
|
suggestion.upvotes.push(userId);
|
||||||
|
if (hasDownvoted) {
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (interaction.customId === "downvote") {
|
||||||
|
if (hasDownvoted) {
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
} else {
|
||||||
|
suggestion.downvotes.push(userId);
|
||||||
|
if (hasUpvoted) {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (interaction.customId === "removevote") {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2));
|
||||||
|
|
||||||
|
const upvoteCount = suggestion.upvotes.length;
|
||||||
|
const downvoteCount = suggestion.downvotes.length;
|
||||||
|
|
||||||
|
const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data).setFields([
|
||||||
|
{ name: "Suggestion", value: suggestion.suggestion, inline: true },
|
||||||
|
{ name: "From", value: `<@${suggestion.author}>` },
|
||||||
|
{
|
||||||
|
name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`,
|
||||||
|
value: `${upvoteCount}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`,
|
||||||
|
value: `${downvoteCount}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await interaction.update({ embeds: [updatedEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleInvites(interaction, enable) {
|
||||||
|
if (supportbot.Ticket.Invites.StaffOnly) {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
const SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)
|
||||||
|
) {
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.setInvitable(enable);
|
||||||
|
|
||||||
|
const message = enable ? msgconfig.Ticket.EnableInvites : msgconfig.Ticket.DisableInvites;
|
||||||
|
const embed = new Discord.EmbedBuilder().setDescription(message).setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [embed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modal submission handler for editing profile
|
||||||
|
if (interaction.type === Discord.InteractionType.ModalSubmit && interaction.customId === "editProfileModal") {
|
||||||
|
const userId = interaction.user.id;
|
||||||
|
const profilePath = `./Data/Profiles/${userId}.json`;
|
||||||
|
|
||||||
|
let profileData;
|
||||||
|
if (fs.existsSync(profilePath)) {
|
||||||
|
profileData = JSON.parse(fs.readFileSync(profilePath, "utf8"));
|
||||||
|
} else {
|
||||||
|
profileData = {
|
||||||
|
bio: "",
|
||||||
|
timezone: "",
|
||||||
|
clockedIn: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newBio = interaction.fields.getTextInputValue("bio");
|
||||||
|
const newTimezone = interaction.fields.getTextInputValue("timezone");
|
||||||
|
|
||||||
|
profileData.bio = newBio;
|
||||||
|
profileData.timezone = newTimezone;
|
||||||
|
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
|
||||||
|
const updatedProfileEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(`${interaction.user.username}'s Profile`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.setThumbnail(interaction.user.displayAvatarURL())
|
||||||
|
.addFields(
|
||||||
|
{ name: "Bio", value: newBio || "No bio set.", inline: false },
|
||||||
|
{ name: "Timezone", value: newTimezone || "No timezone set.", inline: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (profileData.clockedIn !== undefined) {
|
||||||
|
updatedProfileEmbed.addFields({
|
||||||
|
name: "Clocked In Status",
|
||||||
|
value: profileData.clockedIn ? "✅ Clocked In" : "❌ Clocked Out",
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.reply({ embeds: [updatedProfileEmbed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update profile data: ", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "There was an error while updating your profile. Please try again later.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { OpenAI } = require('openai');
|
||||||
|
|
||||||
|
// Load configuration files with validation
|
||||||
|
function loadConfig(path) {
|
||||||
|
try {
|
||||||
|
return yaml.load(fs.readFileSync(path, "utf8"));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error loading config file at ${path}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const supportbotai = yaml.load(fs.readFileSync("./Configs/supportbot-ai.yml"));
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
// Validate configuration values
|
||||||
|
function validateConfig(config, keys) {
|
||||||
|
keys.forEach(key => {
|
||||||
|
if (!config[key]) {
|
||||||
|
throw new Error(`Missing configuration key: ${key}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHANNELS = [supportbotai.Channels.AIChannel];
|
||||||
|
|
||||||
|
// Initialize Discord client
|
||||||
|
const client = new Discord.Client({
|
||||||
|
intents: ['Guilds', 'GuildMembers', 'GuildMessages']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load custom Event structure
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
// Initialize OpenAI client
|
||||||
|
const openai = new OpenAI({
|
||||||
|
apiKey: supportbotai.General.OpenAI_Key,
|
||||||
|
});
|
||||||
|
|
||||||
|
const PASTEBIN_API_KEY = supportbotai.General.PastebinAPI_Key;
|
||||||
|
const PASTEBIN_API_URL = supportbotai.General.PastebinAPI_URL;
|
||||||
|
|
||||||
|
// Function to create a paste on Pastebin
|
||||||
|
async function createPaste(content) {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(PASTEBIN_API_URL, new URLSearchParams({
|
||||||
|
api_dev_key: PASTEBIN_API_KEY,
|
||||||
|
api_option: 'paste',
|
||||||
|
api_paste_code: content,
|
||||||
|
api_paste_private: 1, // 0 = public, 1 = unlisted, 2 = private
|
||||||
|
api_paste_expire_date: '1D', // Expire in 1 day
|
||||||
|
api_paste_format: 'text'
|
||||||
|
}));
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Pastebin Error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event handler for message creation
|
||||||
|
module.exports = new Event("messageCreate", async (client, message) => {
|
||||||
|
if (message.author.bot || !message.guild) return;
|
||||||
|
if (!CHANNELS.includes(message.channelId) && !message.mentions.users.has(client.user.id)) return;
|
||||||
|
|
||||||
|
if (supportbotai.Enabled) {
|
||||||
|
|
||||||
|
const sendTypingInterval = setInterval(() => {
|
||||||
|
message.channel.sendTyping();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
let conversation = [{
|
||||||
|
role: "system",
|
||||||
|
content: "SupportBot is your friendly neighbourhood support bot."
|
||||||
|
}];
|
||||||
|
|
||||||
|
let prevMessages = await message.channel.messages.fetch({ limit: 10 });
|
||||||
|
prevMessages = prevMessages.reverse().filter(msg => !msg.author.bot || msg.author.id === client.user.id);
|
||||||
|
|
||||||
|
prevMessages.forEach((msg) => {
|
||||||
|
const username = msg.author.username.replace(/\s+/g, '_').replace(/[^\w\s]/gi, '');
|
||||||
|
|
||||||
|
conversation.push({
|
||||||
|
role: msg.author.id === client.user.id ? "assistant" : "user",
|
||||||
|
name: username,
|
||||||
|
content: msg.content,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await openai.chat.completions.create({
|
||||||
|
model: supportbotai.General.Model,
|
||||||
|
messages: conversation,
|
||||||
|
max_tokens: supportbotai.General.Tokens,
|
||||||
|
});
|
||||||
|
|
||||||
|
clearInterval(sendTypingInterval);
|
||||||
|
|
||||||
|
if (response.choices && response.choices.length > 0) {
|
||||||
|
const replyContent = response.choices[0].message.content;
|
||||||
|
|
||||||
|
const SupportBotAI = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setDescription(replyContent)
|
||||||
|
.setColor(supportbotai.Embed.Color)
|
||||||
|
.setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (replyContent.length > 2000) {
|
||||||
|
const pasteLink = await createPaste(replyContent);
|
||||||
|
|
||||||
|
const SupportBotAIPastebin = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setDescription(supportbotai.Messages.MessageTooLong.replace("{pastebin}", pasteLink))
|
||||||
|
.setColor(supportbotai.Embed.Color)
|
||||||
|
.setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
message.reply({ embeds: [SupportBotAIPastebin] });
|
||||||
|
} else {
|
||||||
|
message.reply({ embeds: [SupportBotAI] });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const SupportBotAIErrorResponse = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setDescription(supportbotai.Messages.ErrorResponse)
|
||||||
|
.setColor(supportbotai.Embed.Color)
|
||||||
|
.setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
message.reply({ embeds: [SupportBotAIErrorResponse], ephemeral: true });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
clearInterval(sendTypingInterval);
|
||||||
|
|
||||||
|
const SupportBotAIErrorResponse = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setDescription(supportbotai.Messages.OpenAIError)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error)
|
||||||
|
.setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
console.error('OpenAI Error:', error);
|
||||||
|
message.reply({ embeds: [SupportBotAIErrorResponse], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbotai.Enabled === false) {
|
||||||
|
const AIDisabled = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setDescription(supportbotai.Messages.AIDisabled)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error)
|
||||||
|
.setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
message.reply({ embeds: [AIDisabled], ephemeral: true })
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ready Event
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const { Client, GatewayIntentBits, ActivityType } = require('discord.js');
|
||||||
|
const client = new Discord.Client({intents: 32767})
|
||||||
|
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
const panelconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/ticket-panel.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const cmdconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
let chan1 = client.channels.cache.get(supportbot.Ticket.TicketHome);
|
||||||
|
|
||||||
|
module.exports = new Event("ready", async (client, interaction) => {
|
||||||
|
const { getRole, getChannel, getCategory } = client;
|
||||||
|
|
||||||
|
if (supportbot.Activity.Type === "Playing", "playing") {
|
||||||
|
client.user.setPresence({
|
||||||
|
activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Playing }],
|
||||||
|
status: supportbot.Activity.Type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Activity.Type === "Watching", "watching") {
|
||||||
|
client.user.setPresence({
|
||||||
|
activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Watching }],
|
||||||
|
status: supportbot.Activity.Type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Activity.Type === "Listening", "listening") {
|
||||||
|
client.user.setPresence({
|
||||||
|
activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Listening }],
|
||||||
|
status: supportbot.Activity.Type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Activity.Type === "Competing", "competing") {
|
||||||
|
client.user.setPresence({
|
||||||
|
activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Competing }],
|
||||||
|
status: supportbot.Activity.Type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[31m`, `┏━━━┓╋╋╋╋╋╋╋╋╋╋╋╋╋┏┓┏━━┓╋╋╋┏┓`);
|
||||||
|
console.log(`\u001b[31m`, `┃┏━┓┃╋╋╋╋╋╋╋╋╋╋╋╋┏┛┗┫┏┓┃╋╋┏┛┗┓`);
|
||||||
|
console.log(`\u001b[31m`, `┃┗━━┳┓┏┳━━┳━━┳━━┳┻┓┏┫┗┛┗┳━┻┓┏┛`);
|
||||||
|
console.log(`\u001b[31m`, `┗━━┓┃┃┃┃┏┓┃┏┓┃┏┓┃┏┫┃┃┏━┓┃┏┓┃┃`);
|
||||||
|
console.log(`\u001b[31m`, `┃┗━┛┃┗┛┃┗┛┃┗┛┃┗┛┃┃┃┗┫┗━┛┃┗┛┃┗┓`);
|
||||||
|
console.log(`\u001b[31m`, `┗━━━┻━━┫┏━┫┏━┻━━┻┛┗━┻━━━┻━━┻━┛`);
|
||||||
|
console.log(`\u001b[31m`, `┗╋╋╋╋╋╋╋┃┃╋┃┃`);
|
||||||
|
console.log(`\u001b[31m`, `╋╋╋╋╋╋╋┗┛╋┗┛`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `${supportbot.General.Name} | [${supportbot.SupportBot_Version}]`, `\u001b[32m`, `Connected to Discord`,);
|
||||||
|
console.log("\u001b[32m", "SupportBot created by Emerald Development ");
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Links] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", "Discord: https://dsc.gg/emerald-dev");
|
||||||
|
console.log("\u001b[32m", "Website: https://emeraldsrv.com");
|
||||||
|
console.log("\u001b[32m", "Community: https://community.emeraldsrv.com");
|
||||||
|
console.log("\u001b[32m", "Documentation: https://docs.emeraldsrv.com");
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Invite] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", `Invite URL: https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=8&scope=bot%20applications.commands`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Config Check] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", "Config initialization...");
|
||||||
|
|
||||||
|
const roles = [
|
||||||
|
supportbot.Roles.StaffMember.Admin,
|
||||||
|
supportbot.Roles.StaffMember.Staff,
|
||||||
|
supportbot.Roles.ModRoles.Blacklisted,
|
||||||
|
supportbot.Roles.ModRoles.Muted
|
||||||
|
];
|
||||||
|
|
||||||
|
if (supportbot.Roles.AutoRole.Role) roles.push(supportbot.Roles.AutoRole.Role);
|
||||||
|
|
||||||
|
const channels = [
|
||||||
|
supportbot.Suggestions.Channel,
|
||||||
|
supportbot.Ticket.Log.TicketLog,
|
||||||
|
supportbot.Ticket.Log.TranscriptLog,
|
||||||
|
supportbot.Ticket.TicketHome,
|
||||||
|
supportbot.Welcome.Channel,
|
||||||
|
supportbot.Leave.Channel,
|
||||||
|
supportbot.Translate.Log
|
||||||
|
];
|
||||||
|
//const categories = [supportbot.TicketCategory];
|
||||||
|
|
||||||
|
if (!channels) {
|
||||||
|
console.log("\u001b[31m", `[MISSING CHANNEL]`, `\u001b[37;1m`, `${channels}`, "\u001b[31m", `channel not found. Please check your config file.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// console.log(`\u001b[32m`, `[CHANNEL LOCATED]`, `\u001b[37;1m`, `${channels}`, `\u001b[32;1m`, `channel has been found.`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const missingC = [];
|
||||||
|
const missingR = [];
|
||||||
|
const missingCat = [];
|
||||||
|
|
||||||
|
for (let r of roles) {
|
||||||
|
const find = await getRole(r, client.guilds.cache.first());
|
||||||
|
if (!find) missingR.push(r);
|
||||||
|
}
|
||||||
|
// for (let cat of categories) {
|
||||||
|
// const find = await getCategory(cat, client.guilds.cache.first());
|
||||||
|
// if (!find) missingCat.push(cat);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const missingRoles = await Promise.all(roles.map(role => getRole(role, client.guilds.cache.first())));
|
||||||
|
const missingChannels = await Promise.all(channels.map(channel => getChannel(channel, client.guilds.cache.first())));
|
||||||
|
|
||||||
|
if (missingRoles.some(role => !role)) {
|
||||||
|
console.log("\u001b[31m", `Missing roles in your server configuration: ${missingRoles.filter(role => !role).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingChannels.some(channel => !channel)) {
|
||||||
|
console.log("\u001b[31m", `Missing channels in your server configuration: ${missingChannels.filter(channel => !channel).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\u001b[32m", "Configs initialized, No problems were detected.");
|
||||||
|
console.log(` `);
|
||||||
|
|
||||||
|
});
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Emerald Services
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,94 +1,96 @@
|
|||||||
<h1 align="center">SupportBot v3.4</h1>
|
<h1 align="center">
|
||||||
<h4 align="center">A Self Hosted discord application</h4>
|
<br>
|
||||||
|
<a href="https://github.com/Emerald-Services/SupportBot"><img src="https://i.imgur.com/cuadAYv.png"></a>
|
||||||
|
<br>
|
||||||
|
SupportBot
|
||||||
|
<br>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<a href="https://opensource.org/licenses/MIT">
|
||||||
|
<img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="shield.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/discordjs">
|
||||||
|
<img src="https://img.shields.io/badge/DISCORD.JS%20-%20v14-blue?style=for-the-badge" alt="shield.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/nodejs/node">
|
||||||
|
<img src="https://img.shields.io/badge/NODE.JS%20-%20v20.x-green?style=for-the-badge" alt="shield.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/Emerald-Services/SupportBot/releases">
|
||||||
|
<img src="https://img.shields.io/github/downloads/Emerald-Services/SupportBot/total?style=for-the-badge" alt="shield.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| SupportBot | Node.JS | Discord.JS | Supported |
|
||||||
|
|------------|---------|------------|------------|
|
||||||
|
| 8.x | 20.x | 14.x. | ✅ Yes
|
||||||
|
| 7.7.3 | 16.x | 13.x. | ✅ Yes
|
||||||
|
| 7.x | 16.x | 13.x. | ❌ No
|
||||||
|
| 6.x | 14.x | 13.x. | ❌ No
|
||||||
|
| 5.x | 12.x | 13.x. | ❌ No
|
||||||
|
| 4.x | 11.x | 13.x. | ❌ No
|
||||||
|
| Older | 10.x | 13.x. | ❌ No
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://discord.gg/hmWgxdF">
|
<a href="https://emeraldsrv.com/">Website</a>
|
||||||
<img src="https://discordapp.com/api/guilds/516345301985132552/widget.png?style=shield" alt="Discord Server">
|
•
|
||||||
</a>
|
<a href="https://github.com/Emerald-Services/SupportBot/wiki">Wiki</a>
|
||||||
<img src="https://img.shields.io/badge/Made%20with-NodeJS-blue.svg" alt="Made with NodeJS">
|
<br>
|
||||||
|
<a href="#about">About</a>
|
||||||
|
•
|
||||||
|
<a href="#support">Support</a>
|
||||||
|
•
|
||||||
|
<a href="#license">License</a>
|
||||||
|
•
|
||||||
|
<a href="https://github.com/Emerald-Services/SupportBot/wiki/Third-Party-Developer">Third-Party</a>
|
||||||
|
•
|
||||||
|
<a href="#contributors">Contributors</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
SupportBot is a free & open source discord bot for your server that has the capability to control & manage your servers support.
|
## About
|
||||||
|
|
||||||
| Version | Supported | Type |
|
SupportBot is an Open-Source discord bot built with [discord.js](https://github.com/discordjs/discord.js). It's primarily focused to help servers organise and manage their support system in a unique way with full customisation to match your brand.
|
||||||
| ------- | ------------------ |--------------------|
|
|
||||||
| 1.0.x | ❌ | None |
|
|
||||||
| 2.0.x | ⚠ | Community |
|
|
||||||
| 3.0.x | ✅ | Priority |
|
|
||||||
| 4.0.x | ❌ | N/A |
|
|
||||||
| Premium | ❌ | N/A |
|
|
||||||
|
|
||||||
# Getting Started
|
## Support
|
||||||
Firstly you will need to download the resource, Once you have downloaded the resource open a new tab in your browser and go to https://discordapp.com/developers/applications/. Create a new application and then open your app and select bot and then create your bot. Copy the bot token and paste it where it says ``"token": "BOT TOKEN HERE",`` in the ``settings.json`` file.
|
|
||||||
|
|
||||||
# Invite the bot
|
<a href="https://emeraldsrv.com/discord">
|
||||||
Head back to discord developers portal where your application is and head into the ``OAuth`` tab and select bot and then below select ``Administrator`` then copy the link and paste into your browser and it should as your to invite the bot to a server.
|
<img alt="Discord" src="https://img.shields.io/discord/597779408295821323?logo=discord&logoColor=white&style=for-the-badge">
|
||||||
|
</a>
|
||||||
|
|
||||||
# Configurating SupportBot
|
|
||||||
Once you have setup your discord application such as invited the bot and added your bot token to the ``settings.json`` we can begin configurating your bot. Firstly open up the ``settings.json`` file and you will see loads of different things to config. You will see the following below:
|
|
||||||
|
|
||||||
```
|
## License
|
||||||
"prefix": "!",
|
|
||||||
"botname": "SupportBot",
|
|
||||||
"colour": "#42f477",
|
|
||||||
"footer": "Support Bot, By Emerald",
|
|
||||||
|
|
||||||
"BotStatus": "Support Bot",.
|
Released under the [MIT](https://opensource.org/licenses/MIT) license.
|
||||||
|
|
||||||
"staff": "Staff",
|
|
||||||
"support": "Support Team",
|
|
||||||
"everyone": "@everyone",
|
|
||||||
|
|
||||||
"category": "Tickets",
|
## Third-Party
|
||||||
"Ticket_Message": "Your support ticket has been opened successfully\nPlease allow us some time to reach out to you.",
|
|
||||||
"Ticket_Logs": "ticket-logs",
|
|
||||||
|
|
||||||
"Announcement_Title": "SupportBot Announcement",
|
- [Official addons repository](https://github.com/Emerald-Services/Addons/)
|
||||||
"Announcement_Channel": "announcements",
|
- [Syphers Addons](https://github.com/SypherRed/SB_Addons_Unofficial)
|
||||||
|
- [BuiltByBit](https://builtbybit.com/supportbot)
|
||||||
|
- [Polymart](https://polymart.org/resource/supportbot-1-discord-ticket-bot.518)
|
||||||
|
|
||||||
"Welcome_Message": "Welcome to the server!",
|
|
||||||
"Welcome_Channel": "welcome",
|
|
||||||
|
|
||||||
"Leave_Message": "Thank you for visiting us!",
|
## Contributors
|
||||||
"Leave_Channel": "welcome",
|
|
||||||
|
|
||||||
"Poll_Channel": "polls",
|
<a href="https://github.com/Emerald-Services/SupportBot/graphs/contributors">
|
||||||
"Poll_Title": "📊 Polls",
|
<img src="https://contrib.rocks/image?repo=Emerald-Services/SupportBot">
|
||||||
"Reaction_Poll_1": "✅",
|
</a>
|
||||||
"Reaction_Poll_2": "❎",
|
|
||||||
|
|
||||||
"Suggestion_Title": "SupportBot Suggestions",
|
## Hosting
|
||||||
"Suggestion_Channel": "suggestions",
|
|
||||||
"suggestyes": "✅",
|
|
||||||
"suggestno": "❎",
|
|
||||||
|
|
||||||
"LINK_1_NAME": "Discord",
|
You can use our [Pterodactyl egg](https://github.com/Emerald-Services/Pterodactyl-Egg) to host it on your own panel. We currently don't offer hosting for you, altough we might add this in the future.
|
||||||
"LINK_2_NAME": "Twitter",
|
If you don't know how to install pterodactyl, you could always host it on replit:
|
||||||
"LINK_3_NAME": "Website",
|
|
||||||
|
|
||||||
"LINK_1": "https://dicord.gg/changemeinconfig",
|
[]([https://repl.it/github/ItsNyoty/iki](https://repl.it/github/Emerald-Services/SupportBot
|
||||||
"LINK_2": "https://twitter.com/changemeinconfig",
|
)
|
||||||
"LINK_3": "https://www.example.com/",
|
|
||||||
|
|
||||||
"LINKS_TITLE": "SupportBot Links",
|
|
||||||
|
|
||||||
"Ticket_Command": "ticket",
|
|
||||||
"Suggest_Command": "suggest",
|
|
||||||
"Say_Command": "say",
|
|
||||||
"Remove_Command": "remove",
|
|
||||||
"Add_Command": "add",
|
|
||||||
"Ping_Command": "ping",
|
|
||||||
"Close_Command": "close",
|
|
||||||
"Forceclose_Command": "forceclose",
|
|
||||||
"Rename_Command": "rename",
|
|
||||||
"Help_Command": "help",
|
|
||||||
"Link_Command": "links",
|
|
||||||
"Lockchat_Command": "lock",
|
|
||||||
"UnLockchat_Command": "unlock",
|
|
||||||
"Poll_Command": "poll"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Contributors List
|
|
||||||
|
|
||||||
# Donators List
|
|
||||||
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 7.7.2 | :white_check_mark: |
|
||||||
|
| 7.7.1 | :white_check_mark: |
|
||||||
|
| < 4.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Use this section to tell people how to report a vulnerability.
|
||||||
|
|
||||||
|
Tell them where to go, how often they can expect to get an update on a
|
||||||
|
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||||
|
declined, etc.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Addon Structure
|
||||||
|
class Command {
|
||||||
|
constructor(options) {
|
||||||
|
this.name = options.name;
|
||||||
|
this.description = options.description;
|
||||||
|
this.permissions = options.permissions;
|
||||||
|
this.options = options.options || [];
|
||||||
|
this.run = options.run;
|
||||||
|
this.defaultPermission = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to dynamically update options
|
||||||
|
setOptions(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
constructor(event, run) {
|
||||||
|
this.event = event;
|
||||||
|
this.run = run;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Command, Event };
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const { GatewayIntentBits, Partials } = require('discord.js');
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const { Command, Event } = require('./Addon.js'); // Adjust the path as needed
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
class Client extends Discord.Client {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
intents: [
|
||||||
|
GatewayIntentBits.Guilds,
|
||||||
|
GatewayIntentBits.GuildMembers,
|
||||||
|
GatewayIntentBits.GuildMessages
|
||||||
|
],
|
||||||
|
partials: [Partials.Channel]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.commands = new Discord.Collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getChannel(channel, guild) {
|
||||||
|
if (!channel) return null; // Add check for undefined channel
|
||||||
|
return guild.channels.cache.find(
|
||||||
|
(c) =>
|
||||||
|
(c.type === Discord.ChannelType.GuildText || c.type === Discord.ChannelType.GuildNews) &&
|
||||||
|
(c.id === channel || (c.name && c.name.toLowerCase() === channel.toLowerCase()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRole(role, guild) {
|
||||||
|
if (!role) return null; // Add check for undefined role
|
||||||
|
return guild.roles.cache.find(
|
||||||
|
(r) => r.id === role || (r.name && r.name.toLowerCase() === role.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCategory(category, guild) {
|
||||||
|
if (!category) return null; // Add check for undefined category
|
||||||
|
return guild.channels.cache.find(
|
||||||
|
(c) =>
|
||||||
|
c.type === Discord.ChannelType.GuildCategory &&
|
||||||
|
(c.id === category || (c.name && c.name.toLowerCase() === category.toLowerCase()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(token) {
|
||||||
|
let tempCommandFiles = fs.readdirSync("./Commands").filter((file) => file.endsWith(".js"));
|
||||||
|
|
||||||
|
if (cmdconfig.Suggestion.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "suggest.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Help.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "help.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Info.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "info.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.OpenTicket.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "ticket.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.CloseTicket.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "close.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Embed.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "embed.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Translate.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "translate.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.UserInfo.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "userinfo.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Ping.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.AddUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "addUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.RemoveUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "removeUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.ForceAddUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "forceaddUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Profile.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "profile.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Settings.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "settings.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandFiles = tempCommandFiles;
|
||||||
|
const commands = commandFiles.map((file) => require(`../Commands/${file}`));
|
||||||
|
|
||||||
|
// Load main commands
|
||||||
|
console.log(`\u001b[33m`, "――――――――――――――――――――――――――――――――――――――――――――");
|
||||||
|
|
||||||
|
commands.forEach((cmd) => {
|
||||||
|
console.log(`\u001b[32m`, `[CMD]`, `\u001b[37;1m`, `${cmd.name}`, `\u001b[32;1m`, "Loaded");
|
||||||
|
this.commands.set(cmd.name, cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load addon commands and events
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
if (supportbot.General.Addons.Enabled) {
|
||||||
|
const addonFiles = fs.readdirSync("./Addons").filter((file) => file.endsWith(".js"));
|
||||||
|
|
||||||
|
const addons = addonFiles.map((file) => {
|
||||||
|
const addon = require(`../Addons/${file}`);
|
||||||
|
addon.name = file.split(".")[0];
|
||||||
|
return addon;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Addons
|
||||||
|
console.log(" ");
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
addons.forEach((addon) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[32m`,
|
||||||
|
`[ADDON]`,
|
||||||
|
`\u001b[37;1m`,
|
||||||
|
`${addon.name}`,
|
||||||
|
`\u001b[32;1m`,
|
||||||
|
"Loaded"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (addon instanceof Command) {
|
||||||
|
this.commands.set(addon.name, addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addon.events && Array.isArray(addon.events)) {
|
||||||
|
addon.events.forEach((event) => {
|
||||||
|
if (event instanceof Event) {
|
||||||
|
this.on(event.event, (...args) => event.run(this, ...args));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register Slash Commands
|
||||||
|
|
||||||
|
this.once("ready", async () => {
|
||||||
|
await this.guilds.cache.first()?.commands.set(this.commands);
|
||||||
|
console.log(
|
||||||
|
"\u001b[32m",
|
||||||
|
`[SUCCESS]`,
|
||||||
|
`\u001b[37;1m`,
|
||||||
|
`Slash Commands Registered for ${this.guilds.cache.first().name}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(" ");
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
fs.readdirSync("./Events").filter((file) => file.endsWith(".js")).forEach((file) => {
|
||||||
|
const event = require(`../Events/${file}`);
|
||||||
|
console.log(`\u001b[32m`, `[EVENT]`, `\u001b[37;1m`, `${event.event}`, `\u001b[32;1m`, "Loaded");
|
||||||
|
this.on(event.event, (...args) => event.run(this, ...args));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||||
|
if (process.argv[2] !== "test") {
|
||||||
|
await this.login(token);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31;1m`,
|
||||||
|
"RUNNING IN TEST MODE, IF NOT INTENDED, PLEASE USE npm start"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Client;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Command Structure
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
constructor(options) {
|
||||||
|
this.name = options.name;
|
||||||
|
this.description = options.description;
|
||||||
|
this.permissions = options.permissions || [];
|
||||||
|
this.options = options.options || [];
|
||||||
|
this.run = options.run;
|
||||||
|
this.defaultPermission = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = Command;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Event Structure
|
||||||
|
class Event {
|
||||||
|
constructor(event, run) {
|
||||||
|
this.event = event;
|
||||||
|
this.run = run;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Event;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ticket ID Structure
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
class TicketNumberID {
|
||||||
|
static async pad() {
|
||||||
|
let num = await this.get();
|
||||||
|
let n = num + "";
|
||||||
|
await this.set(num + 1);
|
||||||
|
return n.length >= 4 ? n : new Array(4 - n.length + 1).join("0") + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async get() {
|
||||||
|
let ticketnumberID = await JSON.parse(
|
||||||
|
fs.readFileSync("./Data/ticket-panel-id.json", "utf8")
|
||||||
|
);
|
||||||
|
if (!ticketnumberID.id) {
|
||||||
|
return this.set(0);
|
||||||
|
} else {
|
||||||
|
return ticketnumberID.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async set(value) {
|
||||||
|
let ticketnumberID = await JSON.parse(
|
||||||
|
fs.readFileSync("./Data/ticket-panel-id.json", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
ticketnumberID.id = value;
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/ticket-panel-id.json",
|
||||||
|
JSON.stringify(ticketnumberID, null, 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async reset() {
|
||||||
|
return await this.set(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TicketNumberID;
|
||||||
@@ -1 +0,0 @@
|
|||||||
theme: jekyll-theme-cayman
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Add User
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
module.exports.run = async (bot, message, args) => {
|
|
||||||
message.delete()
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Add_Command}`)
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === bot.settings.support)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply({embed: rolemissing});
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply({embed: donothaverole});
|
|
||||||
|
|
||||||
const outsideticket = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot use this command becase you are outside a ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.channel.name.startsWith(`ticket-`)) return message.channel.send({embed: outsideticket});
|
|
||||||
|
|
||||||
let rUser = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
|
|
||||||
|
|
||||||
const cantfinduser = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Hmm! Does that user exist? I cannot find the user.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if(!rUser) return message.channel.send({embed: cantfinduser});
|
|
||||||
|
|
||||||
const channel = message.guild.channels.find(channel => channel.name === message.channel.name);
|
|
||||||
|
|
||||||
const cantfindchannel = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Hmm! Does that ticket exist? I cannot find the ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if(!channel) return message.channel.send({embed: cantfindchannel});
|
|
||||||
message.delete().catch(O_o=>{});
|
|
||||||
|
|
||||||
message.channel.overwritePermissions(rUser, { READ_MESSAGES: true, SEND_MESSAGES: true });
|
|
||||||
|
|
||||||
const useradded = new Discord.RichEmbed()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setDescription(`:white_check_mark: Successfully Added ${rUser} to the ticket.`)
|
|
||||||
.setTimestamp();
|
|
||||||
|
|
||||||
message.channel.send({embed: useradded});
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has successfully added ${rUser} to ${message.channel}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Add_Command,
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Close Ticket
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
const outsideticket = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot use this command becase you are outside a ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.channel.name.startsWith(`ticket-`)) return message.channel.send({embed: outsideticket});
|
|
||||||
const close1 = new Discord.RichEmbed()
|
|
||||||
.setDescription(`Looks like you have come to the end of your support ticket\nPlease confirm that you want to close your ticket by saying ||**confirm**||`)
|
|
||||||
.setFooter("Your request will be avoided in 20 seconds")
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
message.channel.send({embed: close1}).then(m => {
|
|
||||||
message.channel.awaitMessages(response => response.content === `confirm`, {
|
|
||||||
max: 1,
|
|
||||||
time: 10000,
|
|
||||||
errors: ['time'],
|
|
||||||
|
|
||||||
}).then((collected) => {
|
|
||||||
message.channel.delete();
|
|
||||||
|
|
||||||
}).catch(() => {
|
|
||||||
m.edit('Close ticket request, timedout').then(m2 => {
|
|
||||||
m2.delete();
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Close_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Close_Command,
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Forceclose Ticket
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.support}`)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply({embed: rolemissing});
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply({embed: donothaverole});
|
|
||||||
|
|
||||||
const outsideticket = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot use this command becase you are outside a ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.channel.name.startsWith(`ticket-`)) return message.channel.send({embed: outsideticket});
|
|
||||||
message.channel.delete();
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Forceclose_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Forceclose_Command,
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Help
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let userCommands = "";
|
|
||||||
userCommands += `**${bot.settings.prefix}${bot.settings.Link_Command}**: Get some important links!\n`;
|
|
||||||
userCommands += `**${bot.settings.prefix}${bot.settings.Ping_Command}**: Check the bots ping. Pong!\n`;
|
|
||||||
userCommands += `**${bot.settings.prefix}${bot.settings.Ticket_Command} <reason>**: Create a support ticket\n`;
|
|
||||||
userCommands += `**${bot.settings.prefix}${bot.settings.Close_Command}**: Close your support ticket\n`;
|
|
||||||
userCommands += `**${bot.settings.prefix}${bot.settings.Suggest_Command} <suggestion>**: Create a server suggestion\n`;
|
|
||||||
|
|
||||||
let supportCommands = "";
|
|
||||||
supportCommands += `**${bot.settings.prefix}${bot.settings.Add_Command} <user>**: Adds a user to a ticket\n`;
|
|
||||||
supportCommands += `**${bot.settings.prefix}${bot.settings.Remove_Command} <user>**: Removes a user from a ticket\n`;
|
|
||||||
supportCommands += `**${bot.settings.prefix}${bot.settings.Forceclose_Command}**: Forceclose a support ticket\n`;
|
|
||||||
supportCommands += `**${bot.settings.prefix}${bot.settings.Rename_Command}**: Rename a support ticket\n`;
|
|
||||||
|
|
||||||
let staffCommands = "";
|
|
||||||
staffCommands += `**${bot.settings.prefix}${bot.settings.Say_Command} <message>**: Create a bot announcement\n`;
|
|
||||||
staffCommands += `**${bot.settings.prefix}${bot.settings.Lockchat_Command}**: Lock the chat channel\n`;
|
|
||||||
staffCommands += `**${bot.settings.prefix}${bot.settings.UnLockchat_Command}**: UnLock the chat channel\n`;
|
|
||||||
|
|
||||||
const embed = new Discord.RichEmbed()
|
|
||||||
.setTitle(bot.settings.botname)
|
|
||||||
.addField(":ticket: Support Commands", userCommands)
|
|
||||||
.addField(":pushpin: Support Commands", supportCommands, true)
|
|
||||||
.addField(":pushpin: Staff Commands", staffCommands, true)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer, message.author.displayAvatarURL);
|
|
||||||
|
|
||||||
message.channel.send(embed)
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Help_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Help_Command,
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Help
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let BotLinks = "";
|
|
||||||
BotLinks += `[${bot.settings.LINK_1_NAME}](${bot.settings.LINK_1})\n`;
|
|
||||||
BotLinks += `[${bot.settings.LINK_2_NAME}](${bot.settings.LINK_2})\n`;
|
|
||||||
BotLinks += `[${bot.settings.LINK_3_NAME}](${bot.settings.LINK_3})\n`;
|
|
||||||
|
|
||||||
const links = new Discord.RichEmbed()
|
|
||||||
.setTitle(`${bot.settings.LINKS_TITLE}`)
|
|
||||||
.setDescription(BotLinks)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer)
|
|
||||||
message.channel.send(links)
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Link_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Link_Command,
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Lockchat
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = async(bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.staff}`)
|
|
||||||
let everyoneRole = message.guild.roles.find(everyone => everyone.name === `${bot.settings.everyone}`)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply(rolemissing).catch(err=>{console.error(err)})
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply(donothaverole)
|
|
||||||
|
|
||||||
message.channel.overwritePermissions(everyoneRole, { READ_MESSAGES: false, SEND_MESSAGES: false });
|
|
||||||
|
|
||||||
const lockmsg = new Discord.RichEmbed()
|
|
||||||
.setDescription(":white_check_mark: **Chat Locked**")
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
message.channel.send(lockmsg)
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Lockchat_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Lockchat_Command,
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Ping
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
const embed = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:ping_pong: **Pong!** \`${bot.ping}ms\` `)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
message.channel.send(embed).catch(console.error);
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Ping_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Ping_Command,
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Poll
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.staff}`)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply(rolemissing).catch(err=>{console.error(err)})
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply(donothaverole)
|
|
||||||
|
|
||||||
const embed = new Discord.RichEmbed()
|
|
||||||
.setTitle(`${bot.settings.Poll_Title}`)
|
|
||||||
.setDescription(args.join(" "))
|
|
||||||
.setTimestamp()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer, message.author.displayAvatarURL)
|
|
||||||
|
|
||||||
let ac = message.guild.channels.find(AnnounceChannel => AnnounceChannel.name === `${bot.settings.Poll_Channel}`)
|
|
||||||
if(!ac) return message.channel.send(`:x: Error! Could not find the logs channel **${bot.settings.Poll_Channel}**`)
|
|
||||||
|
|
||||||
ac.send(embed)
|
|
||||||
|
|
||||||
.then(async function(msg) {
|
|
||||||
msg.react(bot.settings.Reaction_Poll_1).then(() => msg.react(bot.settings.Reaction_Poll_2));
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Poll_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Poll_Command,
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Remove User
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
module.exports.run = async (bot, message, args) => {
|
|
||||||
message.delete()
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Add_Command}`)
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === bot.settings.support)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply({embed: rolemissing});
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply({embed: donothaverole});
|
|
||||||
|
|
||||||
const outsideticket = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot use this command becase you are outside a ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.channel.name.startsWith(`ticket-`)) return message.channel.send({embed: outsideticket});
|
|
||||||
|
|
||||||
let rUser = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
|
|
||||||
|
|
||||||
const cantfinduser = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Hmm! Does that user exist? I cannot find the user.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if(!rUser) return message.channel.send({embed: cantfinduser});
|
|
||||||
|
|
||||||
const channel = message.guild.channels.find(channel => channel.name === message.channel.name);
|
|
||||||
|
|
||||||
const cantfindchannel = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Hmm! Does that ticket exist? I cannot find the ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if(!channel) return message.channel.send({embed: cantfindchannel});
|
|
||||||
message.delete().catch(O_o=>{});
|
|
||||||
|
|
||||||
message.channel.overwritePermissions(rUser, { READ_MESSAGES: false, SEND_MESSAGES: false });
|
|
||||||
|
|
||||||
const useradded = new Discord.RichEmbed()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setDescription(`:white_check_mark: Successfully remove ${rUser} from the ticket.`)
|
|
||||||
.setTimestamp();
|
|
||||||
|
|
||||||
message.channel.send({embed: useradded});
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has successfully removed ${rUser} from ${message.channel}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Remove_Command,
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Close Ticket
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === bot.settings.support)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply({embed: rolemissing});
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.support}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply({embed: donothaverole});
|
|
||||||
|
|
||||||
const outsideticket = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot use this command becase you are outside a ticket channel.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.channel.name.startsWith(`ticket-`)) return message.channel.send({embed: outsideticket});
|
|
||||||
const renameto = args.join(" ")
|
|
||||||
message.channel.setName(`ticket-${renameto}-${message.author.username}`)
|
|
||||||
|
|
||||||
// Renamed Ticket Logistic
|
|
||||||
const logEmbed = new Discord.RichEmbed()
|
|
||||||
.setTitle(":ticket: Ticket Renamed")
|
|
||||||
.setDescription(`<@${message.author.id}> has renamed a ticket to ${renameto}`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer)
|
|
||||||
|
|
||||||
let logChannel = message.guild.channels.find(TicketChannel => TicketChannel.name === `${bot.settings.Ticket_Logs}`);
|
|
||||||
if(!logChannel) return message.channel.send(`:x: Error! Could not find the logs channel **${bot.settings.Ticket_Logs}**`);
|
|
||||||
|
|
||||||
logChannel.send({embed: logEmbed})
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Rename_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Rename_Command,
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Report
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.staff}`);
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour);
|
|
||||||
|
|
||||||
if(!staffGroup) {
|
|
||||||
message.reply(rolemissing).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if(!message.member.roles.has(staffGroup.id)) {
|
|
||||||
message.reply(donothaverole);
|
|
||||||
} else {
|
|
||||||
if(!args[0]) {
|
|
||||||
message.reply(":x: Sorry! Please specify the user to report.");
|
|
||||||
} else {
|
|
||||||
if(!args[1]) {
|
|
||||||
message.reply(":x: Sorry! Specify the reason of your report.");
|
|
||||||
} else {
|
|
||||||
let reportDesc = args.slice(1).join(" ");
|
|
||||||
const embed = new Discord.RichEmbed()
|
|
||||||
.setTitle(`${bot.settings.Report_Title}`)
|
|
||||||
.setThumbnail(message.author.avatarURL)
|
|
||||||
.addField("Report by:", `<@${message.author.id}>`, false)
|
|
||||||
.addField("Description:", `${reportDesc}`, false)
|
|
||||||
.addField("Reported User:", `${args[0]}`, false)
|
|
||||||
.setTimestamp(new Date())
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(`${message.author.username}#${message.author.discriminator}`, message.author.displayAvatarURL);
|
|
||||||
let rc = message.guild.channels.find(ReportChannel => ReportChannel.name === `${bot.settings.Report_Channel}`)
|
|
||||||
if(!rc) {
|
|
||||||
message.channel.send(`:x: Error! Could not find the logs channel **${bot.settings.Report_Channel}**`);
|
|
||||||
} else {
|
|
||||||
rc.send(embed);
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Report_Command}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Report_Command
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Say
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = (bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.staff}`)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply(rolemissing).catch(err=>{console.error(err)})
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply(donothaverole)
|
|
||||||
|
|
||||||
const embed = new Discord.RichEmbed()
|
|
||||||
.setTitle(`${bot.settings.Announcement_Title}`)
|
|
||||||
.setDescription(args.join(" "))
|
|
||||||
.setTimestamp()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(`${message.author.username}#${message.author.discriminator}`, message.author.displayAvatarURL)
|
|
||||||
|
|
||||||
let ac = message.guild.channels.find(AnnounceChannel => AnnounceChannel.name === `${bot.settings.Announcement_Channel}`)
|
|
||||||
if(!ac) return message.channel.send(`:x: Error! Could not find the logs channel **${bot.settings.Announcement_Channel}**`)
|
|
||||||
|
|
||||||
ac.send(embed)
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Say_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Say_Command,
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Suggest
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = async(bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
const SuggestionEmbed = new Discord.RichEmbed()
|
|
||||||
.setTitle(`${bot.settings.Suggestion_Title}`)
|
|
||||||
.setDescription(args.join(" "))
|
|
||||||
.setFooter(`Suggestion by ${message.author.username}`, message.author.displayAvatarURL)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
|
|
||||||
let sc = message.guild.channels.find(SuggestionChannel => SuggestionChannel.name === `${bot.settings.Suggestion_Channel}`);
|
|
||||||
if(!sc) return message.channel.send(`:x: Error! Could not find the suggestion channel **${bot.settings.Suggestion_Channel}**`);
|
|
||||||
|
|
||||||
sc.send(SuggestionEmbed)
|
|
||||||
|
|
||||||
.then(async function(msg) {
|
|
||||||
msg.react(bot.settings.suggestyes).then(() => msg.react(bot.settings.suggestno));
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Suggest_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Suggest_Command,
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Ticket
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = async(bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
const ID = Math.floor(Math.random() * 10) + 2000;
|
|
||||||
const subject = args.join(" ") || "No Subject.";
|
|
||||||
|
|
||||||
const alreadyopen = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Cannot create a ticket because **ticket-${message.author.username}** already exists.`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (message.guild.channels.find(TicketChannel => TicketChannel.name === 'ticket-' + message.author.username)) return message.channel.send(alreadyopen);
|
|
||||||
message.guild.createChannel(`ticket-${message.author.username}`, 'text').then(TicketChannel => {
|
|
||||||
|
|
||||||
// Roles
|
|
||||||
let staff = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.support}`)
|
|
||||||
let everyone = message.guild.roles.find(everyoneRole => everyoneRole.name === `@everyone`)
|
|
||||||
|
|
||||||
// Permissions
|
|
||||||
TicketChannel.overwritePermissions(everyone, { SEND_MESSAGES: false, READ_MESSAGES: false })
|
|
||||||
TicketChannel.overwritePermissions(staff, { SEND_MESSAGES: true, READ_MESSAGES: true })
|
|
||||||
TicketChannel.overwritePermissions(message.author, { SEND_MESSAGES: true, READ_MESSAGES: true })
|
|
||||||
TicketChannel.overwritePermissions(bot.user, { SEND_MESSAGES: true, READ_MESSAGES: true })
|
|
||||||
|
|
||||||
// Category
|
|
||||||
let category = message.guild.channels.find(c => c.name === bot.settings.category);
|
|
||||||
if (category) {
|
|
||||||
TicketChannel.setParent(category.id);
|
|
||||||
} else {
|
|
||||||
if (message.guild.channels.get(bot.settings.category)) {
|
|
||||||
TicketChannel.setParent(message.guild.channels.get(bot.settings.category).id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ticketopened = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:white_check_mark: <@${message.author.id}> You ticket has been created <#${TicketChannel.id}>`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
message.channel.send({embed: ticketopened});
|
|
||||||
|
|
||||||
// Ticket Message - ( Able to edit this message via the settings.json file )
|
|
||||||
const ticketMessage = `Hi! <@${message.author.id}>\n${bot.settings.Ticket_Message}`;
|
|
||||||
|
|
||||||
const TicketMessage = new Discord.RichEmbed()
|
|
||||||
.setDescription(ticketMessage)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer)
|
|
||||||
TicketChannel.send({embed: TicketMessage});
|
|
||||||
|
|
||||||
if (subject != 'No Subject.') {
|
|
||||||
TicketChannel.setTopic(subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ticket Logging
|
|
||||||
const logEmbed = new Discord.RichEmbed()
|
|
||||||
.setTitle(":ticket: Logistics of your Ticket")
|
|
||||||
.addField("Ticket ID", ID, true)
|
|
||||||
.addField("User", `<@${message.author.id}>`, true)
|
|
||||||
.addField("Channel", `ticket#${ID}`, true)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setFooter(bot.settings.footer)
|
|
||||||
|
|
||||||
if (subject != 'No Subject.') {
|
|
||||||
logEmbed.addField('Subject', subject, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let logChannel = message.guild.channels.find(TicketChannel => TicketChannel.name === `${bot.settings.Ticket_Logs}`);
|
|
||||||
if(!logChannel) return message.channel.send(`:x: Error! Could not find the logs channel **${bot.settings.Ticket_Logs}**`);
|
|
||||||
|
|
||||||
logChannel.send({embed: logEmbed})
|
|
||||||
|
|
||||||
}).catch(err=>{console.error(err)});
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.Ticket_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.Ticket_Command,
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// SupportBot
|
|
||||||
// Command: Lockchat
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = async(bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
let staffGroup = message.guild.roles.find(staffRole => staffRole.name === `${bot.settings.staff}`)
|
|
||||||
let everyoneRole = message.guild.roles.find(everyone => everyone.name === `${bot.settings.everyone}`)
|
|
||||||
|
|
||||||
const rolemissing = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Looks like this server doesn't have the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!staffGroup) return message.reply(rolemissing).catch(err=>{console.error(err)})
|
|
||||||
|
|
||||||
const donothaverole = new Discord.RichEmbed()
|
|
||||||
.setDescription(`:x: Sorry! You cannot use this command with the role **${bot.settings.staff}**`)
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
if (!message.member.roles.has(staffGroup.id)) return message.reply(donothaverole)
|
|
||||||
|
|
||||||
message.channel.overwritePermissions(everyoneRole, { READ_MESSAGES: true, SEND_MESSAGES: true });
|
|
||||||
|
|
||||||
const lockmsg = new Discord.RichEmbed()
|
|
||||||
.setDescription(":white_check_mark: **Chat Un-Locked**")
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
message.channel.send(lockmsg)
|
|
||||||
|
|
||||||
console.log(`\x1b[36m`, `${message.author} has executed ${bot.settings.prefix}${bot.settings.UnLockchat_Command}`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: bot.settings.UnLockchat_Command,
|
|
||||||
}
|
|
||||||
@@ -1,102 +1,44 @@
|
|||||||
// Resource: SupportBot
|
// ___ _ ___ _
|
||||||
// Developed by Emerald
|
// / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
// Version: 3.4
|
// \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
// <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
// |_| |_|
|
||||||
|
//
|
||||||
|
// SupportBot created by Emerald Services
|
||||||
|
// Installed with MIT License
|
||||||
|
//
|
||||||
|
// Discord Support: https://emeraldsrv.dev/discord
|
||||||
|
// Community Resources: https://emeraldsrv.dev/resources
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const bot = new Discord.Client();
|
|
||||||
|
|
||||||
bot.commands = new Discord.Collection();
|
const yaml = require("js-yaml");
|
||||||
bot.settings = require("./settings.json");
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
fs.readdir("./commands/", (err, files) => {
|
const Client = require("./Structures/Client.js");
|
||||||
if(err) console.log(err);
|
const client = new Client({
|
||||||
|
intents: ['Guilds', 'GuildMembers', 'GuildMessages']
|
||||||
let jsfile = files.filter(f => f.split(".").pop() === "js")
|
|
||||||
if(jsfile.length <= 0) return console.log(`${bot.settings.botname} No commands found. Try to Re-download the resource`);
|
|
||||||
|
|
||||||
jsfile.forEach((f, i) =>{
|
|
||||||
let props = require(`./commands/${f}`);
|
|
||||||
console.log(`[${bot.settings.botname}] > Command Loaded > ${f}`);
|
|
||||||
bot.commands.set(props.help.name, props);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
client.start(supportbot.General.Token);
|
||||||
|
|
||||||
bot.addons = new Discord.Collection();
|
|
||||||
|
|
||||||
fs.readdir("./sb-addons/", (err, files) => {
|
|
||||||
if(err) console.log(err);
|
|
||||||
|
|
||||||
let jsfile = files.filter(f => f.split(".").pop() === "js")
|
|
||||||
if(jsfile.length <= 0) return console.log(`${bot.settings.botname} No addons detected nor default! Either download addons from https://itzemerald.tk/`);
|
|
||||||
|
|
||||||
jsfile.forEach((f, i) =>{
|
|
||||||
let props = require(`./sb-addons/${f}`);
|
|
||||||
console.log(`[${bot.settings.botname}] > Addons Loaded > ${f}`);
|
|
||||||
bot.addons.set(props.help.name, props);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.on("ready", async () => {
|
|
||||||
bot.user.setActivity(bot.settings.BotStatus, {type:"PLAYING"});
|
|
||||||
console.log(`\x1b[36m`, `=== [SupportBot] ===\n\nSupportBot - Created by Emerald Services\nInvite ${bot.user.username} to your server\nhttps://discordapp.com/api/oauth2/authorize?client_id=${bot.user.username}&permissions=8&scope=bot\n\n=== [SupportBot] ===`)
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.on("message", async message => {
|
|
||||||
if(message.author.bot) return;
|
|
||||||
if(message.channel.type === "dm") return;
|
|
||||||
if (message.content.indexOf(bot.settings.prefix) !== 0) return;
|
|
||||||
|
|
||||||
let messageArray = message.content.split(" ");
|
|
||||||
const args = message.content.slice(bot.settings.prefix.length).trim().split(/ +/g);
|
|
||||||
const command = args.shift().toLowerCase();
|
|
||||||
|
|
||||||
const cmd = bot.commands.get(command);
|
|
||||||
if(!cmd) return;
|
|
||||||
cmd.run(bot, message, args);
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.on("message", async message => {
|
|
||||||
if(message.author.bot) return;
|
|
||||||
if(message.channel.type === "dm") return;
|
|
||||||
if (message.content.indexOf(bot.settings.prefix) !== 0) return;
|
|
||||||
|
|
||||||
let messageArray = message.content.split(" ");
|
|
||||||
const args = message.content.slice(bot.settings.prefix.length).trim().split(/ +/g);
|
|
||||||
const addon = args.shift().toLowerCase();
|
|
||||||
|
|
||||||
const cmd = bot.addons.get(addon);
|
|
||||||
if(!cmd) return;
|
|
||||||
cmd.run(bot, message, args);
|
|
||||||
});
|
|
||||||
|
|
||||||
// [SupportBot] Welcome Message
|
|
||||||
|
|
||||||
bot.on("guildMemberAdd", (member) => {
|
|
||||||
let channel = member.guild.channels.find(channel => channel.name === `${bot.settings.Welcome_Channel}`)
|
|
||||||
|
|
||||||
const WelcomeMsg= new Discord.RichEmbed()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setThumbnail(member.user.avatarURL)
|
|
||||||
.setDescription(`:wave: ${member.user.username}\n${bot.settings.Welcome_Message}`)
|
|
||||||
|
|
||||||
channel.send(WelcomeMsg);
|
|
||||||
});
|
|
||||||
|
|
||||||
// [SupportBot] Leave Message
|
|
||||||
|
|
||||||
bot.on("guildMemberRemove", (member) => {
|
|
||||||
let channel = member.guild.channels.find(channel => channel.name === `${bot.settings.Leave_Channel}`)
|
|
||||||
|
|
||||||
const LeaveMsg= new Discord.RichEmbed()
|
|
||||||
.setColor(bot.settings.colour)
|
|
||||||
.setThumbnail(member.user.avatarURL)
|
|
||||||
.setDescription(`:wave: ${member.user.username}\n${bot.settings.Leave_Message}`)
|
|
||||||
|
|
||||||
channel.send(LeaveMsg);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.login(bot.settings.token);
|
|
||||||
Generated
+1671
File diff suppressed because it is too large.
Load diff
+25
-11
@@ -1,18 +1,32 @@
|
|||||||
{
|
{
|
||||||
"name": "supportbot",
|
"name": "supportbot",
|
||||||
"version": "3.4",
|
"version": "8.0.1",
|
||||||
"description": "SupportBot",
|
"description": "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
|
||||||
"discord.js": "^11.4.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "!help"
|
"setup": "npm i && node index.js",
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/Emerald-Services/SupportBot.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
|
||||||
"SupportBot"
|
|
||||||
],
|
|
||||||
"author": "Emerald Services",
|
"author": "Emerald Services",
|
||||||
"homepage": "https://discord.gg/hmWgxdF"
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/Emerald-Services/SupportBot/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/Emerald-Services/SupportBot#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"@paypal/checkout-server-sdk": "^1.0.3",
|
||||||
|
"@vitalets/google-translate-api": "^8.0.0",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"chatgpt": "^5.2.5",
|
||||||
|
"discord.js": "^14.13.0",
|
||||||
|
"js": "^0.1.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"moment": "^2.29.3",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"openai": "^4.50.0",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// SupportBot Addons
|
|
||||||
// Default Addon
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
bot.settings = require("../settings.json");
|
|
||||||
|
|
||||||
exports.run = async(bot, message, args) => {
|
|
||||||
message.delete();
|
|
||||||
|
|
||||||
message.channel.send(":white_check_mark: **SupportBot Addon**\nThis addon is here by default.\nWe are currently working on some super amazing addons for SupportBot\nHowever, If you would like to start creating your own support bot addon\ncontact us at EmeraldServices.\n")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.help = {
|
|
||||||
name: 'addon',
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
{
|
|
||||||
|
|
||||||
"SupportBot": "v3.4 / Download addons @ https://itzemerald.tk/",
|
|
||||||
|
|
||||||
"token": "TOKEN",
|
|
||||||
"prefix": "!",
|
|
||||||
"botname": "SupportBot",
|
|
||||||
"colour": "#42f477",
|
|
||||||
"footer": "Support Bot, By Emerald",
|
|
||||||
|
|
||||||
"BotStatus": "Support Bot",
|
|
||||||
|
|
||||||
"staff": "Staff",
|
|
||||||
"support": "Support",
|
|
||||||
"everyone": "@everyone",
|
|
||||||
|
|
||||||
"category": "Tickets",
|
|
||||||
"Ticket_Message": "Your support ticket has been opened successfully\nPlease allow us some time to reach out to you.",
|
|
||||||
"Ticket_Logs": "ticket-logs",
|
|
||||||
|
|
||||||
"Announcement_Title": "SupportBot Announcement",
|
|
||||||
"Announcement_Channel": "announcements",
|
|
||||||
|
|
||||||
"Welcome_Message": "Welcome to the server!",
|
|
||||||
"Welcome_Channel": "welcome",
|
|
||||||
|
|
||||||
"Leave_Message": "Thank you for visiting us!",
|
|
||||||
"Leave_Channel": "welcome",
|
|
||||||
|
|
||||||
"Poll_Channel": "polls",
|
|
||||||
"Poll_Title": "📊 Polls",
|
|
||||||
"Reaction_Poll_1": "✅",
|
|
||||||
"Reaction_Poll_2": "❎",
|
|
||||||
|
|
||||||
"Suggestion_Title": "SupportBot Suggestions",
|
|
||||||
"Suggestion_Channel": "suggestions",
|
|
||||||
"suggestyes": "✅",
|
|
||||||
"suggestno": "❎",
|
|
||||||
|
|
||||||
"Report_Channel": "reports",
|
|
||||||
"Report_Title": "SupportBot Report",
|
|
||||||
|
|
||||||
"LINK_1_NAME": "Discord",
|
|
||||||
"LINK_2_NAME": "Twitter",
|
|
||||||
"LINK_3_NAME": "Website",
|
|
||||||
|
|
||||||
"LINK_1": "https://dicord.gg/changemeinconfig",
|
|
||||||
"LINK_2": "https://twitter.com/changemeinconfig",
|
|
||||||
"LINK_3": "https://www.example.com/",
|
|
||||||
|
|
||||||
"LINKS_TITLE": "SupportBot Links",
|
|
||||||
|
|
||||||
"Ticket_Command": "ticket",
|
|
||||||
"Suggest_Command": "suggest",
|
|
||||||
"Say_Command": "say",
|
|
||||||
"Remove_Command": "remove",
|
|
||||||
"Add_Command": "add",
|
|
||||||
"Ping_Command": "ping",
|
|
||||||
"Close_Command": "close",
|
|
||||||
"Forceclose_Command": "forceclose",
|
|
||||||
"Rename_Command": "rename",
|
|
||||||
"Help_Command": "help",
|
|
||||||
"Link_Command": "links",
|
|
||||||
"Lockchat_Command": "lock",
|
|
||||||
"UnLockchat_Command": "unlock",
|
|
||||||
"Poll_Command": "poll",
|
|
||||||
"Report_Command": "report"
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user