From 37ea38f516e4f86c43b685fd365e078336c6e858 Mon Sep 17 00:00:00 2001
From: Brendan Golden <git@brendan.ie>
Date: Sat, 23 Nov 2024 22:17:57 +0000
Subject: [PATCH] feat: backport changes from the #17-automate-onboarding-mk-ii
 branch

---
 Cargo.lock                 | 413 +++++++++++++++++++++++++++++++++----
 Cargo.toml                 |   5 +-
 src/commands/link_email.rs |  43 +++-
 src/lib.rs                 |  68 ++----
 4 files changed, 433 insertions(+), 96 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index d8c9113..0f043b2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -218,6 +218,28 @@ dependencies = [
  "wasm-bindgen-futures",
 ]
 
+[[package]]
+name = "async-stream"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
 [[package]]
 name = "async-task"
 version = "4.7.1"
@@ -232,7 +254,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -920,7 +942,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1024,7 +1046,26 @@ dependencies = [
  "futures-core",
  "futures-sink",
  "futures-util",
- "http",
+ "http 0.2.12",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
+dependencies = [
+ "atomic-waker",
+ "bytes 1.7.1",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http 1.1.0",
  "indexmap",
  "slab",
  "tokio",
@@ -1147,6 +1188,17 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes 1.7.1",
+ "fnv",
+ "itoa",
+]
+
 [[package]]
 name = "http-body"
 version = "0.4.6"
@@ -1154,7 +1206,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
 dependencies = [
  "bytes 1.7.1",
- "http",
+ "http 0.2.12",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes 1.7.1",
+ "http 1.1.0",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes 1.7.1",
+ "futures-util",
+ "http 1.1.0",
+ "http-body 1.0.1",
  "pin-project-lite",
 ]
 
@@ -1216,9 +1291,9 @@ dependencies = [
  "futures-channel",
  "futures-core",
  "futures-util",
- "h2",
- "http",
- "http-body",
+ "h2 0.3.26",
+ "http 0.2.12",
+ "http-body 0.4.6",
  "httparse",
  "httpdate",
  "itoa",
@@ -1230,6 +1305,26 @@ dependencies = [
  "want",
 ]
 
+[[package]]
+name = "hyper"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
+dependencies = [
+ "bytes 1.7.1",
+ "futures-channel",
+ "futures-util",
+ "h2 0.4.7",
+ "http 1.1.0",
+ "http-body 1.0.1",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
 [[package]]
 name = "hyper-rustls"
 version = "0.24.2"
@@ -1237,13 +1332,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
- "http",
- "hyper",
+ "http 0.2.12",
+ "hyper 0.14.30",
  "rustls 0.21.12",
  "tokio",
  "tokio-rustls 0.24.1",
 ]
 
+[[package]]
+name = "hyper-rustls"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+dependencies = [
+ "futures-util",
+ "http 1.1.0",
+ "hyper 1.5.1",
+ "hyper-util",
+ "rustls 0.23.18",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls 0.26.0",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes 1.7.1",
+ "http-body-util",
+ "hyper 1.5.1",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+dependencies = [
+ "bytes 1.7.1",
+ "futures-channel",
+ "futures-util",
+ "http 1.1.0",
+ "http-body 1.0.1",
+ "hyper 1.5.1",
+ "pin-project-lite",
+ "socket2 0.5.7",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
 [[package]]
 name = "iana-time-zone"
 version = "0.1.61"
@@ -1330,7 +1477,7 @@ dependencies = [
  "curl-sys",
  "flume 0.9.2",
  "futures-lite 1.13.0",
- "http",
+ "http 0.2.12",
  "log",
  "once_cell",
  "slab",
@@ -1678,7 +1825,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1775,7 +1922,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1901,9 +2048,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -2014,11 +2161,11 @@ dependencies = [
  "encoding_rs",
  "futures-core",
  "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-rustls",
+ "h2 0.3.26",
+ "http 0.2.12",
+ "http-body 0.4.6",
+ "hyper 0.14.30",
+ "hyper-rustls 0.24.2",
  "ipnet",
  "js-sys",
  "log",
@@ -2028,12 +2175,12 @@ dependencies = [
  "percent-encoding",
  "pin-project-lite",
  "rustls 0.21.12",
- "rustls-pemfile",
+ "rustls-pemfile 1.0.4",
  "serde",
  "serde_json",
  "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
+ "sync_wrapper 0.1.2",
+ "system-configuration 0.5.1",
  "tokio",
  "tokio-rustls 0.24.1",
  "tokio-util",
@@ -2047,6 +2194,49 @@ dependencies = [
  "winreg",
 ]
 
+[[package]]
+name = "reqwest"
+version = "0.12.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
+dependencies = [
+ "base64 0.22.1",
+ "bytes 1.7.1",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2 0.4.7",
+ "http 1.1.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "hyper 1.5.1",
+ "hyper-rustls 0.27.3",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pemfile 2.2.0",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper 1.0.2",
+ "system-configuration 0.6.1",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows-registry",
+]
+
 [[package]]
 name = "ring"
 version = "0.16.20"
@@ -2145,10 +2335,23 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
 dependencies = [
  "log",
  "ring 0.17.8",
- "rustls-webpki",
+ "rustls-webpki 0.101.7",
  "sct",
 ]
 
+[[package]]
+name = "rustls"
+version = "0.23.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
+dependencies = [
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki 0.102.8",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "rustls-pemfile"
 version = "1.0.4"
@@ -2158,6 +2361,21 @@ dependencies = [
  "base64 0.21.7",
 ]
 
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+
 [[package]]
 name = "rustls-webpki"
 version = "0.101.7"
@@ -2168,6 +2386,17 @@ dependencies = [
  "untrusted 0.9.0",
 ]
 
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "ring 0.17.8",
+ "rustls-pki-types",
+ "untrusted 0.9.0",
+]
+
 [[package]]
 name = "ryu"
 version = "1.0.18"
@@ -2239,9 +2468,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
 dependencies = [
  "serde_derive",
 ]
@@ -2258,13 +2487,13 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -2321,7 +2550,7 @@ dependencies = [
  "mime_guess",
  "parking_lot",
  "percent-encoding",
- "reqwest",
+ "reqwest 0.11.27",
  "serde",
  "serde-value",
  "serde_json",
@@ -2423,6 +2652,7 @@ dependencies = [
  "sqlx",
  "surf",
  "tokio",
+ "wolves_oxidised",
 ]
 
 [[package]]
@@ -2819,9 +3049,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.77"
+version = "2.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2834,6 +3064,15 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
 
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
 [[package]]
 name = "system-configuration"
 version = "0.5.1"
@@ -2842,7 +3081,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
 dependencies = [
  "bitflags 1.3.2",
  "core-foundation",
- "system-configuration-sys",
+ "system-configuration-sys 0.5.0",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags 2.6.0",
+ "core-foundation",
+ "system-configuration-sys 0.6.0",
 ]
 
 [[package]]
@@ -2855,6 +3105,16 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "tempfile"
 version = "3.12.0"
@@ -2885,7 +3145,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -2996,7 +3256,17 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
 ]
 
 [[package]]
@@ -3020,6 +3290,17 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls 0.23.18",
+ "rustls-pki-types",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-stream"
 version = "0.1.16"
@@ -3031,6 +3312,19 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "tokio-test"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
+dependencies = [
+ "async-stream",
+ "bytes 1.7.1",
+ "futures-core",
+ "tokio",
+ "tokio-stream",
+]
+
 [[package]]
 name = "tokio-util"
 version = "0.7.12"
@@ -3070,7 +3364,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -3107,7 +3401,7 @@ dependencies = [
  "base64 0.13.1",
  "byteorder",
  "bytes 1.7.1",
- "http",
+ "http 0.2.12",
  "httparse",
  "log",
  "rand 0.8.5",
@@ -3298,7 +3592,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
  "wasm-bindgen-shared",
 ]
 
@@ -3332,7 +3626,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -3432,6 +3726,36 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows-registry"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+dependencies = [
+ "windows-result",
+ "windows-strings",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -3590,6 +3914,17 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "wolves_oxidised"
+version = "0.1.0"
+source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#eee6a76c695a36f1fe220fdeafd5a43757e50527"
+dependencies = [
+ "reqwest 0.12.9",
+ "serde",
+ "serde_json",
+ "tokio-test",
+]
+
 [[package]]
 name = "zerocopy"
 version = "0.7.35"
@@ -3608,7 +3943,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.89",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index a26023a..2dc64c8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,9 @@ name = "update_minecraft"
 serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] }
 tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
 
+# wolves api
+wolves_oxidised = { git = "https://forgejo.skynet.ie/Skynet/wolves-oxidised.git" }
+
 #  to make the http requests
 surf = "2.3.2"
 
@@ -37,4 +40,4 @@ chrono = "0.4.26"
 lettre = "0.10.4"
 maud = "0.25.0"
 
-serde = "1.0.188"
\ No newline at end of file
+serde = "1.0"
\ No newline at end of file
diff --git a/src/commands/link_email.rs b/src/commands/link_email.rs
index 1b462f6..a2a6f5d 100644
--- a/src/commands/link_email.rs
+++ b/src/commands/link_email.rs
@@ -59,7 +59,34 @@ pub mod link {
     // check if email exists
     let details = match get_server_member_email(&db, email).await {
       None => {
-        return "Please check it matches (including case) your preferred contact on https://ulwolves.ie/memberships/profile and that you are fully paid up.".to_string()
+        let invalid_user =  "Please check it matches (including case) your preferred contact on https://ulwolves.ie/memberships/profile and that you are fully paid up.".to_string();
+
+        let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api));
+
+        // see if the user actually exists
+        let id = match wolves.get_member(email).await {
+          None => {
+            return invalid_user;
+          }
+          Some(x) => x,
+        };
+
+        // save teh user id and email to teh db
+        match save_to_db_user(&db, id, email).await {
+          Ok(x) => x,
+          Err(x) => {
+            dbg!(x);
+            return "Error: unable to save user to teh database, contact Computer Society".to_string();
+          }
+        };
+
+        // pull it back out (technically could do it in previous step but more explicit)
+        match get_server_member_email(&db, email).await {
+          None => {
+            return "Error: failed to read user from database.".to_string();
+          }
+          Some(x) => x,
+        }
       }
       Some(x) => x,
     };
@@ -232,6 +259,20 @@ pub mod link {
     .fetch_optional(db)
     .await
   }
+
+  async fn save_to_db_user(db: &Pool<Sqlite>, id_wolves: i64, email: &str) -> Result<Option<Wolves>, sqlx::Error> {
+    sqlx::query_as::<_, Wolves>(
+      "
+        INSERT INTO wolves (id_wolves, email)
+        VALUES ($1, $2)
+        ON CONFLICT(id_wolves) DO UPDATE SET email = $2
+        ",
+    )
+    .bind(id_wolves)
+    .bind(email)
+    .fetch_optional(db)
+    .await
+  }
 }
 
 pub mod verify {
diff --git a/src/lib.rs b/src/lib.rs
index 5923151..05f6125 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,6 +38,8 @@ pub struct Config {
 
   // wolves API base for clubs/socs
   pub wolves_url: String,
+  // API key for accessing more general resources
+  pub wolves_api: String,
 }
 impl TypeMapKey for Config {
   type Value = Arc<RwLock<Config>>;
@@ -63,6 +65,7 @@ pub fn get_config() -> Config {
     mail_user: "".to_string(),
     mail_pass: "".to_string(),
     wolves_url: "".to_string(),
+    wolves_api: "".to_string(),
   };
 
   if let Ok(x) = env::var("DATABASE_HOME") {
@@ -92,6 +95,9 @@ pub fn get_config() -> Config {
   if let Ok(x) = env::var("WOLVES_URL") {
     config.wolves_url = x.trim().to_string();
   }
+  if let Ok(x) = env::var("WOLVES_API") {
+    config.wolves_api = x.trim().to_string();
+  }
 
   config
 }
@@ -526,36 +532,8 @@ pub mod get_data {
   use super::*;
   use crate::set_roles::update_server;
   use std::collections::BTreeMap;
+  use wolves_oxidised::WolvesUser;
 
-  #[derive(Deserialize, Serialize, Debug)]
-  struct WolvesResultUser {
-    committee: String,
-    member_id: String,
-    first_name: String,
-    last_name: String,
-    contact_email: String,
-    opt_in_email: String,
-    student_id: Option<String>,
-    note: Option<String>,
-    expiry: String,
-    requested: String,
-    approved: String,
-    sitename: String,
-    domain: String,
-  }
-
-  #[derive(Deserialize, Serialize, Debug)]
-  struct WolvesResult {
-    success: i8,
-    result: Vec<WolvesResultUser>,
-  }
-
-  #[derive(Deserialize, Serialize, Debug)]
-  struct WolvesResultLocal {
-    pub id_wolves: String,
-    pub email: String,
-    pub expiry: String,
-  }
   pub async fn get_wolves(ctx: &Context) {
     let db_lock = {
       let data_read = ctx.data.read().await;
@@ -569,6 +547,9 @@ pub mod get_data {
     };
     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,
@@ -581,7 +562,7 @@ pub mod get_data {
 
       // list of users that need to be updated for this server
       let mut user_to_update = vec![];
-      for user in get_wolves_sub(&config, wolves_api).await {
+      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 => {
@@ -627,30 +608,7 @@ pub mod get_data {
     .unwrap_or_default()
   }
 
-  async fn get_wolves_sub(config: &Config, wolves_api: &str) -> Vec<WolvesResultUser> {
-    if config.wolves_url.is_empty() {
-      return vec![];
-    }
-
-    // get wolves data
-    if let Ok(mut res) = surf::post(&config.wolves_url).header("X-AM-Identity", wolves_api).await {
-      if let Ok(WolvesResult {
-        success,
-        result,
-      }) = res.body_json().await
-      {
-        if success != 1 {
-          return vec![];
-        }
-
-        return result;
-      }
-    }
-
-    vec![]
-  }
-
-  async fn add_users_wolves(db: &Pool<Sqlite>, user: &WolvesResultUser) {
+  async fn add_users_wolves(db: &Pool<Sqlite>, user: &WolvesUser) {
     // expiry
     match sqlx::query_as::<_, Wolves>(
       "
@@ -671,7 +629,7 @@ pub mod get_data {
       }
     }
   }
-  async fn add_users_server_members(db: &Pool<Sqlite>, server: &GuildId, user: &WolvesResultUser) {
+  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)