Compare commits
No commits in common. "e8a9857e19a9d6b9a09ea41279a33cb1d47754d8" and "ac3e7e242b049b7402534e292c1c081701029211" have entirely different histories.
e8a9857e19
...
ac3e7e242b
16 changed files with 38 additions and 484 deletions
|
@ -1,4 +0,0 @@
|
||||||
-- This file should undo anything in `up.sql`
|
|
||||||
DROP TABLE friend_requests;
|
|
||||||
DROP FUNCTION check_friend_request;
|
|
||||||
DROP TABLE friends;
|
|
|
@ -1,35 +0,0 @@
|
||||||
-- Your SQL goes here
|
|
||||||
CREATE TABLE friends (
|
|
||||||
uuid1 UUID REFERENCES users(uuid),
|
|
||||||
uuid2 UUID REFERENCES users(uuid),
|
|
||||||
accepted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
||||||
PRIMARY KEY (uuid1, uuid2),
|
|
||||||
CHECK (uuid1 < uuid2)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE friend_requests (
|
|
||||||
sender UUID REFERENCES users(uuid),
|
|
||||||
receiver UUID REFERENCES users(uuid),
|
|
||||||
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
||||||
PRIMARY KEY (sender, receiver),
|
|
||||||
CHECK (sender <> receiver)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Create a function to check for existing friendships
|
|
||||||
CREATE FUNCTION check_friend_request()
|
|
||||||
RETURNS TRIGGER AS $$
|
|
||||||
BEGIN
|
|
||||||
IF EXISTS (
|
|
||||||
SELECT 1 FROM friends
|
|
||||||
WHERE (uuid1, uuid2) = (LEAST(NEW.sender, NEW.receiver), GREATEST(NEW.sender, NEW.receiver))
|
|
||||||
) THEN
|
|
||||||
RAISE EXCEPTION 'Users are already friends';
|
|
||||||
END IF;
|
|
||||||
RETURN NEW;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
-- Create the trigger
|
|
||||||
CREATE TRIGGER prevent_friend_request_conflict
|
|
||||||
BEFORE INSERT OR UPDATE ON friend_requests
|
|
||||||
FOR EACH ROW EXECUTE FUNCTION check_friend_request();
|
|
|
@ -38,9 +38,7 @@ pub async fn res(req: HttpRequest, data: web::Data<Data>) -> Result<HttpResponse
|
||||||
refresh_token_cookie.make_removal();
|
refresh_token_cookie.make_removal();
|
||||||
|
|
||||||
if deleted == 0 {
|
if deleted == 0 {
|
||||||
return Ok(HttpResponse::NotFound()
|
return Ok(HttpResponse::NotFound().cookie(refresh_token_cookie).finish())
|
||||||
.cookie(refresh_token_cookie)
|
|
||||||
.finish());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().cookie(refresh_token_cookie).finish())
|
Ok(HttpResponse::Ok().cookie(refresh_token_cookie).finish())
|
||||||
|
|
|
@ -83,9 +83,7 @@ pub async fn ws(
|
||||||
|
|
||||||
let message_body: MessageBody = serde_json::from_str(&text)?;
|
let message_body: MessageBody = serde_json::from_str(&text)?;
|
||||||
|
|
||||||
let message = channel
|
let message = channel.new_message(&data, uuid, message_body.message, message_body.reply_to).await?;
|
||||||
.new_message(&data, uuid, message_body.message, message_body.reply_to)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
redis::cmd("PUBLISH")
|
redis::cmd("PUBLISH")
|
||||||
.arg(&[channel_uuid.to_string(), serde_json::to_string(&message)?])
|
.arg(&[channel_uuid.to_string(), serde_json::to_string(&message)?])
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
Data,
|
Data,
|
||||||
api::v1::auth::check_access_token,
|
api::v1::auth::check_access_token,
|
||||||
error::Error,
|
error::Error,
|
||||||
objects::{Me, Member},
|
objects::Member,
|
||||||
utils::{get_auth_header, global_checks},
|
utils::{get_auth_header, global_checks},
|
||||||
};
|
};
|
||||||
use ::uuid::Uuid;
|
use ::uuid::Uuid;
|
||||||
|
@ -28,9 +28,7 @@ pub async fn get(
|
||||||
|
|
||||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||||
|
|
||||||
let me = Me::get(&mut conn, uuid).await?;
|
let members = Member::fetch_all(&data, guild_uuid).await?;
|
||||||
|
|
||||||
let members = Member::fetch_all(&data, &me, guild_uuid).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(members))
|
Ok(HttpResponse::Ok().json(members))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
use ::uuid::Uuid;
|
|
||||||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
pub mod uuid;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
Data,
|
|
||||||
api::v1::auth::check_access_token,
|
|
||||||
error::Error,
|
|
||||||
objects::Me,
|
|
||||||
utils::{get_auth_header, global_checks},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Returns a list of users that are your friends
|
|
||||||
#[get("/friends")]
|
|
||||||
pub async fn get(req: HttpRequest, data: web::Data<Data>) -> Result<HttpResponse, Error> {
|
|
||||||
let headers = req.headers();
|
|
||||||
|
|
||||||
let auth_header = get_auth_header(headers)?;
|
|
||||||
|
|
||||||
let mut conn = data.pool.get().await?;
|
|
||||||
|
|
||||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
|
||||||
|
|
||||||
global_checks(&data, uuid).await?;
|
|
||||||
|
|
||||||
let me = Me::get(&mut conn, uuid).await?;
|
|
||||||
|
|
||||||
let friends = me.get_friends(&data).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(friends))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct UserReq {
|
|
||||||
uuid: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `POST /api/v1/me/friends` Send friend request
|
|
||||||
///
|
|
||||||
/// requires auth? yes
|
|
||||||
///
|
|
||||||
/// ### Request Example:
|
|
||||||
/// ```
|
|
||||||
/// json!({
|
|
||||||
/// "uuid": "155d2291-fb23-46bd-a656-ae7c5d8218e6",
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
/// NOTE: UUIDs in this response are made using `uuidgen`, UUIDs made by the actual backend will be UUIDv7 and have extractable timestamps
|
|
||||||
///
|
|
||||||
/// ### Responses
|
|
||||||
/// 200 Success
|
|
||||||
///
|
|
||||||
/// 404 Not Found
|
|
||||||
///
|
|
||||||
/// 400 Bad Request (usually means users are already friends)
|
|
||||||
///
|
|
||||||
#[post("/friends")]
|
|
||||||
pub async fn post(
|
|
||||||
req: HttpRequest,
|
|
||||||
json: web::Json<UserReq>,
|
|
||||||
data: web::Data<Data>,
|
|
||||||
) -> Result<HttpResponse, Error> {
|
|
||||||
let headers = req.headers();
|
|
||||||
|
|
||||||
let auth_header = get_auth_header(headers)?;
|
|
||||||
|
|
||||||
let mut conn = data.pool.get().await?;
|
|
||||||
|
|
||||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
|
||||||
|
|
||||||
global_checks(&data, uuid).await?;
|
|
||||||
|
|
||||||
let me = Me::get(&mut conn, uuid).await?;
|
|
||||||
|
|
||||||
me.add_friend(&mut conn, json.uuid).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().finish())
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
use actix_web::{HttpRequest, HttpResponse, delete, web};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
Data,
|
|
||||||
api::v1::auth::check_access_token,
|
|
||||||
error::Error,
|
|
||||||
objects::Me,
|
|
||||||
utils::{get_auth_header, global_checks},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[delete("/friends/{uuid}")]
|
|
||||||
pub async fn delete(
|
|
||||||
req: HttpRequest,
|
|
||||||
path: web::Path<(Uuid,)>,
|
|
||||||
data: web::Data<Data>,
|
|
||||||
) -> Result<HttpResponse, Error> {
|
|
||||||
let headers = req.headers();
|
|
||||||
|
|
||||||
let auth_header = get_auth_header(headers)?;
|
|
||||||
|
|
||||||
let mut conn = data.pool.get().await?;
|
|
||||||
|
|
||||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
|
||||||
|
|
||||||
global_checks(&data, uuid).await?;
|
|
||||||
|
|
||||||
let me = Me::get(&mut conn, uuid).await?;
|
|
||||||
|
|
||||||
me.remove_friend(&mut conn, path.0).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().finish())
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@ use crate::{
|
||||||
utils::{get_auth_header, global_checks},
|
utils::{get_auth_header, global_checks},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod friends;
|
|
||||||
mod guilds;
|
mod guilds;
|
||||||
|
|
||||||
pub fn web() -> Scope {
|
pub fn web() -> Scope {
|
||||||
|
@ -18,9 +17,6 @@ pub fn web() -> Scope {
|
||||||
.service(get)
|
.service(get)
|
||||||
.service(update)
|
.service(update)
|
||||||
.service(guilds::get)
|
.service(guilds::get)
|
||||||
.service(friends::get)
|
|
||||||
.service(friends::post)
|
|
||||||
.service(friends::uuid::delete)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("")]
|
#[get("")]
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
Data,
|
Data,
|
||||||
api::v1::auth::check_access_token,
|
api::v1::auth::check_access_token,
|
||||||
error::Error,
|
error::Error,
|
||||||
objects::{Me, User},
|
objects::User,
|
||||||
utils::{get_auth_header, global_checks},
|
utils::{get_auth_header, global_checks},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,9 +45,7 @@ pub async fn get(
|
||||||
|
|
||||||
global_checks(&data, uuid).await?;
|
global_checks(&data, uuid).await?;
|
||||||
|
|
||||||
let me = Me::get(&mut conn, uuid).await?;
|
let user = User::fetch_one(&data, user_uuid).await?;
|
||||||
|
|
||||||
let user = User::fetch_one_with_friendship(&data, &me, user_uuid).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(user))
|
Ok(HttpResponse::Ok().json(user))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use diesel::{Queryable, Selectable};
|
|
||||||
use serde::Serialize;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::schema::{friend_requests, friends};
|
|
||||||
|
|
||||||
#[derive(Serialize, Queryable, Selectable, Clone)]
|
|
||||||
#[diesel(table_name = friends)]
|
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
|
||||||
pub struct Friend {
|
|
||||||
pub uuid1: Uuid,
|
|
||||||
pub uuid2: Uuid,
|
|
||||||
pub accepted_at: DateTime<Utc>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Queryable, Selectable, Clone)]
|
|
||||||
#[diesel(table_name = friend_requests)]
|
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
|
||||||
pub struct FriendRequest {
|
|
||||||
pub sender: Uuid,
|
|
||||||
pub receiver: Uuid,
|
|
||||||
pub requested_at: DateTime<Utc>,
|
|
||||||
}
|
|
|
@ -1,8 +1,5 @@
|
||||||
use actix_web::web::BytesMut;
|
use actix_web::web::BytesMut;
|
||||||
use diesel::{
|
use diesel::{ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper, update};
|
||||||
ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper, delete, insert_into,
|
|
||||||
update,
|
|
||||||
};
|
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
@ -12,8 +9,7 @@ use uuid::Uuid;
|
||||||
use crate::{
|
use crate::{
|
||||||
Conn, Data,
|
Conn, Data,
|
||||||
error::Error,
|
error::Error,
|
||||||
objects::{Friend, FriendRequest, User},
|
schema::{guild_members, guilds, users},
|
||||||
schema::{friend_requests, friends, guild_members, guilds, users},
|
|
||||||
utils::{EMAIL_REGEX, USERNAME_REGEX, image_check},
|
utils::{EMAIL_REGEX, USERNAME_REGEX, image_check},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,10 +124,7 @@ impl Me {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_username(&mut self, data: &Data, new_username: String) -> Result<(), Error> {
|
pub async fn set_username(&mut self, data: &Data, new_username: String) -> Result<(), Error> {
|
||||||
if !USERNAME_REGEX.is_match(&new_username)
|
if !USERNAME_REGEX.is_match(&new_username) || new_username.len() < 3 || new_username.len() > 32 {
|
||||||
|| new_username.len() < 3
|
|
||||||
|| new_username.len() > 32
|
|
||||||
{
|
|
||||||
return Err(Error::BadRequest("Invalid username".to_string()));
|
return Err(Error::BadRequest("Invalid username".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,11 +153,13 @@ impl Me {
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut conn = data.pool.get().await?;
|
let mut conn = data.pool.get().await?;
|
||||||
|
|
||||||
let new_display_name_option = if new_display_name.is_empty() {
|
let new_display_name_option;
|
||||||
None
|
|
||||||
|
if new_display_name.is_empty() {
|
||||||
|
new_display_name_option = None;
|
||||||
} else {
|
} else {
|
||||||
Some(new_display_name)
|
new_display_name_option = Some(new_display_name)
|
||||||
};
|
}
|
||||||
|
|
||||||
use users::dsl;
|
use users::dsl;
|
||||||
update(users::table)
|
update(users::table)
|
||||||
|
@ -241,179 +236,4 @@ impl Me {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn friends_with(
|
|
||||||
&self,
|
|
||||||
conn: &mut Conn,
|
|
||||||
user_uuid: Uuid,
|
|
||||||
) -> Result<Option<Friend>, Error> {
|
|
||||||
use friends::dsl;
|
|
||||||
|
|
||||||
let friends: Vec<Friend> = if self.uuid < user_uuid {
|
|
||||||
load_or_empty(
|
|
||||||
dsl::friends
|
|
||||||
.filter(dsl::uuid1.eq(self.uuid))
|
|
||||||
.filter(dsl::uuid2.eq(user_uuid))
|
|
||||||
.load(conn)
|
|
||||||
.await,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
load_or_empty(
|
|
||||||
dsl::friends
|
|
||||||
.filter(dsl::uuid1.eq(user_uuid))
|
|
||||||
.filter(dsl::uuid2.eq(self.uuid))
|
|
||||||
.load(conn)
|
|
||||||
.await,
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
|
|
||||||
if friends.is_empty() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(friends[0].clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn add_friend(&self, conn: &mut Conn, user_uuid: Uuid) -> Result<(), Error> {
|
|
||||||
if self.friends_with(conn, user_uuid).await?.is_some() {
|
|
||||||
// TODO: Check if another error should be used
|
|
||||||
return Err(Error::BadRequest("Already friends with user".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
use friend_requests::dsl;
|
|
||||||
|
|
||||||
let friend_request: Vec<FriendRequest> = load_or_empty(
|
|
||||||
dsl::friend_requests
|
|
||||||
.filter(dsl::sender.eq(user_uuid))
|
|
||||||
.filter(dsl::receiver.eq(self.uuid))
|
|
||||||
.load(conn)
|
|
||||||
.await,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
#[allow(clippy::get_first)]
|
|
||||||
if let Some(friend_request) = friend_request.get(0) {
|
|
||||||
use friends::dsl;
|
|
||||||
|
|
||||||
if self.uuid < user_uuid {
|
|
||||||
insert_into(friends::table)
|
|
||||||
.values((dsl::uuid1.eq(self.uuid), dsl::uuid2.eq(user_uuid)))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
insert_into(friends::table)
|
|
||||||
.values((dsl::uuid1.eq(user_uuid), dsl::uuid2.eq(self.uuid)))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
use friend_requests::dsl as frdsl;
|
|
||||||
|
|
||||||
delete(friend_requests::table)
|
|
||||||
.filter(frdsl::sender.eq(friend_request.sender))
|
|
||||||
.filter(frdsl::receiver.eq(friend_request.receiver))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
use friend_requests::dsl;
|
|
||||||
|
|
||||||
insert_into(friend_requests::table)
|
|
||||||
.values((dsl::sender.eq(self.uuid), dsl::receiver.eq(user_uuid)))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_friend(&self, conn: &mut Conn, user_uuid: Uuid) -> Result<(), Error> {
|
|
||||||
if self.friends_with(conn, user_uuid).await?.is_none() {
|
|
||||||
// TODO: Check if another error should be used
|
|
||||||
return Err(Error::BadRequest("Not friends with user".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
use friends::dsl;
|
|
||||||
|
|
||||||
if self.uuid < user_uuid {
|
|
||||||
delete(friends::table)
|
|
||||||
.filter(dsl::uuid1.eq(self.uuid))
|
|
||||||
.filter(dsl::uuid2.eq(user_uuid))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
delete(friends::table)
|
|
||||||
.filter(dsl::uuid1.eq(user_uuid))
|
|
||||||
.filter(dsl::uuid2.eq(self.uuid))
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_friends(&self, data: &Data) -> Result<Vec<User>, Error> {
|
|
||||||
use friends::dsl;
|
|
||||||
|
|
||||||
let mut conn = data.pool.get().await?;
|
|
||||||
|
|
||||||
let friends1 = load_or_empty(
|
|
||||||
dsl::friends
|
|
||||||
.filter(dsl::uuid1.eq(self.uuid))
|
|
||||||
.select(Friend::as_select())
|
|
||||||
.load(&mut conn)
|
|
||||||
.await,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let friends2 = load_or_empty(
|
|
||||||
dsl::friends
|
|
||||||
.filter(dsl::uuid2.eq(self.uuid))
|
|
||||||
.select(Friend::as_select())
|
|
||||||
.load(&mut conn)
|
|
||||||
.await,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let friend_futures = friends1.iter().map(async move |friend| {
|
|
||||||
User::fetch_one_with_friendship(data, self, friend.uuid2).await
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut friends = futures::future::try_join_all(friend_futures).await?;
|
|
||||||
|
|
||||||
let friend_futures = friends2.iter().map(async move |friend| {
|
|
||||||
User::fetch_one_with_friendship(data, self, friend.uuid1).await
|
|
||||||
});
|
|
||||||
|
|
||||||
friends.append(&mut futures::future::try_join_all(friend_futures).await?);
|
|
||||||
|
|
||||||
Ok(friends)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
pub async fn get_friend_requests(&self, conn: &mut Conn) -> Result<Vec<FriendRequest>, Error> {
|
|
||||||
use friend_requests::dsl;
|
|
||||||
|
|
||||||
let friend_request: Vec<FriendRequest> = load_or_empty(
|
|
||||||
dsl::friend_requests
|
|
||||||
.filter(dsl::receiver.eq(self.uuid))
|
|
||||||
.load(conn)
|
|
||||||
.await
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_friend_request(&self, conn: &mut Conn, user_uuid: Uuid) -> Result<Vec<FriendRequest>, Error> {
|
|
||||||
use friend_requests::dsl;
|
|
||||||
|
|
||||||
let friend_request: Vec<FriendRequest> = load_or_empty(
|
|
||||||
dsl::friend_requests
|
|
||||||
.filter(dsl::sender.eq(user_uuid))
|
|
||||||
.filter(dsl::receiver.eq(self.uuid))
|
|
||||||
.load(conn)
|
|
||||||
.await
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use uuid::Uuid;
|
||||||
use crate::{
|
use crate::{
|
||||||
Conn, Data,
|
Conn, Data,
|
||||||
error::Error,
|
error::Error,
|
||||||
objects::{Me, Permissions, Role},
|
objects::{Permissions, Role},
|
||||||
schema::guild_members,
|
schema::guild_members,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,14 +26,8 @@ pub struct MemberBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemberBuilder {
|
impl MemberBuilder {
|
||||||
pub async fn build(&self, data: &Data, me: Option<&Me>) -> Result<Member, Error> {
|
pub async fn build(&self, data: &Data) -> Result<Member, Error> {
|
||||||
let user;
|
let user = User::fetch_one(data, self.user_uuid).await?;
|
||||||
|
|
||||||
if let Some(me) = me {
|
|
||||||
user = User::fetch_one_with_friendship(data, me, self.user_uuid).await?;
|
|
||||||
} else {
|
|
||||||
user = User::fetch_one(data, self.user_uuid).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Member {
|
Ok(Member {
|
||||||
uuid: self.uuid,
|
uuid: self.uuid,
|
||||||
|
@ -100,12 +94,7 @@ impl Member {
|
||||||
Ok(member_builder)
|
Ok(member_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_one(
|
pub async fn fetch_one(data: &Data, user_uuid: Uuid, guild_uuid: Uuid) -> Result<Self, Error> {
|
||||||
data: &Data,
|
|
||||||
me: &Me,
|
|
||||||
user_uuid: Uuid,
|
|
||||||
guild_uuid: Uuid,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut conn = data.pool.get().await?;
|
let mut conn = data.pool.get().await?;
|
||||||
|
|
||||||
use guild_members::dsl;
|
use guild_members::dsl;
|
||||||
|
@ -116,10 +105,10 @@ impl Member {
|
||||||
.get_result(&mut conn)
|
.get_result(&mut conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
member.build(data, Some(me)).await
|
member.build(data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_all(data: &Data, me: &Me, guild_uuid: Uuid) -> Result<Vec<Self>, Error> {
|
pub async fn fetch_all(data: &Data, guild_uuid: Uuid) -> Result<Vec<Self>, Error> {
|
||||||
let mut conn = data.pool.get().await?;
|
let mut conn = data.pool.get().await?;
|
||||||
|
|
||||||
use guild_members::dsl;
|
use guild_members::dsl;
|
||||||
|
@ -133,7 +122,7 @@ impl Member {
|
||||||
|
|
||||||
let member_futures = member_builders
|
let member_futures = member_builders
|
||||||
.iter()
|
.iter()
|
||||||
.map(async move |m| m.build(data, Some(me)).await);
|
.map(async move |m| m.build(data).await);
|
||||||
|
|
||||||
futures::future::try_join_all(member_futures).await
|
futures::future::try_join_all(member_futures).await
|
||||||
}
|
}
|
||||||
|
@ -156,6 +145,6 @@ impl Member {
|
||||||
.execute(&mut conn)
|
.execute(&mut conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
member.build(data, None).await
|
member.build(data).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use uuid::Uuid;
|
||||||
|
|
||||||
mod channel;
|
mod channel;
|
||||||
mod email_token;
|
mod email_token;
|
||||||
mod friends;
|
|
||||||
mod guild;
|
mod guild;
|
||||||
mod invite;
|
mod invite;
|
||||||
mod me;
|
mod me;
|
||||||
|
@ -21,8 +20,6 @@ mod user;
|
||||||
|
|
||||||
pub use channel::Channel;
|
pub use channel::Channel;
|
||||||
pub use email_token::EmailToken;
|
pub use email_token::EmailToken;
|
||||||
pub use friends::Friend;
|
|
||||||
pub use friends::FriendRequest;
|
|
||||||
pub use guild::Guild;
|
pub use guild::Guild;
|
||||||
pub use invite::Invite;
|
pub use invite::Invite;
|
||||||
pub use me::Me;
|
pub use me::Me;
|
||||||
|
|
|
@ -1,40 +1,15 @@
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use diesel::{ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper};
|
use diesel::{ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{Conn, Data, error::Error, objects::Me, schema::users};
|
use crate::{Conn, Data, error::Error, schema::users};
|
||||||
|
|
||||||
use super::load_or_empty;
|
use super::load_or_empty;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Queryable, Selectable)]
|
#[derive(Deserialize, Serialize, Clone, Queryable, Selectable)]
|
||||||
#[diesel(table_name = users)]
|
#[diesel(table_name = users)]
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct UserBuilder {
|
|
||||||
uuid: Uuid,
|
|
||||||
username: String,
|
|
||||||
display_name: Option<String>,
|
|
||||||
avatar: Option<String>,
|
|
||||||
pronouns: Option<String>,
|
|
||||||
about: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserBuilder {
|
|
||||||
fn build(self) -> User {
|
|
||||||
User {
|
|
||||||
uuid: self.uuid,
|
|
||||||
username: self.username,
|
|
||||||
display_name: self.display_name,
|
|
||||||
avatar: self.avatar,
|
|
||||||
pronouns: self.pronouns,
|
|
||||||
about: self.about,
|
|
||||||
friends_since: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
|
||||||
pub struct User {
|
pub struct User {
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
username: String,
|
username: String,
|
||||||
|
@ -42,7 +17,6 @@ pub struct User {
|
||||||
avatar: Option<String>,
|
avatar: Option<String>,
|
||||||
pronouns: Option<String>,
|
pronouns: Option<String>,
|
||||||
about: Option<String>,
|
about: Option<String>,
|
||||||
friends_since: Option<DateTime<Utc>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
|
@ -54,53 +28,33 @@ impl User {
|
||||||
}
|
}
|
||||||
|
|
||||||
use users::dsl;
|
use users::dsl;
|
||||||
let user_builder: UserBuilder = dsl::users
|
let user: User = dsl::users
|
||||||
.filter(dsl::uuid.eq(user_uuid))
|
.filter(dsl::uuid.eq(user_uuid))
|
||||||
.select(UserBuilder::as_select())
|
.select(User::as_select())
|
||||||
.get_result(&mut conn)
|
.get_result(&mut conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let user = user_builder.build();
|
|
||||||
|
|
||||||
data.set_cache_key(user_uuid.to_string(), user.clone(), 1800)
|
data.set_cache_key(user_uuid.to_string(), user.clone(), 1800)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_one_with_friendship(
|
|
||||||
data: &Data,
|
|
||||||
me: &Me,
|
|
||||||
user_uuid: Uuid,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut conn = data.pool.get().await?;
|
|
||||||
|
|
||||||
let mut user = Self::fetch_one(data, user_uuid).await?;
|
|
||||||
|
|
||||||
if let Some(friend) = me.friends_with(&mut conn, user_uuid).await? {
|
|
||||||
user.friends_since = Some(friend.accepted_at);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fetch_amount(
|
pub async fn fetch_amount(
|
||||||
conn: &mut Conn,
|
conn: &mut Conn,
|
||||||
offset: i64,
|
offset: i64,
|
||||||
amount: i64,
|
amount: i64,
|
||||||
) -> Result<Vec<Self>, Error> {
|
) -> Result<Vec<Self>, Error> {
|
||||||
use users::dsl;
|
use users::dsl;
|
||||||
let user_builders: Vec<UserBuilder> = load_or_empty(
|
let users: Vec<User> = load_or_empty(
|
||||||
dsl::users
|
dsl::users
|
||||||
.limit(amount)
|
.limit(amount)
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.select(UserBuilder::as_select())
|
.select(User::as_select())
|
||||||
.load(conn)
|
.load(conn)
|
||||||
.await,
|
.await,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let users: Vec<User> = user_builders.iter().map(|u| u.clone().build()).collect();
|
|
||||||
|
|
||||||
Ok(users)
|
Ok(users)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,22 +31,6 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
|
||||||
friend_requests (sender, receiver) {
|
|
||||||
sender -> Uuid,
|
|
||||||
receiver -> Uuid,
|
|
||||||
requested_at -> Timestamptz,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
|
||||||
friends (uuid1, uuid2) {
|
|
||||||
uuid1 -> Uuid,
|
|
||||||
uuid2 -> Uuid,
|
|
||||||
accepted_at -> Timestamptz,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
guild_members (uuid) {
|
guild_members (uuid) {
|
||||||
uuid -> Uuid,
|
uuid -> Uuid,
|
||||||
|
@ -169,8 +153,6 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
access_tokens,
|
access_tokens,
|
||||||
channel_permissions,
|
channel_permissions,
|
||||||
channels,
|
channels,
|
||||||
friend_requests,
|
|
||||||
friends,
|
|
||||||
guild_members,
|
guild_members,
|
||||||
guilds,
|
guilds,
|
||||||
instance_permissions,
|
instance_permissions,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue