You've already forked AstralRinth
forked from didirus/AstralRinth
Friends system for app (#2958)
* Friends system for app * Fix impl issues * move friends to in-memory store
This commit is contained in:
@@ -18,7 +18,7 @@ const FLOWS_NAMESPACE: &str = "flows";
|
||||
pub enum Flow {
|
||||
OAuth {
|
||||
user_id: Option<UserId>,
|
||||
url: Option<String>,
|
||||
url: String,
|
||||
provider: AuthProvider,
|
||||
},
|
||||
Login2FA {
|
||||
|
||||
132
apps/labrinth/src/database/models/friend_item.rs
Normal file
132
apps/labrinth/src/database/models/friend_item.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use crate::database::models::UserId;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
pub struct FriendItem {
|
||||
pub user_id: UserId,
|
||||
pub friend_id: UserId,
|
||||
pub created: DateTime<Utc>,
|
||||
pub accepted: bool,
|
||||
}
|
||||
|
||||
impl FriendItem {
|
||||
pub async fn insert(
|
||||
&self,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"
|
||||
INSERT INTO friends (user_id, friend_id, created, accepted)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
",
|
||||
self.user_id.0,
|
||||
self.friend_id.0,
|
||||
self.created,
|
||||
self.accepted,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_friend<'a, E>(
|
||||
user_id: UserId,
|
||||
friend_id: UserId,
|
||||
exec: E,
|
||||
) -> Result<Option<FriendItem>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let friend = sqlx::query!(
|
||||
"
|
||||
SELECT f.user_id, f.friend_id, f.created, f.accepted
|
||||
FROM friends f
|
||||
WHERE (f.user_id = $1 AND f.friend_id = $2) OR (f.user_id = $2 AND f.friend_id = $1)
|
||||
",
|
||||
user_id.0,
|
||||
friend_id.0,
|
||||
)
|
||||
.fetch_optional(exec)
|
||||
.await?
|
||||
.map(|row| FriendItem {
|
||||
user_id: UserId(row.user_id),
|
||||
friend_id: UserId(row.friend_id),
|
||||
created: row.created,
|
||||
accepted: row.accepted,
|
||||
});
|
||||
|
||||
Ok(friend)
|
||||
}
|
||||
|
||||
pub async fn update_friend(
|
||||
user_id: UserId,
|
||||
friend_id: UserId,
|
||||
accepted: bool,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE friends
|
||||
SET accepted = $3
|
||||
WHERE (user_id = $1 AND friend_id = $2) OR (user_id = $2 AND friend_id = $1)
|
||||
",
|
||||
user_id.0,
|
||||
friend_id.0,
|
||||
accepted,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_user_friends<'a, E>(
|
||||
user_id: UserId,
|
||||
accepted: Option<bool>,
|
||||
exec: E,
|
||||
) -> Result<Vec<FriendItem>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let friends = sqlx::query!(
|
||||
"
|
||||
SELECT f.user_id, f.friend_id, f.created, f.accepted
|
||||
FROM friends f
|
||||
WHERE f.user_id = $1 OR f.friend_id = $1
|
||||
",
|
||||
user_id.0,
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|row| FriendItem {
|
||||
user_id: UserId(row.user_id),
|
||||
friend_id: UserId(row.friend_id),
|
||||
created: row.created,
|
||||
accepted: row.accepted,
|
||||
})
|
||||
.filter(|x| accepted.map(|y| y == x.accepted).unwrap_or(true))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(friends)
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
user_id: UserId,
|
||||
friend_id: UserId,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM friends
|
||||
WHERE (user_id = $1 AND friend_id = $2) OR (user_id = $2 AND friend_id = $1)
|
||||
",
|
||||
user_id.0 as i64,
|
||||
friend_id.0 as i64,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ pub mod categories;
|
||||
pub mod charge_item;
|
||||
pub mod collection_item;
|
||||
pub mod flow_item;
|
||||
pub mod friend_item;
|
||||
pub mod ids;
|
||||
pub mod image_item;
|
||||
pub mod legacy_loader_fields;
|
||||
|
||||
@@ -44,6 +44,8 @@ pub struct User {
|
||||
pub created: DateTime<Utc>,
|
||||
pub role: String,
|
||||
pub badges: Badges,
|
||||
|
||||
pub allow_friend_requests: bool,
|
||||
}
|
||||
|
||||
impl User {
|
||||
@@ -58,13 +60,13 @@ impl User {
|
||||
avatar_url, raw_avatar_url, bio, created,
|
||||
github_id, discord_id, gitlab_id, google_id, steam_id, microsoft_id,
|
||||
email_verified, password, paypal_id, paypal_country, paypal_email,
|
||||
venmo_handle, stripe_customer_id
|
||||
venmo_handle, stripe_customer_id, allow_friend_requests
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7,
|
||||
$8, $9, $10, $11, $12, $13,
|
||||
$14, $15, $16, $17, $18, $19, $20
|
||||
$14, $15, $16, $17, $18, $19, $20, $21
|
||||
)
|
||||
",
|
||||
self.id as UserId,
|
||||
@@ -86,7 +88,8 @@ impl User {
|
||||
self.paypal_country,
|
||||
self.paypal_email,
|
||||
self.venmo_handle,
|
||||
self.stripe_customer_id
|
||||
self.stripe_customer_id,
|
||||
self.allow_friend_requests,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
@@ -172,7 +175,7 @@ impl User {
|
||||
created, role, badges,
|
||||
github_id, discord_id, gitlab_id, google_id, steam_id, microsoft_id,
|
||||
email_verified, password, totp_secret, paypal_id, paypal_country, paypal_email,
|
||||
venmo_handle, stripe_customer_id
|
||||
venmo_handle, stripe_customer_id, allow_friend_requests
|
||||
FROM users
|
||||
WHERE id = ANY($1) OR LOWER(username) = ANY($2)
|
||||
",
|
||||
@@ -205,6 +208,7 @@ impl User {
|
||||
venmo_handle: u.venmo_handle,
|
||||
stripe_customer_id: u.stripe_customer_id,
|
||||
totp_secret: u.totp_secret,
|
||||
allow_friend_requests: u.allow_friend_requests,
|
||||
};
|
||||
|
||||
acc.insert(u.id, (Some(u.username), user));
|
||||
@@ -643,6 +647,16 @@ impl User {
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM friends
|
||||
WHERE user_id = $1 OR friend_id = $1
|
||||
",
|
||||
id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM user_backup_codes
|
||||
|
||||
@@ -547,6 +547,23 @@ impl RedisConnection {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn get_many(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
ids: &[String],
|
||||
) -> Result<Vec<Option<String>>, DatabaseError> {
|
||||
let mut cmd = cmd("MGET");
|
||||
redis_args(
|
||||
&mut cmd,
|
||||
ids.iter()
|
||||
.map(|x| format!("{}_{}:{}", self.meta_namespace, namespace, x))
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
);
|
||||
let res = redis_execute(&mut cmd, &mut self.connection).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn get_deserialized_from_json<R>(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
@@ -561,6 +578,22 @@ impl RedisConnection {
|
||||
.and_then(|x| serde_json::from_str(&x).ok()))
|
||||
}
|
||||
|
||||
pub async fn get_many_deserialized_from_json<R>(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
ids: &[String],
|
||||
) -> Result<Vec<Option<R>>, DatabaseError>
|
||||
where
|
||||
R: for<'a> serde::Deserialize<'a>,
|
||||
{
|
||||
Ok(self
|
||||
.get_many(namespace, ids)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| x.and_then(|val| serde_json::from_str::<R>(&val).ok()))
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub async fn delete<T1>(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
|
||||
Reference in New Issue
Block a user