Servers: Core objects required. Includes creation. Bump version to 0.5.0.
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
export version=0.4.2-alpha.3
|
export version=0.5.0-alpha.0
|
||||||
echo "pub const VERSION: &str = \"${version}\";" > src/version.rs
|
echo "pub const VERSION: &str = \"${version}\";" > src/version.rs
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
mod microservice;
|
|
||||||
mod channel;
|
mod channel;
|
||||||
mod message;
|
mod message;
|
||||||
|
mod microservice;
|
||||||
mod server;
|
mod server;
|
||||||
mod user;
|
|
||||||
mod sync;
|
mod sync;
|
||||||
|
mod user;
|
||||||
|
|
||||||
use microservice::*;
|
use microservice::*;
|
||||||
|
|
||||||
@@ -12,5 +12,5 @@ pub use channel::*;
|
|||||||
pub use january::*;
|
pub use january::*;
|
||||||
pub use message::*;
|
pub use message::*;
|
||||||
pub use server::*;
|
pub use server::*;
|
||||||
pub use user::*;
|
|
||||||
pub use sync::*;
|
pub use sync::*;
|
||||||
|
pub use user::*;
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::notifications::events::ClientboundNotification;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
use mongodb::bson::from_document;
|
||||||
|
use mongodb::bson::to_document;
|
||||||
|
use rocket_contrib::json::JsonValue;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MemberCompositeKey {
|
pub struct MemberCompositeKey {
|
||||||
pub guild: String,
|
pub server: String,
|
||||||
pub user: String,
|
pub user: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,9 +41,67 @@ pub struct Server {
|
|||||||
pub nonce: Option<String>,
|
pub nonce: Option<String>,
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
|
|
||||||
|
pub name: String,
|
||||||
|
// pub default_permissions: u32,
|
||||||
pub channels: Vec<String>,
|
pub channels: Vec<String>,
|
||||||
pub invites: Vec<Invite>,
|
// pub invites: Vec<Invite>,
|
||||||
pub bans: Vec<Ban>,
|
// pub bans: Vec<Ban>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub default_permissions: u32,
|
pub icon: Option<File>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub banner: Option<File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub async fn get(id: &str) -> Result<Server> {
|
||||||
|
let doc = get_collection("servers")
|
||||||
|
.find_one(doc! { "_id": id }, None)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "server",
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| Error::UnknownServer)?;
|
||||||
|
|
||||||
|
from_document::<Server>(doc).map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "from_document",
|
||||||
|
with: "server",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn publish(self) -> Result<()> {
|
||||||
|
get_collection("servers")
|
||||||
|
.insert_one(
|
||||||
|
to_document(&self).map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "to_bson",
|
||||||
|
with: "channel",
|
||||||
|
})?,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "insert_one",
|
||||||
|
with: "server",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let server_id = self.id.clone();
|
||||||
|
ClientboundNotification::ServerCreate(self).publish(server_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn publish_update(&self, data: JsonValue) -> Result<()> {
|
||||||
|
ClientboundNotification::ServerUpdate {
|
||||||
|
id: self.id.clone(),
|
||||||
|
data,
|
||||||
|
clear: None,
|
||||||
|
}
|
||||||
|
.publish(self.id.clone());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete(&self) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ impl Ref {
|
|||||||
self.fetch("channels").await
|
self.fetch("channels").await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_server(&self) -> Result<Server> {
|
||||||
|
self.fetch("servers").await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_message(&self, channel: &Channel) -> Result<Message> {
|
pub async fn fetch_message(&self, channel: &Channel) -> Result<Message> {
|
||||||
let message: Message = self.fetch("messages").await?;
|
let message: Message = self.fetch("messages").await?;
|
||||||
if &message.channel != channel.id() {
|
if &message.channel != channel.id() {
|
||||||
|
|||||||
@@ -29,6 +29,18 @@ pub async fn create_database() {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to create servers collection.");
|
.expect("Failed to create servers collection.");
|
||||||
|
|
||||||
|
db.create_collection("server_members", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create server_members collection.");
|
||||||
|
|
||||||
|
db.create_collection("server_bans", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create server_bans collection.");
|
||||||
|
|
||||||
|
db.create_collection("invites", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create invites collection.");
|
||||||
|
|
||||||
db.create_collection("migrations", None)
|
db.create_collection("migrations", None)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create migrations collection.");
|
.expect("Failed to create migrations collection.");
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct MigrationInfo {
|
|||||||
revision: i32,
|
revision: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LATEST_REVISION: i32 = 4;
|
pub const LATEST_REVISION: i32 = 5;
|
||||||
|
|
||||||
pub async fn migrate_database() {
|
pub async fn migrate_database() {
|
||||||
let migrations = get_collection("migrations");
|
let migrations = get_collection("migrations");
|
||||||
@@ -138,6 +138,25 @@ pub async fn run_migrations(revision: i32) -> i32 {
|
|||||||
.expect("Failed to create user_settings collection.");
|
.expect("Failed to create user_settings collection.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if revision <= 4 {
|
||||||
|
info!("Running migration [revision 4 / 2021-06-01]: Add more server collections.");
|
||||||
|
|
||||||
|
get_db()
|
||||||
|
.create_collection("server_members", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create server_members collection.");
|
||||||
|
|
||||||
|
get_db()
|
||||||
|
.create_collection("server_bans", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create server_bans collection.");
|
||||||
|
|
||||||
|
get_db()
|
||||||
|
.create_collection("invites", None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create invites collection.");
|
||||||
|
}
|
||||||
|
|
||||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||||
LATEST_REVISION
|
LATEST_REVISION
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub struct PermissionCalculator<'a> {
|
|||||||
user: Option<&'a User>,
|
user: Option<&'a User>,
|
||||||
relationship: Option<&'a RelationshipStatus>,
|
relationship: Option<&'a RelationshipStatus>,
|
||||||
channel: Option<&'a Channel>,
|
channel: Option<&'a Channel>,
|
||||||
|
server: Option<&'a Server>,
|
||||||
|
|
||||||
has_mutual_connection: bool,
|
has_mutual_connection: bool,
|
||||||
}
|
}
|
||||||
@@ -23,6 +24,7 @@ impl<'a> PermissionCalculator<'a> {
|
|||||||
user: None,
|
user: None,
|
||||||
relationship: None,
|
relationship: None,
|
||||||
channel: None,
|
channel: None,
|
||||||
|
server: None,
|
||||||
|
|
||||||
has_mutual_connection: false,
|
has_mutual_connection: false,
|
||||||
}
|
}
|
||||||
@@ -49,6 +51,13 @@ impl<'a> PermissionCalculator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_server(self, server: &'a Server) -> PermissionCalculator {
|
||||||
|
PermissionCalculator {
|
||||||
|
server: Some(&server),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_mutual_connection(self) -> PermissionCalculator<'a> {
|
pub fn with_mutual_connection(self) -> PermissionCalculator<'a> {
|
||||||
PermissionCalculator {
|
PermissionCalculator {
|
||||||
has_mutual_connection: true,
|
has_mutual_connection: true,
|
||||||
|
|||||||
42
src/database/permissions/server.rs
Normal file
42
src/database/permissions/server.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::Result;
|
||||||
|
|
||||||
|
use super::PermissionCalculator;
|
||||||
|
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, Copy, Clone)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum ServerPermission {
|
||||||
|
View = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_op_ex!(+ |a: &ServerPermission, b: &ServerPermission| -> u32 { *a as u32 | *b as u32 });
|
||||||
|
impl_op_ex_commutative!(+ |a: &u32, b: &ServerPermission| -> u32 { *a | *b as u32 });
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct ServerPermissions(MSB0 [u32]);
|
||||||
|
u32;
|
||||||
|
pub get_view, _: 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PermissionCalculator<'a> {
|
||||||
|
pub async fn calculate_server(self) -> Result<u32> {
|
||||||
|
let server = if let Some(server) = self.server {
|
||||||
|
server
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if &self.perspective.id == server.owner {
|
||||||
|
Ok(u32::MAX)
|
||||||
|
} else {
|
||||||
|
Ok(ServerPermission::View as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn for_server(self) -> Result<ChannelPermissions<[u32; 1]>> {
|
||||||
|
Ok(ServerPermissions([self.calculate_server().await?]))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,12 @@ pub enum RemoveChannelField {
|
|||||||
Icon,
|
Icon,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub enum RemoveServerField {
|
||||||
|
Icon,
|
||||||
|
Banner,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum ClientboundNotification {
|
pub enum ClientboundNotification {
|
||||||
@@ -46,6 +52,7 @@ pub enum ClientboundNotification {
|
|||||||
Authenticated,
|
Authenticated,
|
||||||
Ready {
|
Ready {
|
||||||
users: Vec<User>,
|
users: Vec<User>,
|
||||||
|
servers: Vec<Server>,
|
||||||
channels: Vec<Channel>,
|
channels: Vec<Channel>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -67,6 +74,9 @@ pub enum ClientboundNotification {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
clear: Option<RemoveChannelField>,
|
clear: Option<RemoveChannelField>,
|
||||||
},
|
},
|
||||||
|
ChannelDelete {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
ChannelGroupJoin {
|
ChannelGroupJoin {
|
||||||
id: String,
|
id: String,
|
||||||
user: String,
|
user: String,
|
||||||
@@ -75,9 +85,6 @@ pub enum ClientboundNotification {
|
|||||||
id: String,
|
id: String,
|
||||||
user: String,
|
user: String,
|
||||||
},
|
},
|
||||||
ChannelDelete {
|
|
||||||
id: String,
|
|
||||||
},
|
|
||||||
ChannelStartTyping {
|
ChannelStartTyping {
|
||||||
id: String,
|
id: String,
|
||||||
user: String,
|
user: String,
|
||||||
@@ -87,6 +94,25 @@ pub enum ClientboundNotification {
|
|||||||
user: String,
|
user: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ServerCreate(Server),
|
||||||
|
ServerUpdate {
|
||||||
|
id: String,
|
||||||
|
data: JsonValue,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
clear: Option<RemoveServerField>,
|
||||||
|
},
|
||||||
|
ServerDelete {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
ServerMemberJoin {
|
||||||
|
id: String,
|
||||||
|
user: String,
|
||||||
|
},
|
||||||
|
ServerMemberLeave {
|
||||||
|
id: String,
|
||||||
|
user: String,
|
||||||
|
},
|
||||||
|
|
||||||
UserUpdate {
|
UserUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
data: JsonValue,
|
data: JsonValue,
|
||||||
@@ -104,8 +130,8 @@ pub enum ClientboundNotification {
|
|||||||
},
|
},
|
||||||
UserSettingsUpdate {
|
UserSettingsUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
update: JsonValue
|
update: JsonValue,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientboundNotification {
|
impl ClientboundNotification {
|
||||||
@@ -137,6 +163,12 @@ pub fn prehandle_hook(notification: &ClientboundNotification) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ClientboundNotification::ServerMemberJoin { id, user } => {
|
||||||
|
subscribe_if_exists(user.clone(), id.clone()).ok();
|
||||||
|
}
|
||||||
|
ClientboundNotification::ServerCreate(server) => {
|
||||||
|
subscribe_if_exists(server.owner.clone(), server.id.clone()).ok();
|
||||||
|
}
|
||||||
ClientboundNotification::UserRelationship { id, user, status } => {
|
ClientboundNotification::UserRelationship { id, user, status } => {
|
||||||
if status != &RelationshipStatus::None {
|
if status != &RelationshipStatus::None {
|
||||||
subscribe_if_exists(id.clone(), user.id.clone()).ok();
|
subscribe_if_exists(id.clone(), user.id.clone()).ok();
|
||||||
@@ -151,6 +183,21 @@ pub fn posthandle_hook(notification: &ClientboundNotification) {
|
|||||||
ClientboundNotification::ChannelDelete { id } => {
|
ClientboundNotification::ChannelDelete { id } => {
|
||||||
get_hive().hive.drop_topic(&id).ok();
|
get_hive().hive.drop_topic(&id).ok();
|
||||||
}
|
}
|
||||||
|
ClientboundNotification::ChannelGroupLeave { id, user } => {
|
||||||
|
get_hive()
|
||||||
|
.hive
|
||||||
|
.unsubscribe(&user.to_string(), &id.to_string())
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
ClientboundNotification::ServerDelete { id } => {
|
||||||
|
get_hive().hive.drop_topic(&id).ok();
|
||||||
|
}
|
||||||
|
ClientboundNotification::ServerMemberLeave { id, user } => {
|
||||||
|
get_hive()
|
||||||
|
.hive
|
||||||
|
.unsubscribe(&user.to_string(), &id.to_string())
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
ClientboundNotification::UserRelationship { id, user, status } => {
|
ClientboundNotification::UserRelationship { id, user, status } => {
|
||||||
if status == &RelationshipStatus::None {
|
if status == &RelationshipStatus::None {
|
||||||
get_hive()
|
get_hive()
|
||||||
@@ -159,12 +206,6 @@ pub fn posthandle_hook(notification: &ClientboundNotification) {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientboundNotification::ChannelGroupLeave { id, user } => {
|
|
||||||
get_hive()
|
|
||||||
.hive
|
|
||||||
.unsubscribe(&user.to_string(), &id.to_string())
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
util::result::{Error, Result},
|
util::result::{Error, Result},
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use mongodb::bson::{doc, from_document};
|
use mongodb::bson::{doc, from_document, Document};
|
||||||
|
|
||||||
pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> {
|
pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> {
|
||||||
let mut user_ids: HashSet<String> = HashSet::new();
|
let mut user_ids: HashSet<String> = HashSet::new();
|
||||||
@@ -19,10 +19,68 @@ pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let server_ids = get_collection("server_members")
|
||||||
|
.find(
|
||||||
|
doc! {
|
||||||
|
"_id.user": &user.id
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find",
|
||||||
|
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>>();
|
||||||
|
|
||||||
|
let mut cursor = get_collection("servers")
|
||||||
|
.find(
|
||||||
|
doc! {
|
||||||
|
"_id": {
|
||||||
|
"$in": server_ids
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find",
|
||||||
|
with: "servers",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut servers = vec![];
|
||||||
|
let mut channel_ids = vec![];
|
||||||
|
while let Some(result) = cursor.next().await {
|
||||||
|
if let Ok(doc) = result {
|
||||||
|
let server: Server = from_document(doc).map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "from_document",
|
||||||
|
with: "server",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
channel_ids.extend(server.channels.iter().cloned());
|
||||||
|
servers.push(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut cursor = get_collection("channels")
|
let mut cursor = get_collection("channels")
|
||||||
.find(
|
.find(
|
||||||
doc! {
|
doc! {
|
||||||
"$or": [
|
"$or": [
|
||||||
|
{
|
||||||
|
"_id": {
|
||||||
|
"$in": channel_ids
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"channel_type": "SavedMessages",
|
"channel_type": "SavedMessages",
|
||||||
"user": &user.id
|
"user": &user.id
|
||||||
@@ -75,5 +133,9 @@ pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> {
|
|||||||
user.online = Some(true);
|
user.online = Some(true);
|
||||||
users.push(user);
|
users.push(user);
|
||||||
|
|
||||||
Ok(ClientboundNotification::Ready { users, channels })
|
Ok(ClientboundNotification::Ready {
|
||||||
|
users,
|
||||||
|
servers,
|
||||||
|
channels,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,5 +45,7 @@ pub async fn generate_subscriptions(user: &User) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ! FIXME: fetch memberships for servers
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,8 +243,8 @@ pub fn publish(ids: Vec<String>, notification: ClientboundNotification) {
|
|||||||
for id in ids {
|
for id in ids {
|
||||||
// Block certain notifications from reaching users that aren't meant to see them.
|
// Block certain notifications from reaching users that aren't meant to see them.
|
||||||
match ¬ification {
|
match ¬ification {
|
||||||
ClientboundNotification::UserRelationship { id: user_id, .. } |
|
ClientboundNotification::UserRelationship { id: user_id, .. }
|
||||||
ClientboundNotification::UserSettingsUpdate { id: user_id, .. } => {
|
| ClientboundNotification::UserSettingsUpdate { id: user_id, .. } => {
|
||||||
if &id != user_id {
|
if &id != user_id {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
use rocket::Route;
|
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
|
||||||
routes![]
|
|
||||||
}
|
|
||||||
@@ -3,12 +3,12 @@ pub use rocket::response::Redirect;
|
|||||||
use rocket::Rocket;
|
use rocket::Rocket;
|
||||||
|
|
||||||
mod channels;
|
mod channels;
|
||||||
mod guild;
|
|
||||||
mod onboard;
|
mod onboard;
|
||||||
mod push;
|
mod push;
|
||||||
mod root;
|
mod root;
|
||||||
mod users;
|
mod servers;
|
||||||
mod sync;
|
mod sync;
|
||||||
|
mod users;
|
||||||
|
|
||||||
pub fn mount(rocket: Rocket) -> Rocket {
|
pub fn mount(rocket: Rocket) -> Rocket {
|
||||||
rocket
|
rocket
|
||||||
@@ -16,7 +16,7 @@ pub fn mount(rocket: Rocket) -> Rocket {
|
|||||||
.mount("/onboard", onboard::routes())
|
.mount("/onboard", onboard::routes())
|
||||||
.mount("/users", users::routes())
|
.mount("/users", users::routes())
|
||||||
.mount("/channels", channels::routes())
|
.mount("/channels", channels::routes())
|
||||||
.mount("/guild", guild::routes())
|
.mount("/servers", servers::routes())
|
||||||
.mount("/push", push::routes())
|
.mount("/push", push::routes())
|
||||||
.mount("/sync", sync::routes())
|
.mount("/sync", sync::routes())
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/routes/servers/mod.rs
Normal file
8
src/routes/servers/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use rocket::Route;
|
||||||
|
|
||||||
|
mod server_create;
|
||||||
|
mod server_delete;
|
||||||
|
|
||||||
|
pub fn routes() -> Vec<Route> {
|
||||||
|
routes![server_create::req, server_delete::req]
|
||||||
|
}
|
||||||
73
src/routes/servers/server_create.rs
Normal file
73
src/routes/servers/server_create.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
use rocket_contrib::json::{Json, JsonValue};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use ulid::Ulid;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
#[derive(Validate, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
#[validate(length(min = 1, max = 32))]
|
||||||
|
name: String,
|
||||||
|
// Maximum length of 36 allows both ULIDs and UUIDs.
|
||||||
|
#[validate(length(min = 1, max = 36))]
|
||||||
|
nonce: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/create", data = "<info>")]
|
||||||
|
pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
||||||
|
info.validate()
|
||||||
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
|
if get_collection("servers")
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"nonce": &info.nonce
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "server",
|
||||||
|
})?
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
Err(Error::DuplicateNonce)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = Ulid::new().to_string();
|
||||||
|
let server = Server {
|
||||||
|
id: id.clone(),
|
||||||
|
nonce: Some(info.nonce.clone()),
|
||||||
|
owner: user.id.clone(),
|
||||||
|
|
||||||
|
name: info.name.clone(),
|
||||||
|
channels: vec![],
|
||||||
|
|
||||||
|
icon: None,
|
||||||
|
banner: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
get_collection("server_members")
|
||||||
|
.insert_one(
|
||||||
|
doc! {
|
||||||
|
"_id": {
|
||||||
|
"server": id,
|
||||||
|
"user": user.id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "insert_one",
|
||||||
|
with: "server_members",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
server.clone().publish().await?;
|
||||||
|
|
||||||
|
Ok(json!(server))
|
||||||
|
}
|
||||||
19
src/routes/servers/server_delete.rs
Normal file
19
src/routes/servers/server_delete.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use crate::database::*;
|
||||||
|
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
|
||||||
|
#[delete("/<target>")]
|
||||||
|
pub async fn req(user: User, target: Ref) -> Result<()> {
|
||||||
|
let target = target.fetch_server().await?;
|
||||||
|
|
||||||
|
/*let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_channel(&target)
|
||||||
|
.for_channel()
|
||||||
|
.await?;
|
||||||
|
if !perm.get_view() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}*/
|
||||||
|
|
||||||
|
target.delete().await
|
||||||
|
}
|
||||||
@@ -2,13 +2,13 @@ use crate::database::*;
|
|||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use mongodb::options::FindOneOptions;
|
use mongodb::options::FindOneOptions;
|
||||||
use rocket_contrib::json::{Json, JsonValue};
|
use rocket_contrib::json::{Json, JsonValue};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
keys: Vec<String>
|
keys: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/settings/fetch", data = "<options>")]
|
#[post("/settings/fetch", data = "<options>")]
|
||||||
@@ -27,14 +27,16 @@ pub async fn req(user: User, options: Json<Options>) -> Result<JsonValue> {
|
|||||||
doc! {
|
doc! {
|
||||||
"_id": user.id
|
"_id": user.id
|
||||||
},
|
},
|
||||||
FindOneOptions::builder()
|
FindOneOptions::builder().projection(projection).build(),
|
||||||
.projection(projection)
|
|
||||||
.build()
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Error::DatabaseError { operation: "find_one", with: "user_settings" })? {
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "user_settings",
|
||||||
|
})?
|
||||||
|
{
|
||||||
Ok(json!(doc))
|
Ok(json!(doc))
|
||||||
} else {
|
} else {
|
||||||
Ok(json!({ }))
|
Ok(json!({}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,5 @@ mod get_settings;
|
|||||||
mod set_settings;
|
mod set_settings;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![
|
routes![get_settings::req, set_settings::req]
|
||||||
get_settings::req,
|
|
||||||
set_settings::req
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ use crate::notifications::events::ClientboundNotification;
|
|||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use rocket::request::Form;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use rocket_contrib::json::Json;
|
|
||||||
use mongodb::bson::{doc, to_bson};
|
use mongodb::bson::{doc, to_bson};
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use mongodb::options::UpdateOptions;
|
use mongodb::options::UpdateOptions;
|
||||||
|
use rocket::request::Form;
|
||||||
|
use rocket_contrib::json::Json;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
type Data = HashMap<String, String>;
|
type Data = HashMap<String, String>;
|
||||||
|
|
||||||
@@ -35,10 +35,10 @@ pub async fn req(user: User, data: Json<Data>, options: Form<Options>) -> Result
|
|||||||
for (key, data) in &data {
|
for (key, data) in &data {
|
||||||
set.insert(
|
set.insert(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
vec! [
|
vec![
|
||||||
to_bson(×tamp).unwrap(),
|
to_bson(×tamp).unwrap(),
|
||||||
to_bson(&data.clone()).unwrap()
|
to_bson(&data.clone()).unwrap(),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,17 +51,18 @@ pub async fn req(user: User, data: Json<Data>, options: Form<Options>) -> Result
|
|||||||
doc! {
|
doc! {
|
||||||
"$set": &set
|
"$set": &set
|
||||||
},
|
},
|
||||||
UpdateOptions::builder()
|
UpdateOptions::builder().upsert(true).build(),
|
||||||
.upsert(true)
|
|
||||||
.build()
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Error::DatabaseError { operation: "update_one", with: "user_settings" })?;
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "update_one",
|
||||||
|
with: "user_settings",
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientboundNotification::UserSettingsUpdate {
|
ClientboundNotification::UserSettingsUpdate {
|
||||||
id: user.id.clone(),
|
id: user.id.clone(),
|
||||||
update: json!(set)
|
update: json!(set),
|
||||||
}
|
}
|
||||||
.publish(user.id);
|
.publish(user.id);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ pub enum Error {
|
|||||||
AlreadyInGroup,
|
AlreadyInGroup,
|
||||||
NotInGroup,
|
NotInGroup,
|
||||||
|
|
||||||
|
// ? Server related errors.
|
||||||
|
UnknownServer,
|
||||||
|
|
||||||
// ? General errors.
|
// ? General errors.
|
||||||
TooManyIds,
|
TooManyIds,
|
||||||
FailedValidation {
|
FailedValidation {
|
||||||
@@ -80,6 +83,8 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::AlreadyInGroup => Status::Conflict,
|
Error::AlreadyInGroup => Status::Conflict,
|
||||||
Error::NotInGroup => Status::NotFound,
|
Error::NotInGroup => Status::NotFound,
|
||||||
|
|
||||||
|
Error::UnknownServer => Status::NotFound,
|
||||||
|
|
||||||
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
||||||
Error::DatabaseError { .. } => Status::InternalServerError,
|
Error::DatabaseError { .. } => Status::InternalServerError,
|
||||||
Error::InternalError => Status::InternalServerError,
|
Error::InternalError => Status::InternalServerError,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
pub const VERSION: &str = "0.4.2-alpha.3";
|
pub const VERSION: &str = "0.5.0-alpha.0";
|
||||||
|
|||||||
Reference in New Issue
Block a user