diff --git a/Cargo.lock b/Cargo.lock index 40fe0ca..69e0037 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,6 +233,21 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "async-recursion" version = "1.0.5" @@ -356,6 +371,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.48.5", +] + [[package]] name = "colored" version = "2.1.0" @@ -792,6 +821,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.5.0" @@ -905,6 +957,7 @@ version = "0.1.1" dependencies = [ "actix-web", "async-recursion", + "chrono", "derive_more", "ed25519-dalek", "hex", @@ -980,6 +1033,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1946,6 +2008,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/mellow/Cargo.toml b/mellow/Cargo.toml index 8274a9b..1a19fae 100644 --- a/mellow/Cargo.toml +++ b/mellow/Cargo.toml @@ -17,6 +17,7 @@ hex = "0.4.3" log = "0.4.20" tokio = { version = "1.34.0", features = ["full"] } serde = { version = "1.0.193", features = ["derive"] } +chrono = "0.4.31" reqwest = { version = "0.11.22", features = ["json"] } actix-web = "4.4.0" postgrest = "1.6.0" diff --git a/mellow/src/database.rs b/mellow/src/database.rs index 4bd982a..ef6b29f 100644 --- a/mellow/src/database.rs +++ b/mellow/src/database.rs @@ -46,8 +46,9 @@ impl UserConnection { } } -#[derive(Deserialize, Clone, Debug)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct UserServerConnection { + pub id: String, pub connection: UserConnection } @@ -59,7 +60,7 @@ pub struct UserResponse { pub async fn get_users_by_discord(ids: Vec, server_id: String) -> Vec { serde_json::from_str(&DATABASE.from("user_connections") - .select("sub,user:users(id,connections:mellow_user_server_connections(connection:user_connections(sub,type,username,display_name)))") + .select("sub,user:users(id,connections:mellow_user_server_connections(id,connection:user_connections(sub,type,username,display_name)))") .in_("sub", ids) .eq("users.mellow_user_server_connections.server_id", server_id) .execute().await.unwrap().text().await.unwrap() diff --git a/mellow/src/server.rs b/mellow/src/server.rs index 5c48927..0a7f51c 100644 --- a/mellow/src/server.rs +++ b/mellow/src/server.rs @@ -72,6 +72,7 @@ pub async fn send_logs(server: &Server, logs: Vec) { embeds.push(Embed { title: Some(format!("{} synced their profile", data.member.user.global_name.clone().unwrap_or(data.member.user.username))), author: Some(EmbedAuthor { + url: Some(format!("https://hakumi.cafe/mellow/server/{}/member/{}", server.id, data.member.user.id)), name: data.member.user.global_name, icon_url: data.member.avatar.or(data.member.user.avatar).map(|x| format!("https://cdn.discordapp.com/avatars/{}/{x}.webp?size=48", data.member.user.id)), ..Default::default() diff --git a/mellow/src/syncing.rs b/mellow/src/syncing.rs index 30e6ab1..9750db9 100644 --- a/mellow/src/syncing.rs +++ b/mellow/src/syncing.rs @@ -7,7 +7,7 @@ use async_recursion::async_recursion; use crate::{ roblox::get_user_group_roles, discord::{ DiscordRole, DiscordMember, DiscordModifyMemberPayload, modify_member, get_guild_roles }, - database::{ User, Server, UserResponse, UserConnection, ProfileSyncAction, UserConnectionKind, ProfileSyncActionKind, ProfileSyncActionRequirementKind, ProfileSyncActionRequirementsKind, get_server } + database::{ User, Server, UserResponse, UserConnection, ProfileSyncAction, UserConnectionKind, UserServerConnection, ProfileSyncActionKind, ProfileSyncActionRequirementKind, ProfileSyncActionRequirementsKind, DATABASE, get_server } }; #[derive(Debug, Serialize)] @@ -110,7 +110,7 @@ pub async fn sync_member(user: Option<&User>, member: &DiscordMember, server: &S let mut roles = member.roles.clone(); let mut role_changes: Vec = vec![]; let mut requirement_cache: HashMap = HashMap::new(); - let mut used_connections: Vec = vec![]; + let mut used_connections: Vec = vec![]; let actions2 = server.actions.clone(); for action in server.actions.iter() { @@ -174,12 +174,25 @@ pub async fn sync_member(user: Option<&User>, member: &DiscordMember, server: &S }).await; } + if !used_connections.is_empty() { + let connections = used_connections.clone(); + tokio::spawn(async move { + DATABASE + .from("mellow_user_server_connections") + .update(format!(r#"{{ "last_used_at": "{}" }}"#, chrono::Local::now())) + .in_("id", connections.iter().map(|x| x.id.clone())) + .execute() + .await + .unwrap(); + }); + } + SyncMemberResult { server: server.clone(), role_changes, profile_changed, nickname_change, - relevant_connections: used_connections + relevant_connections: used_connections.into_iter().map(|x| x.connection).collect() } } @@ -190,7 +203,7 @@ pub async fn member_meets_action_requirements( all_actions: &Vec, connection_metadata: &ConnectionMetadata, cache: &mut HashMap, - used_connections: &mut Vec + used_connections: &mut Vec ) -> bool { let mut total_met = 0; let requires_one = matches!(action.requirements_type, ProfileSyncActionRequirementsKind::MeetOne); @@ -202,8 +215,8 @@ pub async fn member_meets_action_requirements( ProfileSyncActionRequirementKind::RobloxHaveGroupRankInRange => { let connection = user.and_then(|x| x.connections.iter().find(|x| matches!(x.connection.kind, UserConnectionKind::Roblox))); if let Some(connection) = connection.cloned() { - if !used_connections.contains(&connection.connection) { - used_connections.push(connection.connection); + if !used_connections.contains(&connection) { + used_connections.push(connection); } }