chore(thanos): strip down codebase to just API routes

This commit is contained in:
Paul Makles
2022-01-27 14:16:30 +00:00
parent ab4c3f913e
commit 0fdb749199
116 changed files with 893 additions and 10025 deletions

View File

@@ -1,6 +1,4 @@
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::try_join;
use mongodb::bson::doc;
@@ -8,161 +6,6 @@ use mongodb::options::{Collation, FindOneOptions};
use rocket::serde::json::Value;
#[put("/<username>/friend")]
pub async fn req(user: User, username: String) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
let col = get_collection("users");
let doc = col
.find_one(
doc! {
"username": username
},
FindOneOptions::builder()
.collation(Collation::builder().locale("en").strength(2).build())
.build(),
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "user",
})?
.ok_or_else(|| Error::UnknownUser)?;
let target_id = doc.get_str("_id").map_err(|_| Error::DatabaseError {
operation: "get_str(_id)",
with: "user",
})?;
let target_user = Ref::from(target_id.to_string())?.fetch_user().await?;
if target_user.bot.is_some() {
return Err(Error::IsBot)
}
match get_relationship(&user, &target_id) {
RelationshipStatus::User => return Err(Error::NoEffect),
RelationshipStatus::Friend => return Err(Error::AlreadyFriends),
RelationshipStatus::Outgoing => return Err(Error::AlreadySentRequest),
RelationshipStatus::Blocked => return Err(Error::Blocked),
RelationshipStatus::BlockedOther => return Err(Error::BlockedByOther),
RelationshipStatus::Incoming => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id,
"relations._id": target_id
},
doc! {
"$set": {
"relations.$.status": "Friend"
}
},
None
),
col.update_one(
doc! {
"_id": target_id,
"relations._id": &user.id
},
doc! {
"$set": {
"relations.$.status": "Friend"
}
},
None
)
) {
Ok(_) => {
let target_user = target_user
.from_override(&user, RelationshipStatus::Friend)
.await?;
let user = user
.from_override(&target_user, RelationshipStatus::Friend)
.await?;
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Friend,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Friend,
}
.publish(target_id.to_string());
Ok(json!({ "status": "Friend" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
RelationshipStatus::None => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id
},
doc! {
"$push": {
"relations": {
"_id": target_id,
"status": "Outgoing"
}
}
},
None
),
col.update_one(
doc! {
"_id": target_id
},
doc! {
"$push": {
"relations": {
"_id": &user.id,
"status": "Incoming"
}
}
},
None
)
) {
Ok(_) => {
let target_user = target_user
.from_override(&user, RelationshipStatus::Outgoing)
.await?;
let user = user
.from_override(&target_user, RelationshipStatus::Incoming)
.await?;
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Outgoing,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Incoming,
}
.publish(target_id.to_string());
Ok(json!({ "status": "Outgoing" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
}
pub async fn req(/*user: UserRef,*/ username: String) -> Result<Value> {
todo!()
}

View File

@@ -1,171 +1,10 @@
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::try_join;
use mongodb::bson::doc;
use rocket::serde::json::Value;
#[put("/<target>/block")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
let col = get_collection("users");
let target = target.fetch_user().await?;
match get_relationship(&user, &target.id) {
RelationshipStatus::User | RelationshipStatus::Blocked => Err(Error::NoEffect),
RelationshipStatus::BlockedOther => {
col.update_one(
doc! {
"_id": &user.id,
"relations._id": &target.id
},
doc! {
"$set": {
"relations.$.status": "Blocked"
}
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "user",
})?;
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked,
}
.publish(user.id.clone());
Ok(json!({ "status": "Blocked" }))
}
RelationshipStatus::None => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id
},
doc! {
"$push": {
"relations": {
"_id": &target.id,
"status": "Blocked"
}
}
},
None
),
col.update_one(
doc! {
"_id": &target.id
},
doc! {
"$push": {
"relations": {
"_id": &user.id,
"status": "BlockedOther"
}
}
},
None
)
) {
Ok(_) => {
let target = target
.from_override(&user, RelationshipStatus::Blocked)
.await?;
let user = user
.from_override(&target, RelationshipStatus::BlockedOther)
.await?;
let target_id = target.id.clone();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther,
}
.publish(target_id);
Ok(json!({ "status": "Blocked" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
RelationshipStatus::Friend
| RelationshipStatus::Incoming
| RelationshipStatus::Outgoing => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id,
"relations._id": &target.id
},
doc! {
"$set": {
"relations.$.status": "Blocked"
}
},
None
),
col.update_one(
doc! {
"_id": &target.id,
"relations._id": &user.id
},
doc! {
"$set": {
"relations.$.status": "BlockedOther"
}
},
None
)
) {
Ok(_) => {
let target = target
.from_override(&user, RelationshipStatus::Blocked)
.await?;
let user = user
.from_override(&target, RelationshipStatus::BlockedOther)
.await?;
let target_id = target.id.clone();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther,
}
.publish(target_id);
Ok(json!({ "status": "Blocked" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
}
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,6 +1,4 @@
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result, EmptyResponse};
use revolt_quark::{EmptyResponse, Result};
use crate::util::regex::RE_USERNAME;
use mongodb::bson::doc;
use rauth::entities::Account;
@@ -19,45 +17,9 @@ pub struct Data {
#[patch("/<_ignore_id>/username", data = "<data>")]
pub async fn req(
account: Account,
user: User,
//user: UserRef,
data: Json<Data>,
_ignore_id: String,
) -> Result<EmptyResponse> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
data.validate()
.map_err(|error| Error::FailedValidation { error })?;
account.verify_password(&data.password)
.map_err(|_| Error::InvalidCredentials)?;
let mut set = doc! {};
if let Some(username) = &data.username {
if (username.to_lowercase() != user.username.to_lowercase()) && User::is_username_taken(&username).await? {
return Err(Error::UsernameTaken);
}
set.insert("username", username.clone());
}
get_collection("users")
.update_one(doc! { "_id": &user.id }, doc! { "$set": set }, None)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "user",
})?;
ClientboundNotification::UserUpdate {
id: user.id.clone(),
data: json!({
"username": data.username
}),
clear: None,
}
.publish_as_user(user.id.clone());
Ok(EmptyResponse {})
todo!()
}

View File

@@ -1,8 +1,7 @@
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result, EmptyResponse};
use crate::{database::*, notifications::events::RemoveUserField};
use revolt_quark::{EmptyResponse, Result, models::user::FieldsUser};
use mongodb::bson::{doc, to_document};
use revolt_quark::models::user::UserStatus;
use rocket::serde::json::Json;
use serde::{Deserialize, Serialize};
use validator::Validate;
@@ -19,138 +18,16 @@ pub struct UserProfileData {
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate]
// #[validate]
status: Option<UserStatus>,
#[validate]
profile: Option<UserProfileData>,
#[validate(length(min = 1, max = 128))]
avatar: Option<String>,
remove: Option<RemoveUserField>,
remove: Option<FieldsUser>,
}
#[patch("/<_ignore_id>", data = "<data>")]
pub async fn req(user: User, data: Json<Data>, _ignore_id: String) -> Result<EmptyResponse> {
let mut data = data.into_inner();
data.validate()
.map_err(|error| Error::FailedValidation { error })?;
if data.status.is_none()
&& data.profile.is_none()
&& data.avatar.is_none()
&& data.remove.is_none()
{
return Ok(EmptyResponse {});
}
let mut unset = doc! {};
let mut set = doc! {};
let mut remove_background = false;
let mut remove_avatar = false;
if let Some(remove) = &data.remove {
match remove {
RemoveUserField::ProfileContent => {
unset.insert("profile.content", 1);
}
RemoveUserField::ProfileBackground => {
unset.insert("profile.background", 1);
remove_background = true;
}
RemoveUserField::StatusText => {
unset.insert("status.text", 1);
}
RemoveUserField::Avatar => {
unset.insert("avatar", 1);
remove_avatar = true;
}
}
}
if let Some(status) = &data.status {
set.insert(
"status",
to_document(&status).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "status",
})?,
);
}
if let Some(profile) = data.profile {
if let Some(content) = profile.content {
set.insert("profile.content", content);
}
if let Some(attachment_id) = profile.background {
let attachment =
File::find_and_use(&attachment_id, "backgrounds", "user", &user.id).await?;
set.insert(
"profile.background",
to_document(&attachment).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "attachment",
})?,
);
remove_background = true;
}
}
let avatar = std::mem::replace(&mut data.avatar, None);
if let Some(attachment_id) = avatar {
let attachment = File::find_and_use(&attachment_id, "avatars", "user", &user.id).await?;
set.insert(
"avatar",
to_document(&attachment).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "attachment",
})?,
);
remove_avatar = true;
}
let mut operations = doc! {};
if set.len() > 0 {
operations.insert("$set", &set);
}
if unset.len() > 0 {
operations.insert("$unset", unset);
}
if operations.len() > 0 {
get_collection("users")
.update_one(doc! { "_id": &user.id }, operations, None)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "user",
})?;
}
ClientboundNotification::UserUpdate {
id: user.id.clone(),
data: json!(set),
clear: data.remove,
}
.publish_as_user(user.id.clone());
if remove_avatar {
if let Some(old_avatar) = user.avatar {
old_avatar.delete().await?;
}
}
if remove_background {
if let Some(profile) = user.profile {
if let Some(old_background) = profile.background {
old_background.delete().await?;
}
}
}
Ok(EmptyResponse {})
pub async fn req(/*user: UserRef,*/ data: Json<Data>, _ignore_id: String) -> Result<EmptyResponse> {
todo!()
}

View File

@@ -1,40 +1,9 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::StreamExt;
use mongodb::bson::doc;
use rocket::serde::json::Value;
#[get("/dms")]
pub async fn req(user: User) -> Result<Value> {
let mut cursor = get_collection("channels")
.find(
doc! {
"$or": [
{
"channel_type": "DirectMessage",
"active": true
},
{
"channel_type": "Group"
}
],
"recipients": user.id
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find",
with: "channels",
})?;
let mut channels = vec![];
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
channels.push(doc);
}
}
Ok(json!(channels))
pub async fn req(/*user: UserRef*/) -> Result<Value> {
todo!()
}

View File

@@ -1,24 +1,9 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use mongodb::bson::doc;
use rocket::serde::json::Value;
#[get("/<target>/profile")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
let target = target.fetch_user().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_user(&target)
.for_user_given()
.await?;
if !perm.get_view_profile() {
Err(Error::MissingPermission)?
}
if target.profile.is_some() {
Ok(json!(target.profile))
} else {
Ok(json!({}))
}
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,13 +1,8 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use rocket::serde::json::Value;
#[get("/<target>/relationship")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
Ok(json!({ "status": get_relationship(&user, &target.id) }))
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,17 +1,8 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use rocket::serde::json::Value;
#[get("/relationships")]
pub async fn req(user: User) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
Ok(if let Some(vec) = user.relations {
json!(vec)
} else {
json!([])
})
pub async fn req(/*user: UserRef*/) -> Result<Value> {
todo!()
}

View File

@@ -1,9 +1,8 @@
use crate::database::*;
use crate::util::result::{Result};
use revolt_quark::Result;
use rocket::serde::json::Value;
#[get("/@me")]
pub async fn req(user: User) -> Result<Value> {
Ok(json!(user))
pub async fn req(/*user: UserRef*/) -> Result<Value> {
todo!()
}

View File

@@ -1,20 +1,8 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use rocket::serde::json::Value;
#[get("/<target>")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
let target = target.fetch_user().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_user(&target)
.for_user_given()
.await?;
if !perm.get_access() {
Err(Error::MissingPermission)?
}
Ok(json!(target.from(&user).with(perm)))
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,5 +1,4 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::StreamExt;
use mongodb::bson::{doc, Document};
@@ -7,56 +6,6 @@ use mongodb::options::FindOptions;
use rocket::serde::json::Value;
#[get("/<target>/mutual")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
let users = get_collection("users")
.find(
doc! {
"$and": [
{ "relations": { "$elemMatch": { "_id": &user.id, "status": "Friend" } } },
{ "relations": { "$elemMatch": { "_id": &target.id, "status": "Friend" } } }
]
},
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find",
with: "users",
})?
.filter_map(async move |s| s.ok())
.collect::<Vec<Document>>()
.await
.into_iter()
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
.collect::<Vec<String>>();
let server_ids = User::fetch_server_ids(&user.id).await?;
let servers = get_collection("server_members")
.find(
doc! {
"_id.user": &target.id,
"_id.server": {
"$in": server_ids
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "server_members",
})?
.filter_map(async move |s| s.ok())
.collect::<Vec<Document>>()
.await
.into_iter()
.filter_map(|x| {
x.get_document("_id")
.ok()
.map(|i| i.get_str("server").ok().map(|x| x.to_string()))
})
.flatten()
.collect::<Vec<String>>();
Ok(json!({ "users": users, "servers": servers }))
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -3,8 +3,6 @@ use rocket::response::{self, Responder};
use rocket::fs::NamedFile;
use std::path::Path;
use crate::database::Ref;
pub struct CachedFile(NamedFile);
pub static CACHE_CONTROL: &'static str = "public, max-age=31536000, immutable";
@@ -18,8 +16,8 @@ impl<'r> Responder<'r, 'static> for CachedFile {
}
#[get("/<target>/default_avatar")]
pub async fn req(target: Ref) -> Option<CachedFile> {
match target.id.chars().nth(25).unwrap() {
pub async fn req(target: String) -> Option<CachedFile> {
match target.chars().nth(25).unwrap() {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => {
NamedFile::open(Path::new("assets/user_red.png")).await.ok().map(|n| CachedFile(n))
}

View File

@@ -1,50 +1,10 @@
use crate::database::*;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use mongodb::bson::doc;
use rocket::serde::json::Value;
use ulid::Ulid;
#[get("/<target>/dm")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
let query = if user.id == target.id {
doc! {
"channel_type": "SavedMessages",
"user": &user.id
}
} else {
doc! {
"channel_type": "DirectMessage",
"recipients": {
"$all": [ &user.id, &target.id ]
}
}
};
let existing_channel = get_collection("channels")
.find_one(query, None)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "channel",
})?;
if let Some(doc) = existing_channel {
Ok(json!(doc))
} else {
let id = Ulid::new().to_string();
let channel = if user.id == target.id {
Channel::SavedMessages { id, user: user.id }
} else {
Channel::DirectMessage {
id,
active: false,
recipients: vec![user.id, target.id],
last_message_id: None,
}
};
channel.clone().publish().await?;
Ok(json!(channel))
}
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,83 +1,10 @@
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::try_join;
use mongodb::bson::doc;
use rocket::serde::json::Value;
#[delete("/<target>/friend")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
let col = get_collection("users");
let target = target.fetch_user().await?;
match get_relationship(&user, &target.id) {
RelationshipStatus::Friend
| RelationshipStatus::Outgoing
| RelationshipStatus::Incoming => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id
},
doc! {
"$pull": {
"relations": {
"_id": &target.id
}
}
},
None
),
col.update_one(
doc! {
"_id": &target.id
},
doc! {
"$pull": {
"relations": {
"_id": &user.id
}
}
},
None
)
) {
Ok(_) => {
let target = target
.from_override(&user, RelationshipStatus::None)
.await?;
let user = user
.from_override(&target, RelationshipStatus::None)
.await?;
let target_id = target.id.clone();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::None,
}
.publish(target_id);
Ok(json!({ "status": "None" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
_ => Err(Error::NoEffect),
}
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}

View File

@@ -1,115 +1,10 @@
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use revolt_quark::{Error, Result};
use futures::try_join;
use mongodb::bson::doc;
use rocket::serde::json::Value;
#[delete("/<target>/block")]
pub async fn req(user: User, target: Ref) -> Result<Value> {
if user.bot.is_some() {
return Err(Error::IsBot)
}
let col = get_collection("users");
let target = target.fetch_user().await?;
match get_relationship(&user, &target.id) {
RelationshipStatus::Blocked => match get_relationship(&target, &user.id) {
RelationshipStatus::Blocked => {
col.update_one(
doc! {
"_id": &user.id,
"relations._id": &target.id
},
doc! {
"$set": {
"relations.$.status": "BlockedOther"
}
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "user",
})?;
let target = target
.from_override(&user, RelationshipStatus::BlockedOther)
.await?;
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::BlockedOther,
}
.publish(user.id.clone());
Ok(json!({ "status": "BlockedOther" }))
}
RelationshipStatus::BlockedOther => {
match try_join!(
col.update_one(
doc! {
"_id": &user.id
},
doc! {
"$pull": {
"relations": {
"_id": &target.id
}
}
},
None
),
col.update_one(
doc! {
"_id": &target.id
},
doc! {
"$pull": {
"relations": {
"_id": &user.id
}
}
},
None
)
) {
Ok(_) => {
let target = target
.from_override(&user, RelationshipStatus::None)
.await?;
let user = user
.from_override(&target, RelationshipStatus::None)
.await?;
let target_id = target.id.clone();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None,
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user: user,
status: RelationshipStatus::None,
}
.publish(target_id);
Ok(json!({ "status": "None" }))
}
Err(_) => Err(Error::DatabaseError {
operation: "update_one",
with: "user",
}),
}
}
_ => Err(Error::InternalError),
},
_ => Err(Error::NoEffect),
}
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> {
todo!()
}