1use google_docs1::hyper_rustls::HttpsConnector;
2use google_docs1::hyper_util::client::legacy::connect::HttpConnector;
3use std::sync::Arc;
5use tokio::sync::{Mutex, OnceCell};
6pub type Error = Box<dyn std::error::Error + Send + Sync>;
7pub type Context<'a> = poise::Context<'a, Data, Error>;
8pub type SciolyHubs<'a> = (
10 &'a google_docs1::api::Docs<HttpsConnector<HttpConnector>>,
11 &'a google_drive3::api::DriveHub<HttpsConnector<HttpConnector>>,
12 &'a google_sheets4::api::Sheets<HttpsConnector<HttpConnector>>,
13);
14#[derive(Debug)]
17pub struct Data {}
18
19use user_handling::SciolyUser;
20
21pub enum Perms {
22 Viewer(),
23 Commenter(),
24 Editor(),
25 Owner(),
26}
27
28#[derive(Debug, serde::Serialize, serde::Deserialize)]
29pub struct Thing {
30 pub users: Vec<SciolyUser>,
31}
32
33pub mod user_handling {
34 use crate::utils::{Context, Error};
35
36 #[derive(Debug, serde::Serialize, serde::Deserialize)]
37 pub struct SciolyUser {
38 pub userid: String,
39 pub default_email: String,
40 pub team: char,
41 pub events: Vec<String>,
42 pub officer: bool,
43 }
44
45 impl Default for SciolyUser {
46 fn default() -> Self {
47 Self {
48 userid: String::from(""),
49 default_email: String::from(""),
50 team: 'z',
51 events: Vec::new(),
52 officer: false,
53 }
54 }
55 }
56
57 pub fn get_user_data(file_path: &str) -> Result<Vec<SciolyUser>, Error> {
58 let data = std::fs::read_to_string(file_path).unwrap();
59 let users: crate::utils::Thing = serde_json::from_str(&data).unwrap();
60 Ok(users.users)
61 }
62
63 pub fn write_user_data(file_path: &str, users: Vec<SciolyUser>) -> Result<(), Error> {
64 std::fs::write(
65 file_path,
66 serde_json::to_string(&crate::utils::Thing { users })?,
67 )?;
68 Ok(())
69 }
70
71 pub fn find_user(userid: &str) -> Result<SciolyUser, Error> {
72 let users = get_user_data("userdata.json")?;
73 for user in users {
74 if user.userid == userid {
75 return Ok(user);
76 }
77 }
78 Err("User not found".into())
79 }
80
81 pub fn get_event_partners(
82 event: &String,
83 userid: &str,
84 team: &char,
85 ) -> Result<Vec<SciolyUser>, Error> {
86 let mut partners = Vec::new();
87 let users = get_user_data("userdata.json")?;
88 for user in users {
89 if &user.team == team && user.events.contains(event) && user.userid != userid {
90 partners.push(user);
91 }
92 }
93 Ok(partners)
94 }
95
96 pub fn get_officers_emails() -> Result<Vec<String>, Error> {
97 let mut emails = Vec::new();
98 let users = get_user_data("userdata.json")?;
99 for user in users {
100 if user.officer {
101 emails.push(user.default_email);
102 }
103 }
104 Ok(emails)
105 }
106 pub fn get_event_id_list(ctx: Context<'_>) -> Result<Vec<(String, String)>, Error> {
107 let mut event_id_list = Vec::new();
108 let event_list = match find_user(&ctx.author().id.to_string()) {
109 Ok(user) => user.events,
110 Err(_) => std::panic::panic_any(
111 "No events found; please register with `/set_defaults`!, or check your roles in this server.",
112 ),
113 };
114
115 for event in event_list {
116 let event_id = format!("{}{}", &ctx.id(), &event);
117 event_id_list.push((event, event_id));
118 }
119 Ok(event_id_list)
120 }
121}
122
123pub mod server_handling {
124 use crate::utils::Error;
125 #[derive(Debug, serde::Serialize, serde::Deserialize)]
126 pub struct Server {
127 pub server_id: String,
128 pub server_name: String,
129 pub server_email: String,
130 pub tests_file_id: String,
131 pub pc_file_id: String,
132 }
133
134 #[derive(Debug, serde::Serialize, serde::Deserialize)]
135 pub struct AllData {
136 pub servers: Vec<Server>,
137 }
138
139 pub fn get_server_data(file_path: &str) -> Result<AllData, Error> {
140 let data = std::fs::read_to_string(file_path).unwrap();
141 let server: AllData = serde_json::from_str(&data).unwrap();
142 Ok(server)
143 }
144
145 pub fn write_server_data(file_path: &str, to_write: AllData) -> Result<(), Error> {
146 std::fs::write(file_path, serde_json::to_string(&to_write)?)?;
147 Ok(())
148 }
149
150 pub fn get_server(server_id: &str) -> Result<Server, Error> {
151 let servers = get_server_data("serverdata.json")?;
152 for server in servers.servers {
153 if server.server_id == server_id {
154 return Ok(server);
155 }
156 }
157 Err("Server not found".into())
158 }
159}
160
161pub mod events {
162 use rust_fuzzy_search::fuzzy_search_sorted;
163
164 static EVENT_LIST: [&str; 30] = [
165 "Air Trajectory",
166 "Anatomy and Physiology",
167 "Astronomy",
168 "Bungee Drop",
169 "Chemistry Lab",
170 "Codebusters",
171 "Crime Busters",
172 "Disease Detectives",
173 "Dynamic Planet",
174 "Ecology",
175 "Electric Vehicle",
176 "Entomology",
177 "Experimental Design",
178 "Forensics",
179 "Fossils",
180 "Geologic Mapping",
181 "Helicopter",
182 "Materials Science",
183 "Metric Mastery",
184 "Microbe Mission",
185 "Mission Possible",
186 "Optics",
187 "Potions and Poisons",
188 "Reach For The Stars",
189 "Road Scholar",
190 "Robot Tour",
191 "Scrambler",
192 "Tower",
193 "Wind Power",
194 "Write It Do It",
195 ];
196
197 pub enum Division {
198 B,
199 C,
200 }
201
202 #[derive(Debug)]
203 pub enum Types {
204 Build,
205 Hybrid,
206 Study,
207 }
208
209 impl std::fmt::Display for Types {
210 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
211 match self {
212 Types::Build => write!(f, "Build"),
213 Types::Hybrid => write!(f, "Hybrid"),
214 Types::Study => write!(f, "Study"),
215 }
216 }
217 }
218
219 pub fn extract_events(event_vec: &Vec<String>) -> Vec<String> {
220 let mut events = Vec::new();
221 for role in event_vec {
222 for event in &EVENT_LIST {
223 if rust_fuzzy_search::fuzzy_compare(role, event) > 0.9 {
224 events.push(event.to_string());
225 }
226 }
227 }
228 events
229 }
230
231 pub fn find_closest_event_name(in_event: String) -> Result<String, crate::utils::Error> {
232 let events = fuzzy_search_sorted(&in_event, &EVENT_LIST);
233 if &in_event == "widi" {
234 Ok("Write It Do It".to_string())
235 } else {
236 Ok(events[0].0.to_string())
240 }
241 }
242
243 pub fn match_event_type(event: &str) -> Types {
244 match event {
245 "Air Trajectory" => Types::Build,
246 "Anatomy and Physiology" => Types::Study,
247 "Astronomy" => Types::Study,
248 "Bungee Drop" => Types::Build,
249 "Chemistry Lab" => Types::Hybrid,
250 "Codebusters" => Types::Study,
251 "Crime Busters" => Types::Study,
252 "Disease Detectives" => Types::Study,
253 "Dynamic Planet" => Types::Study,
254 "Ecology" => Types::Study,
255 "Electric Vehicle" => Types::Build,
256 "Entomology" => Types::Study,
257 "Experimental Design" => Types::Hybrid,
258 "Forensics" => Types::Hybrid,
259 "Fossils" => Types::Study,
260 "Geologic Mapping" => Types::Study,
261 "Helicopter" => Types::Build,
262 "Materials Science" => Types::Hybrid,
263 "Metric Mastery" => Types::Study,
264 "Microbe Mission" => Types::Study,
265 "Mission Possible" => Types::Build,
266 "Optics" => Types::Hybrid,
267 "Potions and Poisons" => Types::Study,
268 "Reach For The Stars" => Types::Study,
269 "Road Scholar" => Types::Study,
270 "Robot Tour" => Types::Build,
271 "Scrambler" => Types::Build,
272 "Tower" => Types::Build,
273 "Wind Power" => Types::Build,
274 "Write It Do It" => Types::Hybrid,
275 _ => Types::Study,
276 }
277 }
278}