forked from Skynet/discord-bot
Merge branch 'main' into #17-automate-onboarding-mk-ii
# Conflicts: # Cargo.lock # src/commands/link_email.rs # src/lib.rs
This commit is contained in:
commit
c79113921d
15 changed files with 1013 additions and 141 deletions
|
@ -19,6 +19,10 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
# get the repo first
|
# get the repo first
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v4
|
- uses: https://code.forgejo.org/actions/checkout@v4
|
||||||
|
- uses: https://forgejo.skynet.ie/Skynet/actions/get_lfs@v3
|
||||||
|
with:
|
||||||
|
repository: ${{ gitea.repository }}
|
||||||
|
ref_name: ${{ gitea.ref_name }}
|
||||||
- run: nix build .#fmt --verbose
|
- run: nix build .#fmt --verbose
|
||||||
|
|
||||||
# clippy is incredibly useful for making yer code better
|
# clippy is incredibly useful for making yer code better
|
||||||
|
@ -30,6 +34,10 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
# get the repo first
|
# get the repo first
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v4
|
- uses: https://code.forgejo.org/actions/checkout@v4
|
||||||
|
- uses: https://forgejo.skynet.ie/Skynet/actions/get_lfs@v3
|
||||||
|
with:
|
||||||
|
repository: ${{ gitea.repository }}
|
||||||
|
ref_name: ${{ gitea.ref_name }}
|
||||||
- run: nix build .#clippy --verbose
|
- run: nix build .#clippy --verbose
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
@ -39,6 +47,10 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
# get the repo first
|
# get the repo first
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v4
|
- uses: https://code.forgejo.org/actions/checkout@v4
|
||||||
|
- uses: https://forgejo.skynet.ie/Skynet/actions/get_lfs@v3
|
||||||
|
with:
|
||||||
|
repository: ${{ gitea.repository }}
|
||||||
|
ref_name: ${{ gitea.ref_name }}
|
||||||
- name: "Build it locally"
|
- name: "Build it locally"
|
||||||
run: nix build --verbose
|
run: nix build --verbose
|
||||||
|
|
||||||
|
@ -49,7 +61,7 @@ jobs:
|
||||||
needs: [ build ]
|
needs: [ build ]
|
||||||
steps:
|
steps:
|
||||||
- name: "Deploy to Skynet"
|
- name: "Deploy to Skynet"
|
||||||
uses: https://forgejo.skynet.ie/Skynet/actions-deploy-to-skynet@v2
|
uses: https://forgejo.skynet.ie/Skynet/actions/deploy@v3
|
||||||
with:
|
with:
|
||||||
input: 'skynet_discord_bot'
|
input: 'skynet_discord_bot'
|
||||||
token: ${{ secrets.API_TOKEN_FORGEJO }}
|
token: ${{ secrets.API_TOKEN_FORGEJO }}
|
37
.gitattributes
vendored
Normal file
37
.gitattributes
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Git config here
|
||||||
|
* text eol=lf
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Git lfs stuff
|
||||||
|
# Documents
|
||||||
|
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.doc filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.docx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Excel
|
||||||
|
*.xls filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.xlsx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.xlsm filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Powerpoints
|
||||||
|
*.ppt filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pptx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ppsx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Images
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Video
|
||||||
|
*.mkv filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wmv filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Misc
|
||||||
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# ET4011
|
||||||
|
*.cbe filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pbs filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# Open/Libre office
|
||||||
|
# from https://www.libreoffice.org/discover/what-is-opendocument/
|
||||||
|
*.odt filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ods filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.odp filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.odg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
# QT
|
||||||
|
*.ui filter=lfs diff=lfs merge=lfs -text
|
94
Cargo.lock
generated
94
Cargo.lock
generated
|
@ -107,9 +107,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.89"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
|
@ -143,7 +143,7 @@ dependencies = [
|
||||||
"async-task",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand 2.1.1",
|
"fastrand 2.1.1",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite 2.5.0",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -158,21 +158,21 @@ dependencies = [
|
||||||
"async-io",
|
"async-io",
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"blocking",
|
"blocking",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite 2.5.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
|
checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite 2.5.0",
|
||||||
"parking",
|
"parking",
|
||||||
"polling",
|
"polling",
|
||||||
"rustix",
|
"rustix",
|
||||||
|
@ -206,7 +206,7 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite 2.5.0",
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"kv-log-macro",
|
"kv-log-macro",
|
||||||
"log",
|
"log",
|
||||||
|
@ -381,7 +381,7 @@ dependencies = [
|
||||||
"async-channel 2.3.1",
|
"async-channel 2.3.1",
|
||||||
"async-task",
|
"async-task",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite 2.5.0",
|
||||||
"piper",
|
"piper",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -586,9 +586,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curl"
|
name = "curl"
|
||||||
version = "0.4.46"
|
version = "0.4.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6"
|
checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curl-sys",
|
"curl-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -601,9 +601,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curl-sys"
|
name = "curl-sys"
|
||||||
version = "0.4.75+curl-8.10.0"
|
version = "0.4.78+curl-8.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a4fd752d337342e4314717c0d9b6586b059a120c80029ebe4d49b11fec7875e"
|
checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -923,9 +923,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "2.3.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand 2.1.1",
|
"fastrand 2.1.1",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -1056,9 +1056,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.6"
|
version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
|
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes 1.7.1",
|
"bytes 1.7.1",
|
||||||
|
@ -1307,14 +1307,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.5.0"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
|
checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 1.7.1",
|
"bytes 1.7.1",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2 0.4.6",
|
"h2 0.4.7",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
@ -1347,9 +1347,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"hyper 1.5.0",
|
"hyper 1.5.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.16",
|
"rustls 0.23.18",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.0",
|
"tokio-rustls 0.26.0",
|
||||||
|
@ -1364,7 +1364,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 1.7.1",
|
"bytes 1.7.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.5.0",
|
"hyper 1.5.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1383,7 +1383,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"hyper 1.5.0",
|
"hyper 1.5.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.5.7",
|
"socket2 0.5.7",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1907,18 +1907,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.5"
|
version = "1.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
|
checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-internal",
|
"pin-project-internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-internal"
|
name = "pin-project-internal"
|
||||||
version = "1.1.5"
|
version = "1.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1977,9 +1977,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.7.3"
|
version = "3.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
|
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
|
@ -2205,11 +2205,11 @@ dependencies = [
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2 0.4.6",
|
"h2 0.4.7",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.5.0",
|
"hyper 1.5.1",
|
||||||
"hyper-rustls 0.27.3",
|
"hyper-rustls 0.27.3",
|
||||||
"hyper-tls",
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
|
@ -2225,7 +2225,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper 1.0.1",
|
"sync_wrapper 1.0.2",
|
||||||
"system-configuration 0.6.1",
|
"system-configuration 0.6.1",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
|
@ -2341,9 +2341,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.16"
|
version = "0.23.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
|
checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
|
@ -2628,15 +2628,6 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signal-hook-registry"
|
|
||||||
version = "1.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signature"
|
name = "signature"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
@ -2657,7 +2648,6 @@ dependencies = [
|
||||||
"maud",
|
"maud",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
|
||||||
"serenity",
|
"serenity",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"surf",
|
"surf",
|
||||||
|
@ -3076,9 +3066,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sync_wrapper"
|
name = "sync_wrapper"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
@ -3252,9 +3242,7 @@ dependencies = [
|
||||||
"bytes 1.7.1",
|
"bytes 1.7.1",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
|
||||||
"socket2 0.5.7",
|
"socket2 0.5.7",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -3308,7 +3296,7 @@ version = "0.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.23.16",
|
"rustls 0.23.18",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
@ -3533,9 +3521,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "value-bag"
|
name = "value-bag"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
|
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
|
@ -3929,7 +3917,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wolves_oxidised"
|
name = "wolves_oxidised"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#eee6a76c695a36f1fe220fdeafd5a43757e50527"
|
source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#867778128c1ef580ebfded7808bbd4e86f22903b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"reqwest 0.12.9",
|
"reqwest 0.12.9",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -23,6 +23,9 @@ tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "full"] }
|
||||||
# TODO: move off of unstable
|
# TODO: move off of unstable
|
||||||
wolves_oxidised = { git = "https://forgejo.skynet.ie/Skynet/wolves-oxidised.git", features = ["unstable"]}
|
wolves_oxidised = { git = "https://forgejo.skynet.ie/Skynet/wolves-oxidised.git", features = ["unstable"]}
|
||||||
|
|
||||||
|
# wolves api
|
||||||
|
wolves_oxidised = { git = "https://forgejo.skynet.ie/Skynet/wolves-oxidised.git" }
|
||||||
|
|
||||||
# to make the http requests
|
# to make the http requests
|
||||||
surf = "2.3.2"
|
surf = "2.3.2"
|
||||||
|
|
||||||
|
@ -42,4 +45,4 @@ chrono = "0.4.26"
|
||||||
lettre = "0.10.4"
|
lettre = "0.10.4"
|
||||||
maud = "0.25.0"
|
maud = "0.25.0"
|
||||||
|
|
||||||
serde = "1.0.188"
|
serde = "1.0"
|
74
README.md
74
README.md
|
@ -1,70 +1,10 @@
|
||||||
# Skynet Discord Bot
|
# Skynet Discord Bot
|
||||||
This bots core purpose is to give members roles based on their status on <ulwolves.ie>.
|
The Skynet bot is designed to manage users on Discord.
|
||||||
It uses an api key provided by wolves to get member lists.
|
It allows users to link their UL Wolves account with Wolves in a GDPR compliant manner.
|
||||||
|
Skynet (bot) is hosted is hosted by the Computer Society on Skynet (computer cluster).
|
||||||
|
|
||||||
Users are able to link their wolves account to the bot and that works across discord servers.
|
## Documentation
|
||||||
For example is a user links on the CompSoc Discord then they will also get their roles (automagically) on Games Dev if they are a member there.
|
We have split up the documentation into different segments depending on who the user is.
|
||||||
|
|
||||||
## Commands - Admin
|
* [Committees](./doc/Committee.md)
|
||||||
|
* [Member](./doc/User.md)
|
||||||
You need admin access to run any of the commands in this section.
|
|
||||||
Either the server owner or a suer with the ``Administrator`` permission
|
|
||||||
|
|
||||||
### Getting the Skynet Discord bot
|
|
||||||
1. Email ``keith@assurememberships.com`` from committee email and say ye want an api key for ``193.1.99.74``
|
|
||||||
2. Create a role for current members (maybe call it ``current-member`` ?)
|
|
||||||
3. (Optional) create a role for all past and current members (ye can use the existing ``member`` role for this, )
|
|
||||||
4. Invite the bot https://discord.com/api/oauth2/authorize?client_id=1145761669256069270&permissions=139855185984&scope=bot
|
|
||||||
5. Make sure the bot role ``@skynet`` is above these two roles (so it can manage them)
|
|
||||||
6. Make sure that you have a role that gives ye administrator powers
|
|
||||||
7. Use the command ``/add`` and insert the api key, role current and role all (desktop recommended)
|
|
||||||
|
|
||||||
The reason for both roles is ye have one for active members while the second is for all current and past members.
|
|
||||||
|
|
||||||
### Minecraft
|
|
||||||
The bot is able to manage the whitelist of a Minecraft server managed by the Computer Society.
|
|
||||||
Talk to us to get a server.
|
|
||||||
|
|
||||||
#### Add
|
|
||||||
This links a minecraft server with your club/society.
|
|
||||||
|
|
||||||
``/minecraft_add SERVER_ID``
|
|
||||||
|
|
||||||
|
|
||||||
#### List
|
|
||||||
List the servers linked to your club/society.
|
|
||||||
It is possible to have more than one minecraft server
|
|
||||||
|
|
||||||
``/minecraft_list``
|
|
||||||
|
|
||||||
#### Delete
|
|
||||||
This unlinks a minecraft server from your club/society.
|
|
||||||
|
|
||||||
``/minecraft_delete SERVER_ID``
|
|
||||||
|
|
||||||
## Commands - User
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
* Start the process using ``/link_wolves WOLVES_EMAIL``
|
|
||||||
* The email that is in the Contact Email here: <https://ulwolves.ie/memberships/profile>
|
|
||||||
* An email will be sent to them that they need to verify using ``/verify CODE``
|
|
||||||
* This will only have to be done once.
|
|
||||||
|
|
||||||
* If the user is an active member on wolves
|
|
||||||
* If they are in any servers with teh Skynet Bot
|
|
||||||
* They will get relevant roles.
|
|
||||||
* If they Join a server with teh bot enabled.
|
|
||||||
* They will be granted the roles automatically
|
|
||||||
* If the user is **not** an active member on wolves.
|
|
||||||
* If they have no Roles
|
|
||||||
* No change
|
|
||||||
* If they have Past Member Role
|
|
||||||
* No change
|
|
||||||
* If they have both Roles
|
|
||||||
* The current-member role will be removed from them
|
|
||||||
* Past Member role will remain unchanged
|
|
||||||
|
|
||||||
### Minecraft
|
|
||||||
Users can link their Minecraft username to grant them access to any servers where teh whitelist is managed by teh bot.
|
|
||||||
|
|
||||||
``/link_minecraft MINECRAFT_USERNAME``
|
|
3
db/migrations/7_minecraft-bedrock.sql
Normal file
3
db/migrations/7_minecraft-bedrock.sql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
-- Using this col we will be able to see if someone has a bedrock account (as well as a java one)
|
||||||
|
ALTER TABLE wolves ADD COLUMN minecraft_uid TEXT;
|
75
doc/Committee.md
Normal file
75
doc/Committee.md
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Skynet Discord Bot
|
||||||
|
This bots core purpose is to give members roles based on their status on <https://ulwolves.ie>.
|
||||||
|
It uses an api key provided by wolves to get member lists.
|
||||||
|
|
||||||
|
Users are able to link their wolves account to the bot and that works across discord servers.
|
||||||
|
For example is a user links on the CompSoc Discord then they will also get their roles (automagically) on Games Dev if they are a member there.
|
||||||
|
|
||||||
|
## Setup - Committee
|
||||||
|
You need admin access to run any of the commands in this section.
|
||||||
|
Either the server owner or a user with the ``Administrator`` permission.
|
||||||
|
|
||||||
|
### Get the API Key
|
||||||
|
The ``api_key`` is used by the Bot in order to request information, it will be used later in the process.
|
||||||
|
|
||||||
|
1. Email ``keith@assurememberships.com`` from committee email and say you want an ``api_key`` for ``193.1.99.74``
|
||||||
|
* The committee email is the one here: <https://cp.ulwolves.ie/mailbox/>
|
||||||
|
* This may take up to a week to get the key.
|
||||||
|
|
||||||
|
### Setup Server
|
||||||
|
The Bot reason for existing is being able to give members Roles.
|
||||||
|
So we have to create those.
|
||||||
|
|
||||||
|
1. Create a role for Current Members.
|
||||||
|
* You can call it whatever you want.
|
||||||
|
* ``member-current`` is a good choice.
|
||||||
|
* This should be a new role
|
||||||
|
2. **Optional**: you can create a role that is given to folks who were but no longer a member.
|
||||||
|
* ``member`` would be a good choice for this
|
||||||
|
* If you have an existing member role this is also a good fit.
|
||||||
|
|
||||||
|
The reason for both roles is ye have one for active members while the second is for all current and past members.
|
||||||
|
|
||||||
|
### Invite Bot
|
||||||
|
1. Invite the bot https://discord.com/api/oauth2/authorize?client_id=1145761669256069270&permissions=139855185984&scope=bot
|
||||||
|
2. Make sure the bot role ``@skynet`` is above these two roles created in the previous step
|
||||||
|
* This is so it can manage the roles (give and remove them from users)
|
||||||
|
|
||||||
|
### Setup Bot
|
||||||
|
This is where the bot is configured.
|
||||||
|
You will need the ``api_key`` from the start of the process.
|
||||||
|
You (personally) will need a role with ``Administrator`` permission to be able to do this.
|
||||||
|
|
||||||
|
1. Use the command ``/add`` and a list of options will pop up.
|
||||||
|
2. ``api_key`` is the key you got from Keith earlier.
|
||||||
|
3. ``role_current`` is the ``member-current`` that you created earlier.
|
||||||
|
4. ``role_past`` (optional) is the role for all current and past members.
|
||||||
|
5. ``bot_channel`` is a channel that folks are recommended to use the bot.
|
||||||
|
* You can have it so folks cannot see message history
|
||||||
|
6. ``server_name`` For example ``UL Computer Society``
|
||||||
|
* Will be removed in the future
|
||||||
|
7. ``wolves_link`` for example <https://ulwolves.ie/society/computer>
|
||||||
|
* Will be removed in the future
|
||||||
|
|
||||||
|
At this point the bot is set up and no further action is required.
|
||||||
|
|
||||||
|
### Minecraft
|
||||||
|
The bot is able to manage the whitelist of a Minecraft server managed by the Computer Society.
|
||||||
|
Talk to us to get a server.
|
||||||
|
|
||||||
|
#### Add
|
||||||
|
This links a minecraft server with your club/society.
|
||||||
|
|
||||||
|
``/minecraft_add SERVER_ID``
|
||||||
|
|
||||||
|
|
||||||
|
#### List
|
||||||
|
List the servers linked to your club/society.
|
||||||
|
It is possible to have more than one minecraft server
|
||||||
|
|
||||||
|
``/minecraft_list``
|
||||||
|
|
||||||
|
#### Delete
|
||||||
|
This unlinks a minecraft server from your club/society.
|
||||||
|
|
||||||
|
``/minecraft_delete SERVER_ID``
|
26
doc/User.md
Normal file
26
doc/User.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Skynet Discord Bot
|
||||||
|
The Skynet bot is designed to make it easy to verify that you are a member of a Club/Society.
|
||||||
|
The bot will be able to give you member roles for any partnered servers.
|
||||||
|
It also provides secondary manifests such as granting access to minecraft servers managed by teh Computer Society.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
This is to link your Discord account with your UL Wolves account.
|
||||||
|
**You will only need to do this once**.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
1. In a Discord server with the Skynet Bot enter ``/link_wolves YOUR_WOLVES_CONTACT_EMAIL``
|
||||||
|
<img src="../media/setup_user_01.png" alt="link process start" width="50%" height="50%">
|
||||||
|
* Your ``YOUR_WOLVES_CONTACT_EMAIL`` is the email in the Contact Email here: <https://ulwolves.ie/memberships/profile>
|
||||||
|
* This is most likely your student mail
|
||||||
|
2. An email will be sent to you with a verification code.
|
||||||
|
<img src="../media/setup_user_02.png" alt="signup email" width="50%" height="50%">
|
||||||
|
3. Verify the code using ``/verify CODE_FROM_EMAIL`` in Discord.
|
||||||
|
<img src="../media/setup_user_03.png" alt="verify in discord" width="50%" height="50%">
|
||||||
|
4. Once complete your Wolves and Discord accounts will be linked.
|
||||||
|
|
||||||
|
You will get member roles on any Discord that is using the bot that you are a member of.
|
||||||
|
|
||||||
|
### Minecraft
|
||||||
|
You can link your Minecraft username to grant you access to any Minecraft server run by UL Computer Society.
|
||||||
|
|
||||||
|
``/link_minecraft MINECRAFT_USERNAME``
|
|
@ -119,7 +119,7 @@
|
||||||
# modify these
|
# modify these
|
||||||
scripts = {
|
scripts = {
|
||||||
# every 20 min
|
# every 20 min
|
||||||
"update_data" = "*:0,20,40";
|
"update_data" = "*:0,10,20,30,40,50";
|
||||||
# groups are updated every hour, offset from teh ldap
|
# groups are updated every hour, offset from teh ldap
|
||||||
"update_users" = "*:05:00";
|
"update_users" = "*:05:00";
|
||||||
# minecraft stuff is updated at 5am
|
# minecraft stuff is updated at 5am
|
||||||
|
|
BIN
media/setup_user_01.png
(Stored with Git LFS)
Normal file
BIN
media/setup_user_01.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
media/setup_user_02.png
(Stored with Git LFS)
Normal file
BIN
media/setup_user_02.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
media/setup_user_03.png
(Stored with Git LFS)
Normal file
BIN
media/setup_user_03.png
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -163,7 +163,7 @@ pub mod link {
|
||||||
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
|
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div style="display: flex; flex-direction: column; align-items: center;" {
|
div {
|
||||||
h2 { "Hello from Skynet!" }
|
h2 { "Hello from Skynet!" }
|
||||||
// Substitute in the name of our recipient.
|
// Substitute in the name of our recipient.
|
||||||
p { "Hi " (user) "," }
|
p { "Hi " (user) "," }
|
||||||
|
@ -263,6 +263,7 @@ pub mod link {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum WolvesResultUserResult {
|
pub enum WolvesResultUserResult {
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub(crate) mod user {
|
||||||
pub(crate) mod add {
|
pub(crate) mod add {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::commands::link_email::link::get_server_member_discord;
|
use crate::commands::link_email::link::get_server_member_discord;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use serenity::model::id::UserId;
|
use serenity::model::id::UserId;
|
||||||
use skynet_discord_bot::common::database::Wolves;
|
use skynet_discord_bot::common::database::Wolves;
|
||||||
use skynet_discord_bot::common::minecraft::{whitelist_update, Minecraft};
|
use skynet_discord_bot::common::minecraft::{whitelist_update, Minecraft};
|
||||||
|
@ -22,13 +23,23 @@ pub(crate) mod user {
|
||||||
use sqlx::Error;
|
use sqlx::Error;
|
||||||
|
|
||||||
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
command.name("link_minecraft").description("Link your minecraft account").create_option(|option| {
|
command
|
||||||
option
|
.name("link_minecraft")
|
||||||
.name("minecraft-username")
|
.description("Link your minecraft account")
|
||||||
.description("Your Minecraft username")
|
.create_option(|option| {
|
||||||
.kind(CommandOptionType::String)
|
option
|
||||||
.required(true)
|
.name("minecraft_username")
|
||||||
})
|
.description("Your Minecraft username")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("bedrock_account")
|
||||||
|
.description("Is this a Bedrock account?")
|
||||||
|
.kind(CommandOptionType::Boolean)
|
||||||
|
.required(false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String {
|
pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String {
|
||||||
|
@ -63,19 +74,48 @@ pub(crate) mod user {
|
||||||
return "Please provide a valid username".to_string();
|
return "Please provide a valid username".to_string();
|
||||||
};
|
};
|
||||||
|
|
||||||
// insert the username into the database
|
// this is always true unless they state its not
|
||||||
match add_minecraft(&db, &command.user.id, username).await {
|
let mut java = true;
|
||||||
Ok(_) => {}
|
if let Some(x) = command.data.options.get(1) {
|
||||||
Err(e) => {
|
if let Some(CommandDataOptionValue::Boolean(z)) = x.to_owned().resolved {
|
||||||
dbg!("{:?}", e);
|
java = !z;
|
||||||
return format!("Failure to minecraft username {:?}", username);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let username_mc;
|
||||||
|
if java {
|
||||||
|
// insert the username into the database
|
||||||
|
match add_minecraft(&db, &command.user.id, username).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
dbg!("{:?}", e);
|
||||||
|
return format!("Failure to minecraft username {:?}", username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
username_mc = username.to_string();
|
||||||
|
} else {
|
||||||
|
match get_minecraft_bedrock(username, &config.minecraft_mcprofile).await {
|
||||||
|
None => {
|
||||||
|
return format!("No UID found for {:?}", username);
|
||||||
|
}
|
||||||
|
Some(x) => {
|
||||||
|
match add_minecraft_bedrock(&db, &command.user.id, &x.floodgateuid).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
dbg!("{:?}", e);
|
||||||
|
return format!("Failure to minecraft UID {:?}", &x.floodgateuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
username_mc = x.floodgateuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a list of servers that the user is a member of
|
// get a list of servers that the user is a member of
|
||||||
if let Ok(servers) = get_servers(&db, &command.user.id).await {
|
if let Ok(servers) = get_servers(&db, &command.user.id).await {
|
||||||
for server in servers {
|
for server in servers {
|
||||||
whitelist_update(&vec![username.to_string()], &server.minecraft, &config.discord_token_minecraft).await;
|
whitelist_update(&vec![(username_mc.to_owned(), java)], &server.minecraft, &config.discord_token_minecraft).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +136,51 @@ pub(crate) mod user {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct BedrockDetails {
|
||||||
|
pub gamertag: String,
|
||||||
|
pub xuid: String,
|
||||||
|
pub floodgateuid: String,
|
||||||
|
pub icon: String,
|
||||||
|
pub gamescore: String,
|
||||||
|
pub accounttier: String,
|
||||||
|
pub textureid: String,
|
||||||
|
pub skin: String,
|
||||||
|
pub linked: bool,
|
||||||
|
pub java_uuid: String,
|
||||||
|
pub java_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_minecraft_bedrock(username: &str, api_key: &str) -> Option<BedrockDetails> {
|
||||||
|
let url = format!("https://mcprofile.io/api/v1/bedrock/gamertag/{username}/");
|
||||||
|
match surf::get(url)
|
||||||
|
.header("x-api-key", api_key)
|
||||||
|
.header("User-Agent", "UL Computer Society")
|
||||||
|
.recv_json()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(res) => Some(res),
|
||||||
|
Err(e) => {
|
||||||
|
dbg!(e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_minecraft_bedrock(db: &Pool<Sqlite>, user: &UserId, minecraft: &str) -> Result<Option<Wolves>, Error> {
|
||||||
|
sqlx::query_as::<_, Wolves>(
|
||||||
|
"
|
||||||
|
UPDATE wolves
|
||||||
|
SET minecraft_uid = ?2
|
||||||
|
WHERE discord = ?1;
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(*user.as_u64() as i64)
|
||||||
|
.bind(minecraft)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_servers(db: &Pool<Sqlite>, discord: &UserId) -> Result<Vec<Minecraft>, Error> {
|
async fn get_servers(db: &Pool<Sqlite>, discord: &UserId) -> Result<Vec<Minecraft>, Error> {
|
||||||
sqlx::query_as::<_, Minecraft>(
|
sqlx::query_as::<_, Minecraft>(
|
||||||
"
|
"
|
||||||
|
@ -249,7 +334,7 @@ pub(crate) mod server {
|
||||||
ID: {id}
|
ID: {id}
|
||||||
Online: {online}
|
Online: {online}
|
||||||
Info: {description}
|
Info: {description}
|
||||||
Link: <http://panel.games.skynet.ie/server/{id}>
|
Link: <https://panel.games.skynet.ie/server/{id}>
|
||||||
"#,
|
"#,
|
||||||
name = &x.attributes.name,
|
name = &x.attributes.name,
|
||||||
online = !x.attributes.is_suspended,
|
online = !x.attributes.is_suspended,
|
||||||
|
|
697
src/lib.rs
697
src/lib.rs
|
@ -9,6 +9,8 @@ use serenity::model::prelude::application_command::ApplicationCommandInteraction
|
||||||
use serenity::prelude::TypeMapKey;
|
use serenity::prelude::TypeMapKey;
|
||||||
use std::{env, sync::Arc};
|
use std::{env, sync::Arc};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
// manages where teh database is stored
|
// manages where teh database is stored
|
||||||
pub home: String,
|
pub home: String,
|
||||||
|
@ -17,6 +19,7 @@ pub struct Config {
|
||||||
// tokens for discord and other API's
|
// tokens for discord and other API's
|
||||||
pub discord_token: String,
|
pub discord_token: String,
|
||||||
pub discord_token_minecraft: String,
|
pub discord_token_minecraft: String,
|
||||||
|
pub minecraft_mcprofile: String,
|
||||||
|
|
||||||
// email settings
|
// email settings
|
||||||
pub mail_smtp: String,
|
pub mail_smtp: String,
|
||||||
|
@ -44,6 +47,7 @@ pub fn get_config() -> Config {
|
||||||
let mut config = Config {
|
let mut config = Config {
|
||||||
discord_token: "".to_string(),
|
discord_token: "".to_string(),
|
||||||
discord_token_minecraft: "".to_string(),
|
discord_token_minecraft: "".to_string(),
|
||||||
|
minecraft_mcprofile: "".to_string(),
|
||||||
|
|
||||||
home: ".".to_string(),
|
home: ".".to_string(),
|
||||||
database: "database.db".to_string(),
|
database: "database.db".to_string(),
|
||||||
|
@ -52,7 +56,6 @@ pub fn get_config() -> Config {
|
||||||
mail_user: "".to_string(),
|
mail_user: "".to_string(),
|
||||||
mail_pass: "".to_string(),
|
mail_pass: "".to_string(),
|
||||||
wolves_url: "".to_string(),
|
wolves_url: "".to_string(),
|
||||||
wolves_api: "".to_string(),
|
|
||||||
committee_server: GuildId(0),
|
committee_server: GuildId(0),
|
||||||
committee_role: RoleId(0),
|
committee_role: RoleId(0),
|
||||||
committee_category: ChannelId(0),
|
committee_category: ChannelId(0),
|
||||||
|
@ -71,6 +74,9 @@ pub fn get_config() -> Config {
|
||||||
if let Ok(x) = env::var("DISCORD_TOKEN_MINECRAFT") {
|
if let Ok(x) = env::var("DISCORD_TOKEN_MINECRAFT") {
|
||||||
config.discord_token_minecraft = x.trim().to_string();
|
config.discord_token_minecraft = x.trim().to_string();
|
||||||
}
|
}
|
||||||
|
if let Ok(x) = env::var("MINECRAFT_MCPROFILE_KEY") {
|
||||||
|
config.minecraft_mcprofile = x.trim().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(x) = env::var("EMAIL_SMTP") {
|
if let Ok(x) = env::var("EMAIL_SMTP") {
|
||||||
config.mail_smtp = x.trim().to_string();
|
config.mail_smtp = x.trim().to_string();
|
||||||
|
@ -85,7 +91,6 @@ pub fn get_config() -> Config {
|
||||||
if let Ok(x) = env::var("WOLVES_URL_BASE") {
|
if let Ok(x) = env::var("WOLVES_URL_BASE") {
|
||||||
config.wolves_url = x.trim().to_string();
|
config.wolves_url = x.trim().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(x) = env::var("WOLVES_API") {
|
if let Ok(x) = env::var("WOLVES_API") {
|
||||||
config.wolves_api = x.trim().to_string();
|
config.wolves_api = x.trim().to_string();
|
||||||
}
|
}
|
||||||
|
@ -109,6 +114,295 @@ pub fn get_config() -> Config {
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct ServerMembers {
|
||||||
|
pub server: GuildId,
|
||||||
|
pub id_wolves: i64,
|
||||||
|
pub expiry: String,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for ServerMembers {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server")?;
|
||||||
|
let server = GuildId::from(server_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
server,
|
||||||
|
id_wolves: row.try_get("id_wolves")?,
|
||||||
|
expiry: row.try_get("expiry")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct ServerMembersWolves {
|
||||||
|
pub server: GuildId,
|
||||||
|
pub id_wolves: i64,
|
||||||
|
pub expiry: String,
|
||||||
|
pub email: String,
|
||||||
|
pub discord: Option<UserId>,
|
||||||
|
pub minecraft: Option<String>,
|
||||||
|
pub minecraft_uid: Option<String>,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for ServerMembersWolves {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server")?;
|
||||||
|
let server = GuildId::from(server_tmp as u64);
|
||||||
|
let discord = match row.try_get("discord") {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
if tmp == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(UserId::from(tmp as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
server,
|
||||||
|
id_wolves: row.try_get("id_wolves")?,
|
||||||
|
expiry: row.try_get("expiry")?,
|
||||||
|
email: row.try_get("email")?,
|
||||||
|
discord,
|
||||||
|
minecraft: row.try_get("minecraft")?,
|
||||||
|
minecraft_uid: row.try_get("minecraft_uid")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct Wolves {
|
||||||
|
pub id_wolves: i64,
|
||||||
|
pub email: String,
|
||||||
|
pub discord: Option<UserId>,
|
||||||
|
pub minecraft: Option<String>,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for Wolves {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let discord = match row.try_get("discord") {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
if tmp == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(UserId::from(tmp as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
id_wolves: row.try_get("id_wolves")?,
|
||||||
|
email: row.try_get("email")?,
|
||||||
|
discord,
|
||||||
|
minecraft: row.try_get("minecraft")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct WolvesVerify {
|
||||||
|
pub email: String,
|
||||||
|
pub discord: UserId,
|
||||||
|
pub auth_code: String,
|
||||||
|
pub date_expiry: String,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for WolvesVerify {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let user_tmp: i64 = row.try_get("discord")?;
|
||||||
|
let discord = UserId::from(user_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
email: row.try_get("email")?,
|
||||||
|
discord,
|
||||||
|
auth_code: row.try_get("auth_code")?,
|
||||||
|
date_expiry: row.try_get("date_expiry")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct Committee {
|
||||||
|
pub email: String,
|
||||||
|
pub discord: UserId,
|
||||||
|
pub auth_code: String,
|
||||||
|
pub committee: i64,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for Committee {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let user_tmp: i64 = row.try_get("discord")?;
|
||||||
|
let discord = UserId::from(user_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
email: row.try_get("email")?,
|
||||||
|
discord,
|
||||||
|
auth_code: row.try_get("auth_code")?,
|
||||||
|
committee: row.try_get("committee")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct Servers {
|
||||||
|
pub server: GuildId,
|
||||||
|
pub wolves_api: String,
|
||||||
|
pub role_past: Option<RoleId>,
|
||||||
|
pub role_current: RoleId,
|
||||||
|
pub member_past: i64,
|
||||||
|
pub member_current: i64,
|
||||||
|
pub bot_channel_id: ChannelId,
|
||||||
|
// these can be removed in teh future with an API update
|
||||||
|
pub server_name: String,
|
||||||
|
pub wolves_link: String,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for Servers {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server")?;
|
||||||
|
let server = GuildId::from(server_tmp as u64);
|
||||||
|
let role_past = match row.try_get("role_past") {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
if tmp == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(RoleId::from(tmp as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let role_current = match row.try_get("role_current") {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
RoleId::from(tmp as u64)
|
||||||
|
}
|
||||||
|
_ => RoleId::from(0u64),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bot_channel_tmp: i64 = row.try_get("bot_channel_id")?;
|
||||||
|
let bot_channel_id = ChannelId::from(bot_channel_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
server,
|
||||||
|
wolves_api: row.try_get("wolves_api")?,
|
||||||
|
role_past,
|
||||||
|
role_current,
|
||||||
|
member_past: row.try_get("member_past")?,
|
||||||
|
member_current: row.try_get("member_current")?,
|
||||||
|
bot_channel_id,
|
||||||
|
server_name: row.try_get("server_name")?,
|
||||||
|
wolves_link: row.try_get("wolves_link")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct Minecraft {
|
||||||
|
pub discord: GuildId,
|
||||||
|
pub minecraft: String,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for Minecraft {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server_discord")?;
|
||||||
|
let discord = GuildId::from(server_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
discord,
|
||||||
|
minecraft: row.try_get("server_minecraft")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct RoleAdder {
|
||||||
|
pub server: GuildId,
|
||||||
|
pub role_a: RoleId,
|
||||||
|
pub role_b: RoleId,
|
||||||
|
pub role_c: RoleId,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for RoleAdder {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server")?;
|
||||||
|
let server = GuildId::from(server_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
server,
|
||||||
|
role_a: get_role_from_row(row, "role_a"),
|
||||||
|
role_b: get_role_from_row(row, "role_b"),
|
||||||
|
role_c: get_role_from_row(row, "role_c"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
|
||||||
|
match row.try_get(col) {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
RoleId(tmp as u64)
|
||||||
|
}
|
||||||
|
_ => RoleId::from(0u64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
||||||
|
let database = format!("{}/{}", &config.home, &config.database);
|
||||||
|
|
||||||
|
let pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(5)
|
||||||
|
.connect_with(
|
||||||
|
SqliteConnectOptions::from_str(&format!("sqlite://{}", database))?
|
||||||
|
.foreign_keys(true)
|
||||||
|
.create_if_missing(true),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// migrations are amazing!
|
||||||
|
sqlx::migrate!("./db/migrations").run(&pool).await?;
|
||||||
|
|
||||||
|
Ok(pool)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_server_config(db: &Pool<Sqlite>, server: &GuildId) -> Option<Servers> {
|
||||||
|
sqlx::query_as::<_, Servers>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM servers
|
||||||
|
WHERE server = ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_server_member(db: &Pool<Sqlite>, server: &GuildId, member: &guild::Member) -> Result<ServerMembersWolves, Error> {
|
||||||
|
sqlx::query_as::<_, ServerMembersWolves>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM server_members
|
||||||
|
JOIN wolves USING (id_wolves)
|
||||||
|
WHERE server = ? AND discord = ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.bind(*member.user.id.as_u64() as i64)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_server_config_bulk(db: &Pool<Sqlite>) -> Vec<Servers> {
|
||||||
|
sqlx::query_as::<_, Servers>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM servers
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_now_iso(short: bool) -> String {
|
pub fn get_now_iso(short: bool) -> String {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
if short {
|
if short {
|
||||||
|
@ -122,6 +416,255 @@ pub fn random_string(len: usize) -> String {
|
||||||
thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect()
|
thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod set_roles {
|
||||||
|
use super::*;
|
||||||
|
pub async fn update_server(ctx: &Context, server: &Servers, remove_roles: &[Option<RoleId>], members_changed: &[UserId]) {
|
||||||
|
let db_lock = {
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let db = db_lock.read().await;
|
||||||
|
|
||||||
|
let Servers {
|
||||||
|
server,
|
||||||
|
role_past,
|
||||||
|
role_current,
|
||||||
|
..
|
||||||
|
} = server;
|
||||||
|
|
||||||
|
let mut roles_set = [0, 0, 0];
|
||||||
|
let mut members = vec![];
|
||||||
|
|
||||||
|
for member in get_server_member_bulk(&db, server).await {
|
||||||
|
if let Some(x) = member.discord {
|
||||||
|
members.push(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut members_all = members.len();
|
||||||
|
|
||||||
|
if let Ok(x) = server.members(ctx, None, None).await {
|
||||||
|
for mut member in x {
|
||||||
|
// members_changed acts as an override to only deal with teh users in it
|
||||||
|
if !members_changed.is_empty() && !members_changed.contains(&member.user.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if members.contains(&member.user.id) {
|
||||||
|
let mut roles = vec![];
|
||||||
|
|
||||||
|
if let Some(role) = &role_past {
|
||||||
|
if !member.roles.contains(role) {
|
||||||
|
roles_set[0] += 1;
|
||||||
|
roles.push(role.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !member.roles.contains(role_current) {
|
||||||
|
roles_set[1] += 1;
|
||||||
|
roles.push(role_current.to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = member.add_roles(ctx, &roles).await {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// old and never
|
||||||
|
|
||||||
|
if let Some(role) = &role_past {
|
||||||
|
if member.roles.contains(role) {
|
||||||
|
members_all += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if member.roles.contains(role_current) {
|
||||||
|
roles_set[2] += 1;
|
||||||
|
// if theya re not a current member and have the role then remove it
|
||||||
|
if let Err(e) = member.remove_role(ctx, role_current).await {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for role in remove_roles.iter().flatten() {
|
||||||
|
if let Err(e) = member.remove_role(ctx, role).await {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_server_numbers(&db, server, members_all as i64, members.len() as i64).await;
|
||||||
|
|
||||||
|
// small bit of logging to note changes over time
|
||||||
|
println!("{:?} Changes: New: +{}, Current: +{}/-{}", server.as_u64(), roles_set[0], roles_set[1], roles_set[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_server_member_bulk(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
|
||||||
|
sqlx::query_as::<_, ServerMembersWolves>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM server_members
|
||||||
|
JOIN wolves USING (id_wolves)
|
||||||
|
WHERE (
|
||||||
|
server = ?
|
||||||
|
AND discord IS NOT NULL
|
||||||
|
AND expiry > ?
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.bind(get_now_iso(true))
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_server_numbers(db: &Pool<Sqlite>, server: &GuildId, past: i64, current: i64) {
|
||||||
|
match sqlx::query_as::<_, Wolves>(
|
||||||
|
"
|
||||||
|
UPDATE servers
|
||||||
|
SET member_past = ?, member_current = ?
|
||||||
|
WHERE server = ?
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(past)
|
||||||
|
.bind(current)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failure to insert into {}", server.as_u64());
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod get_data {
|
||||||
|
use super::*;
|
||||||
|
use crate::set_roles::update_server;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use wolves_oxidised::WolvesUser;
|
||||||
|
|
||||||
|
pub async fn get_wolves(ctx: &Context) {
|
||||||
|
let db_lock = {
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
|
||||||
|
};
|
||||||
|
let db = db_lock.read().await;
|
||||||
|
|
||||||
|
let config_lock = {
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
data_read.get::<Config>().expect("Expected Config in TypeMap.").clone()
|
||||||
|
};
|
||||||
|
let config = config_lock.read().await;
|
||||||
|
|
||||||
|
// set up teh client
|
||||||
|
let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api));
|
||||||
|
|
||||||
|
for server_config in get_server_config_bulk(&db).await {
|
||||||
|
let Servers {
|
||||||
|
server,
|
||||||
|
wolves_api,
|
||||||
|
..
|
||||||
|
} = &server_config;
|
||||||
|
|
||||||
|
let existing_tmp = get_server_member(&db, server).await;
|
||||||
|
let existing = existing_tmp.iter().map(|data| (data.id_wolves, data)).collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
// list of users that need to be updated for this server
|
||||||
|
let mut user_to_update = vec![];
|
||||||
|
for user in wolves.get_members(wolves_api).await {
|
||||||
|
let id = user.member_id.parse::<u64>().unwrap_or_default();
|
||||||
|
match existing.get(&(id as i64)) {
|
||||||
|
None => {
|
||||||
|
// user does not exist already, add everything
|
||||||
|
add_users_wolves(&db, &user).await;
|
||||||
|
add_users_server_members(&db, server, &user).await;
|
||||||
|
}
|
||||||
|
Some(old) => {
|
||||||
|
// always update wolves table, in case data has changed
|
||||||
|
add_users_wolves(&db, &user).await;
|
||||||
|
if old.expiry != user.expiry {
|
||||||
|
add_users_server_members(&db, server, &user).await;
|
||||||
|
|
||||||
|
if let Some(discord_id) = old.discord {
|
||||||
|
user_to_update.push(discord_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user_to_update.is_empty() {
|
||||||
|
update_server(ctx, &server_config, &[], &user_to_update).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_server_member(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
|
||||||
|
sqlx::query_as::<_, ServerMembersWolves>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM server_members
|
||||||
|
JOIN wolves USING (id_wolves)
|
||||||
|
WHERE (
|
||||||
|
server = ?
|
||||||
|
AND discord IS NOT NULL
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_users_wolves(db: &Pool<Sqlite>, user: &WolvesUser) {
|
||||||
|
// expiry
|
||||||
|
match sqlx::query_as::<_, Wolves>(
|
||||||
|
"
|
||||||
|
INSERT INTO wolves (id_wolves, email)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
ON CONFLICT(id_wolves) DO UPDATE SET email = $2
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(&user.member_id)
|
||||||
|
.bind(&user.contact_email)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failure to insert into Wolves {:?}", user);
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn add_users_server_members(db: &Pool<Sqlite>, server: &GuildId, user: &WolvesUser) {
|
||||||
|
match sqlx::query_as::<_, ServerMembers>(
|
||||||
|
"
|
||||||
|
INSERT OR REPLACE INTO server_members (server, id_wolves, expiry)
|
||||||
|
VALUES (?1, ?2, ?3)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(*server.as_u64() as i64)
|
||||||
|
.bind(&user.member_id)
|
||||||
|
.bind(&user.expiry)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failure to insert into ServerMembers {} {:?}", server.as_u64(), user);
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
For any time ye need to check if a user who calls a command has admin privlages
|
For any time ye need to check if a user who calls a command has admin privlages
|
||||||
*/
|
*/
|
||||||
|
@ -159,3 +702,153 @@ pub async fn is_admin(command: &ApplicationCommandInteraction, ctx: &Context) ->
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
loop through all members of server
|
||||||
|
get a list of folks with mc accounts that are members
|
||||||
|
and a list that arent members
|
||||||
|
*/
|
||||||
|
pub async fn update_server(server_id: &str, db: &Pool<Sqlite>, g_id: &GuildId, config: &Config) {
|
||||||
|
let mut usernames = vec![];
|
||||||
|
for member in get_server_member_bulk(db, g_id).await {
|
||||||
|
if let Some(x) = member.minecraft {
|
||||||
|
usernames.push((x, true));
|
||||||
|
}
|
||||||
|
if let Some(x) = member.minecraft_uid {
|
||||||
|
usernames.push((x, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !usernames.is_empty() {
|
||||||
|
whitelist_update(&usernames, server_id, &config.discord_token_minecraft).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post<T: Serialize>(url: &str, bearer: &str, data: &T) {
|
||||||
|
match surf::post(url)
|
||||||
|
.header("Authorization", bearer)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "Application/vnd.pterodactyl.v1+json")
|
||||||
|
.body_json(&data)
|
||||||
|
{
|
||||||
|
Ok(req) => {
|
||||||
|
req.await.ok();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
dbg!(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct ServerDetailsResSub {
|
||||||
|
pub identifier: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub is_suspended: bool,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct ServerDetailsRes {
|
||||||
|
pub attributes: ServerDetailsResSub,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get<T: Serialize + DeserializeOwned>(url: &str, bearer: &str) -> Option<T> {
|
||||||
|
match surf::get(url)
|
||||||
|
.header("Authorization", bearer)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "Application/vnd.pterodactyl.v1+json")
|
||||||
|
.recv_json()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(res) => Some(res),
|
||||||
|
Err(e) => {
|
||||||
|
dbg!(e);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
struct BodyCommand {
|
||||||
|
command: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
struct BodyDelete {
|
||||||
|
root: String,
|
||||||
|
files: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn whitelist_update(add: &Vec<(String, bool)>, server: &str, token: &str) {
|
||||||
|
println!("Update whitelist for {}", server);
|
||||||
|
let url_base = format!("https://panel.games.skynet.ie/api/client/servers/{server}");
|
||||||
|
let bearer = format!("Bearer {token}");
|
||||||
|
|
||||||
|
for (name, java) in add {
|
||||||
|
let data = if *java {
|
||||||
|
BodyCommand {
|
||||||
|
command: format!("whitelist add {name}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BodyCommand {
|
||||||
|
command: format!("fwhitelist add {name}"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
post(&format!("{url_base}/command"), &bearer, &data).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn whitelist_wipe(server: &str, token: &str) {
|
||||||
|
println!("Wiping whitelist for {}", server);
|
||||||
|
let url_base = format!("https://panel.games.skynet.ie/api/client/servers/{server}");
|
||||||
|
let bearer = format!("Bearer {token}");
|
||||||
|
|
||||||
|
// delete whitelist
|
||||||
|
let deletion = BodyDelete {
|
||||||
|
root: "/".to_string(),
|
||||||
|
files: vec!["whitelist.json".to_string()],
|
||||||
|
};
|
||||||
|
post(&format!("{url_base}/files/delete"), &bearer, &deletion).await;
|
||||||
|
|
||||||
|
// recreate teh file, passing in the type here so the compiler knows what type of vec it is
|
||||||
|
post::<Vec<&str>>(&format!("{url_base}/files/write?file=%2Fwhitelist.json"), &bearer, &vec![]).await;
|
||||||
|
|
||||||
|
// reload the whitelist
|
||||||
|
let data = BodyCommand {
|
||||||
|
command: "whitelist reload".to_string(),
|
||||||
|
};
|
||||||
|
post(&format!("{url_base}/command"), &bearer, &data).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn server_information(server: &str, token: &str) -> Option<ServerDetailsRes> {
|
||||||
|
println!("Get server information for {}", server);
|
||||||
|
let url_base = format!("https://panel.games.skynet.ie/api/client/servers/{server}");
|
||||||
|
let bearer = format!("Bearer {token}");
|
||||||
|
get::<ServerDetailsRes>(&format!("{url_base}/"), &bearer).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_minecraft_config(db: &Pool<Sqlite>) -> Vec<Minecraft> {
|
||||||
|
sqlx::query_as::<_, Minecraft>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM minecraft
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_minecraft_config_server(db: &Pool<Sqlite>, g_id: GuildId) -> Vec<Minecraft> {
|
||||||
|
sqlx::query_as::<_, Minecraft>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM minecraft
|
||||||
|
WHERE server_discord = ?1
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*g_id.as_u64() as i64)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue