scioly_bot/
utils.rs

1use google_docs1::hyper_rustls::HttpsConnector;
2use google_docs1::hyper_util::client::legacy::connect::HttpConnector;
3//use mistralrs::Model;
4use 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>;
8//pub type SharedModel = Arc<Mutex<Model>>;
9pub 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//pub static MODEL: OnceCell<SharedModel> = OnceCell::const_new();
15
16#[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            //for (event, score) in &sorted_vec {
237            //    println!("{:?} {:?}", event, score);
238            //}
239            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}