feat(revcord): inital revcord commit

This commit is contained in:
Zomatree
2022-06-02 17:02:14 +01:00
parent 252a116766
commit b0313b8acb
18 changed files with 706 additions and 8 deletions

View File

@@ -0,0 +1,24 @@
mod models;
pub use twilight_model;
pub use models::{channel, user};
use async_trait::async_trait;
#[async_trait]
pub trait QuarkConversion: Sized {
type Type;
async fn to_quark(self) -> Self::Type;
async fn from_quark(data: Self::Type) -> Self;
}
pub fn to_snowflake<T, S: ToString>(ulid: S) -> twilight_model::id::Id<T> {
todo!()
}
pub fn to_ulid<T>(snowflake: twilight_model::id::Id<T>) -> String {
todo!()
}

View File

@@ -0,0 +1,136 @@
use crate::{QuarkConversion, to_snowflake, to_ulid};
use revolt_quark::models::{Channel as RevoltChannel};
use twilight_model::channel::{Channel as DiscordChannel, ChannelType};
use serde::{Serialize, Deserialize};
use rocket_okapi::{JsonSchema, okapi::schemars::schema::{Schema, SchemaObject}};
use async_trait::async_trait;
use std::collections::HashMap;
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(transparent)]
#[repr(transparent)]
pub struct Channel(DiscordChannel);
#[async_trait]
impl QuarkConversion for Channel {
type Type = RevoltChannel;
async fn to_quark(self) -> Self::Type {
let DiscordChannel { guild_id, id, kind, last_message_id, name, nsfw, recipients, topic, owner_id, .. } = self.0;
match kind {
ChannelType::GuildText => RevoltChannel::TextChannel {
id: to_ulid(id),
server: to_ulid(guild_id.unwrap()),
name: name.unwrap(),
description: topic,
icon: None,
last_message_id: last_message_id.map(to_ulid),
default_permissions: None, // TODO
role_permissions: HashMap::new(),
nsfw: nsfw.unwrap_or_default()
},
ChannelType::Private => RevoltChannel::DirectMessage {
id: to_ulid(id),
active: false,
recipients: recipients.unwrap_or_default().iter().map(|user| to_ulid(user.id)).collect(),
last_message_id: last_message_id.map(to_ulid)
},
ChannelType::GuildVoice => RevoltChannel::VoiceChannel {
id: to_ulid(id),
server: to_ulid(guild_id.unwrap()),
name: name.unwrap(),
description: topic,
icon: None,
default_permissions: None, // TODO
role_permissions: HashMap::new(),
nsfw: nsfw.unwrap_or_default()
},
ChannelType::Group => RevoltChannel::Group {
id: to_ulid(id),
name: name.unwrap(),
owner: to_ulid(owner_id.unwrap()),
description: topic,
recipients: recipients.unwrap_or_default().iter().map(|user| to_ulid(user.id)).collect(),
icon: None,
last_message_id: last_message_id.map(to_ulid),
permissions: None, // TODO
nsfw: nsfw.unwrap_or_default()
},
_ => todo!()
}
}
async fn from_quark(data: Self::Type) -> Self {
Self(DiscordChannel {
application_id: None,
bitrate: None,
default_auto_archive_duration: None,
guild_id: match &data {
RevoltChannel::TextChannel { server, ..} => Some(to_snowflake(server.clone())),
RevoltChannel::VoiceChannel { server, .. } => Some(to_snowflake(server.clone())),
_ => None
},
icon: None, // TODO,
id: to_snowflake(data.id()),
invitable: None,
kind: match &data {
RevoltChannel::SavedMessages { .. } => ChannelType::Private,
RevoltChannel::DirectMessage { .. } => ChannelType::Private,
RevoltChannel::Group { .. } => ChannelType::Group,
RevoltChannel::TextChannel { .. } => ChannelType::GuildText,
RevoltChannel::VoiceChannel { .. } => ChannelType::GuildVoice
},
last_message_id: match &data {
RevoltChannel::Group { last_message_id, .. } => last_message_id.clone().map(to_snowflake),
RevoltChannel::TextChannel { last_message_id, .. } => last_message_id.clone().map(to_snowflake),
RevoltChannel::DirectMessage { last_message_id, .. } => last_message_id.clone().map(to_snowflake),
_ => None
},
last_pin_timestamp: None,
member: None,
member_count: None,
message_count: None,
name: match &data {
RevoltChannel::Group { name, .. } => Some(name),
RevoltChannel::TextChannel { name, ..} => Some(name),
RevoltChannel::VoiceChannel { name, .. } => Some(name),
_ => None
}.cloned(),
newly_created: None,
nsfw: match &data {
RevoltChannel::Group { nsfw, .. } => Some(*nsfw),
RevoltChannel::TextChannel { nsfw, .. } => Some(*nsfw),
RevoltChannel::VoiceChannel { nsfw, .. } => Some(*nsfw),
_ => None
},
owner_id: None,
parent_id: None,
permission_overwrites: None, // TODO,
position: None, // TODO
rate_limit_per_user: None,
recipients: None,
rtc_region: None,
thread_metadata: None,
topic: match &data {
RevoltChannel::Group { description, .. } => description,
RevoltChannel::TextChannel { description, ..} => description,
RevoltChannel::VoiceChannel { description, ..} => description,
_ => &None
}.clone(),
user_limit: None,
video_quality_mode: None
})
}
}
impl JsonSchema for Channel {
fn schema_name() -> String {
"Channel".to_string()
}
fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
Schema::Object(SchemaObject::default())
}
}

View File

@@ -0,0 +1,2 @@
pub mod channel;
pub mod user;

View File

@@ -0,0 +1,140 @@
use crate::{QuarkConversion, to_snowflake, to_ulid};
use revolt_quark::{models::{User as RevoltUser, user::{BotInformation, UserHint}}, Database};
use twilight_model::user::{User as DiscordUser};
use serde::{Serialize, Deserialize};
use rocket_okapi::{JsonSchema, okapi::{schemars::schema::{Schema, SchemaObject}, openapi3::{SecurityScheme, SecuritySchemeData}}, gen::OpenApiGenerator, request::{OpenApiFromRequest, RequestHeaderInput}};
use async_trait::async_trait;
use rocket::{Request, request::{self, FromRequest, Outcome}, http::Status};
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(transparent)]
#[repr(transparent)]
pub struct User(DiscordUser);
impl User {
pub fn into_inner(self) -> DiscordUser {
self.0
}
}
#[async_trait]
impl QuarkConversion for User {
type Type = RevoltUser;
async fn to_quark(self) -> Self::Type {
let DiscordUser { bot, id, name , ..} = self.into_inner();
RevoltUser {
id: to_ulid(id),
username: name,
avatar: None, // TODO,
relations: None,
badges: None, // TODO,
status: None, // TODO,
profile: None, // TODO,
flags: None,
privileged: false,
bot: if bot {
Some(BotInformation {
owner: "0".to_string()
})
} else {
None
},
relationship: None,
online: None
}
}
async fn from_quark(data: Self::Type) -> Self {
Self(DiscordUser {
accent_color: None,
avatar: None, // TODO
bot: data.bot.is_some(),
banner: None, // TODO
discriminator: 1,
email: None,
flags: None,
id: to_snowflake(data.id),
locale: None,
mfa_enabled: None,
name: data.username,
premium_type: None,
public_flags: None,
system: None,
verified: None
})
}
}
impl JsonSchema for User {
fn schema_name() -> String {
"User".to_string()
}
fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
Schema::Object(SchemaObject::default())
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for User {
type Error = rauth::util::Error;
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let user: &Option<User> = request
.local_cache_async(async {
let db = request
.rocket()
.state::<Database>()
.expect("Database state not reachable!");
let header_token = request
.headers()
.get("Authorization")
.next()
.and_then(|x| x.split(' ').nth(1).map(|s| s.to_string()));
if let Some(token) = header_token {
if let Ok(user) = RevoltUser::from_token(db, &token, UserHint::Any).await {
return Some(User::from_quark(user).await);
}
}
None
})
.await;
if let Some(user) = user {
Outcome::Success(user.clone())
} else {
Outcome::Failure((Status::Unauthorized, rauth::util::Error::InvalidSession))
}
}
}
impl<'r> OpenApiFromRequest<'r> for User {
fn from_request_input(
_gen: &mut OpenApiGenerator,
_name: String,
_required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> {
let mut requirements = schemars::Map::new();
requirements.insert("Api Key".to_owned(), vec![]);
Ok(RequestHeaderInput::Security(
"Api Key".to_owned(),
SecurityScheme {
data: SecuritySchemeData::ApiKey {
name: "Authorization".to_owned(),
location: "header".to_owned(),
},
description: Some("Session Token".to_owned()),
extensions: schemars::Map::new(),
},
requirements,
))
}
}

View File

@@ -0,0 +1,6 @@
use lazy_static::lazy_static;
use std::env;
lazy_static! {
pub static ref REVCORD_URL: String = env::var("REVCORD_URL").expect("Missing REVCORD_URL environment variable");
}