Compare commits

...
7 Commits
19 changed files with 107 additions and 38 deletions

No files matched your search

+2 -2
View File
@@ -2,8 +2,8 @@ name: Docker Test & Publish
on: on:
push: push:
branches: # branches:
- "main" # - "main"
tags: tags:
- "*" - "*"
paths-ignore: paths-ignore:
Generated
+8 -8
View File
@@ -3452,7 +3452,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-bonfire" name = "revolt-bonfire"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-channel 2.3.1", "async-channel 2.3.1",
"async-std", "async-std",
@@ -3482,7 +3482,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-config" name = "revolt-config"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-std", "async-std",
"cached", "cached",
@@ -3498,7 +3498,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-database" name = "revolt-database"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-lock", "async-lock",
"async-recursion", "async-recursion",
@@ -3544,7 +3544,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-delta" name = "revolt-delta"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-channel 1.6.1", "async-channel 1.6.1",
"async-std", "async-std",
@@ -3591,7 +3591,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-models" name = "revolt-models"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"iso8601-timestamp 0.2.11", "iso8601-timestamp 0.2.11",
@@ -3608,7 +3608,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-permissions" name = "revolt-permissions"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@@ -3623,7 +3623,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-presence" name = "revolt-presence"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"async-std", "async-std",
"log", "log",
@@ -3634,7 +3634,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-result" name = "revolt-result"
version = "0.7.11" version = "0.7.12"
dependencies = [ dependencies = [
"revolt_okapi", "revolt_okapi",
"revolt_rocket_okapi", "revolt_rocket_okapi",
+2
View File
@@ -21,6 +21,8 @@ Rust 1.70 or higher.
## Development Guide ## Development Guide
Before contributing, make yourself familiar with [our contribution guidelines](https://developers.revolt.chat/contrib.html) and the [technical documentation for this project](https://revoltchat.github.io/backend/).
Before getting started, you'll want to install: Before getting started, you'll want to install:
- Rust toolchain (rustup recommended) - Rust toolchain (rustup recommended)
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-bonfire" name = "revolt-bonfire"
version = "0.7.11" version = "0.7.12"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
edition = "2021" edition = "2021"
@@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" }
revolt-models = { path = "../core/models" } revolt-models = { path = "../core/models" }
revolt-config = { path = "../core/config" } revolt-config = { path = "../core/config" }
revolt-database = { path = "../core/database" } revolt-database = { path = "../core/database" }
revolt-permissions = { version = "0.7.11", path = "../core/permissions" } revolt-permissions = { version = "0.7.12", path = "../core/permissions" }
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] } revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
# redis # redis
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-config" name = "revolt-config"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
+6 -6
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-database" name = "revolt-database"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
@@ -23,13 +23,13 @@ default = ["mongodb", "async-std-runtime", "tasks"]
[dependencies] [dependencies]
# Core # Core
revolt-config = { version = "0.7.11", path = "../config" } revolt-config = { version = "0.7.12", path = "../config" }
revolt-result = { version = "0.7.11", path = "../result" } revolt-result = { version = "0.7.12", path = "../result" }
revolt-models = { version = "0.7.11", path = "../models", features = [ revolt-models = { version = "0.7.12", path = "../models", features = [
"validator", "validator",
] } ] }
revolt-presence = { version = "0.7.11", path = "../presence" } revolt-presence = { version = "0.7.12", path = "../presence" }
revolt-permissions = { version = "0.7.11", path = "../permissions", features = [ revolt-permissions = { version = "0.7.12", path = "../permissions", features = [
"serde", "serde",
"bson", "bson",
] } ] }
@@ -4,8 +4,8 @@ use indexmap::{IndexMap, IndexSet};
use iso8601_timestamp::Timestamp; use iso8601_timestamp::Timestamp;
use revolt_config::{config, FeaturesLimits}; use revolt_config::{config, FeaturesLimits};
use revolt_models::v0::{ use revolt_models::v0::{
self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageSort, MessageWebhook, self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageFlags, MessageSort,
PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION, MessageWebhook, PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION,
}; };
use revolt_permissions::{ChannelPermission, PermissionValue}; use revolt_permissions::{ChannelPermission, PermissionValue};
use revolt_result::Result; use revolt_result::Result;
@@ -65,6 +65,10 @@ auto_derived_partial!(
/// Name and / or avatar overrides for this message /// Name and / or avatar overrides for this message
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub masquerade: Option<Masquerade>, pub masquerade: Option<Masquerade>,
/// Bitfield of message flags
#[serde(skip_serializing_if = "Option::is_none")]
pub flags: Option<i32>,
}, },
"PartialMessage" "PartialMessage"
); );
@@ -200,6 +204,7 @@ impl Default for Message {
reactions: Default::default(), reactions: Default::default(),
interactions: Default::default(), interactions: Default::default(),
masquerade: None, masquerade: None,
flags: None,
} }
} }
} }
@@ -241,6 +246,13 @@ impl Message {
return Err(create_error!(EmptyMessage)); return Err(create_error!(EmptyMessage));
} }
// Ensure flags are either not set or have permissible values
if let Some(flags) = &data.flags {
if flags != &0 && flags != &1 {
return Err(create_error!(InvalidProperty));
}
}
// Ensure restrict_reactions is not specified without reactions list // Ensure restrict_reactions is not specified without reactions list
if let Some(interactions) = &data.interactions { if let Some(interactions) = &data.interactions {
if interactions.restrict_reactions { if interactions.restrict_reactions {
@@ -274,6 +286,7 @@ impl Message {
.unwrap_or_default(), .unwrap_or_default(),
author: author_id, author: author_id,
webhook: webhook.map(|w| w.into()), webhook: webhook.map(|w| w.into()),
flags: data.flags.map(|v| v as i32),
..Default::default() ..Default::default()
}; };
@@ -438,6 +451,7 @@ impl Message {
) )
.await?; .await?;
if !self.has_suppressed_notifications() {
// Push out Web Push notifications // Push out Web Push notifications
crate::tasks::web_push::queue( crate::tasks::web_push::queue(
{ {
@@ -456,6 +470,7 @@ impl Message {
.await, .await,
) )
.await; .await;
}
Ok(()) Ok(())
} }
@@ -487,6 +502,16 @@ impl Message {
})) }))
} }
/// Whether this message has suppressed notifications
pub fn has_suppressed_notifications(&self) -> bool {
if let Some(flags) = self.flags {
flags & MessageFlags::SupressNotifications as i32
== MessageFlags::SupressNotifications as i32
} else {
false
}
}
/// Update message data /// Update message data
pub async fn update(&mut self, db: &Database, partial: PartialMessage) -> Result<()> { pub async fn update(&mut self, db: &Database, partial: PartialMessage) -> Result<()> {
self.apply_options(partial.clone()); self.apply_options(partial.clone());
@@ -61,6 +61,7 @@ auto_derived!(
StatusPresence, StatusPresence,
ProfileContent, ProfileContent,
ProfileBackground, ProfileBackground,
DisplayName,
} }
/// User's relationship with another user (or themselves) /// User's relationship with another user (or themselves)
@@ -657,6 +658,7 @@ impl User {
x.background = None; x.background = None;
} }
} }
FieldsUser::DisplayName => self.display_name = None,
} }
} }
@@ -326,6 +326,7 @@ impl IntoDocumentPath for FieldsUser {
FieldsUser::ProfileContent => "profile.content", FieldsUser::ProfileContent => "profile.content",
FieldsUser::StatusPresence => "status.presence", FieldsUser::StatusPresence => "status.presence",
FieldsUser::StatusText => "status.text", FieldsUser::StatusText => "status.text",
FieldsUser::DisplayName => "display_name",
}) })
} }
} }
+9 -5
View File
@@ -470,7 +470,7 @@ impl crate::Message {
member, member,
webhook: self.webhook, webhook: self.webhook,
content: self.content, content: self.content,
system: self.system.map(|system| system.into()), system: self.system.map(Into::into),
attachments: self attachments: self
.attachments .attachments
.map(|v| v.into_iter().map(|f| f.into()).collect()), .map(|v| v.into_iter().map(|f| f.into()).collect()),
@@ -480,7 +480,8 @@ impl crate::Message {
replies: self.replies, replies: self.replies,
reactions: self.reactions, reactions: self.reactions,
interactions: self.interactions.into(), interactions: self.interactions.into(),
masquerade: self.masquerade.map(|masq| masq.into()), masquerade: self.masquerade.map(Into::into),
flags: self.flags.map(|flags| flags as u32).unwrap_or_default(),
} }
} }
} }
@@ -496,7 +497,7 @@ impl From<crate::PartialMessage> for PartialMessage {
member: None, member: None,
webhook: value.webhook, webhook: value.webhook,
content: value.content, content: value.content,
system: value.system.map(|system| system.into()), system: value.system.map(Into::into),
attachments: value attachments: value
.attachments .attachments
.map(|v| v.into_iter().map(|f| f.into()).collect()), .map(|v| v.into_iter().map(|f| f.into()).collect()),
@@ -505,8 +506,9 @@ impl From<crate::PartialMessage> for PartialMessage {
mentions: value.mentions, mentions: value.mentions,
replies: value.replies, replies: value.replies,
reactions: value.reactions, reactions: value.reactions,
interactions: value.interactions.map(|interactions| interactions.into()), interactions: value.interactions.map(Into::into),
masquerade: value.masquerade.map(|masq| masq.into()), masquerade: value.masquerade.map(Into::into),
flags: value.flags.map(|flags| flags as u32),
} }
} }
} }
@@ -1212,6 +1214,7 @@ impl From<FieldsUser> for crate::FieldsUser {
FieldsUser::ProfileContent => crate::FieldsUser::ProfileContent, FieldsUser::ProfileContent => crate::FieldsUser::ProfileContent,
FieldsUser::StatusPresence => crate::FieldsUser::StatusPresence, FieldsUser::StatusPresence => crate::FieldsUser::StatusPresence,
FieldsUser::StatusText => crate::FieldsUser::StatusText, FieldsUser::StatusText => crate::FieldsUser::StatusText,
FieldsUser::DisplayName => crate::FieldsUser::DisplayName,
} }
} }
} }
@@ -1224,6 +1227,7 @@ impl From<crate::FieldsUser> for FieldsUser {
crate::FieldsUser::ProfileContent => FieldsUser::ProfileContent, crate::FieldsUser::ProfileContent => FieldsUser::ProfileContent,
crate::FieldsUser::StatusPresence => FieldsUser::StatusPresence, crate::FieldsUser::StatusPresence => FieldsUser::StatusPresence,
crate::FieldsUser::StatusText => FieldsUser::StatusText, crate::FieldsUser::StatusText => FieldsUser::StatusText,
crate::FieldsUser::DisplayName => FieldsUser::DisplayName,
} }
} }
} }
@@ -53,6 +53,12 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
if let Some(other_user) = &self.user { if let Some(other_user) = &self.user {
if self.perspective.id == other_user.id { if self.perspective.id == other_user.id {
return RelationshipStatus::User; return RelationshipStatus::User;
} else if let Some(bot) = &other_user.bot {
// For the purposes of permissions checks,
// assume owner is the same as bot
if self.perspective.id == bot.owner {
return RelationshipStatus::User;
}
} }
if let Some(relations) = &self.perspective.relations { if let Some(relations) = &self.perspective.relations {
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-models" name = "revolt-models"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
@@ -19,8 +19,8 @@ default = ["serde", "partials", "rocket"]
[dependencies] [dependencies]
# Core # Core
revolt-config = { version = "0.7.11", path = "../config" } revolt-config = { version = "0.7.12", path = "../config" }
revolt-permissions = { version = "0.7.11", path = "../permissions" } revolt-permissions = { version = "0.7.12", path = "../permissions" }
# Utility # Utility
regex = "1" regex = "1"
+21
View File
@@ -70,6 +70,15 @@ auto_derived_partial!(
/// Name and / or avatar overrides for this message /// Name and / or avatar overrides for this message
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub masquerade: Option<Masquerade>, pub masquerade: Option<Masquerade>,
/// Bitfield of message flags
///
/// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.MessageFlags.html
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "crate::if_zero_u32", default)
)]
pub flags: u32,
}, },
"PartialMessage" "PartialMessage"
); );
@@ -247,6 +256,11 @@ auto_derived!(
pub masquerade: Option<Masquerade>, pub masquerade: Option<Masquerade>,
/// Information about how this message should be interacted with /// Information about how this message should be interacted with
pub interactions: Option<Interactions>, pub interactions: Option<Interactions>,
/// Bitfield of message flags
///
/// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.MessageFlags.html
pub flags: Option<u32>,
} }
/// Options for querying messages /// Options for querying messages
@@ -334,6 +348,13 @@ auto_derived!(
/// Remove all reactions /// Remove all reactions
pub remove_all: Option<bool>, pub remove_all: Option<bool>,
} }
/// Message flag bitfield
#[repr(u32)]
pub enum MessageFlags {
/// Message will not send push / desktop notifications
SupressNotifications = 1,
}
); );
/// Message Author Abstraction /// Message Author Abstraction
+5
View File
@@ -42,6 +42,8 @@ auto_derived_partial!(
pub relations: Vec<Relationship>, pub relations: Vec<Relationship>,
/// Bitfield of user badges /// Bitfield of user badges
///
/// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.UserBadges.html
#[cfg_attr( #[cfg_attr(
feature = "serde", feature = "serde",
serde(skip_serializing_if = "crate::if_zero_u32", default) serde(skip_serializing_if = "crate::if_zero_u32", default)
@@ -52,6 +54,8 @@ auto_derived_partial!(
pub status: Option<UserStatus>, pub status: Option<UserStatus>,
/// Enum of user flags /// Enum of user flags
///
/// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.UserFlags.html
#[cfg_attr( #[cfg_attr(
feature = "serde", feature = "serde",
serde(skip_serializing_if = "crate::if_zero_u32", default) serde(skip_serializing_if = "crate::if_zero_u32", default)
@@ -83,6 +87,7 @@ auto_derived!(
StatusPresence, StatusPresence,
ProfileContent, ProfileContent,
ProfileBackground, ProfileBackground,
DisplayName,
} }
/// User's relationship with another user (or themselves) /// User's relationship with another user (or themselves)
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-permissions" name = "revolt-permissions"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
@@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
[dependencies] [dependencies]
# Core # Core
revolt-result = { version = "0.7.11", path = "../result" } revolt-result = { version = "0.7.12", path = "../result" }
# Utility # Utility
auto_ops = "0.3.0" auto_ops = "0.3.0"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-presence" name = "revolt-presence"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-result" name = "revolt-result"
version = "0.7.11" version = "0.7.12"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"] authors = ["Paul Makles <me@insrt.uk>"]
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-delta" name = "revolt-delta"
version = "0.7.11" version = "0.7.12"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
authors = ["Paul Makles <paulmakles@gmail.com>"] authors = ["Paul Makles <paulmakles@gmail.com>"]
edition = "2018" edition = "2018"
+7 -4
View File
@@ -24,23 +24,26 @@ pub async fn edit(
}) })
})?; })?;
// Filter out invalid edit fields
if !user.privileged && (data.badges.is_some() || data.flags.is_some()) {
return Err(create_error!(NotPrivileged));
}
// If we want to edit a different user than self, ensure we have // If we want to edit a different user than self, ensure we have
// permissions and subsequently replace the user in question // permissions and subsequently replace the user in question
if target.id != "@me" && target.id != user.id { if target.id != "@me" && target.id != user.id {
let target_user = target.as_user(db).await?; let target_user = target.as_user(db).await?;
let is_bot_owner = target_user let is_bot_owner = target_user
.bot .bot
.as_ref()
.map(|bot| bot.owner == user.id) .map(|bot| bot.owner == user.id)
.unwrap_or_default(); .unwrap_or_default();
if !is_bot_owner && !user.privileged { if !is_bot_owner && !user.privileged {
return Err(create_error!(NotPrivileged)); return Err(create_error!(NotPrivileged));
} }
}
// Otherwise, filter out invalid edit fields user = target_user;
if !user.privileged && (data.badges.is_some() || data.flags.is_some()) {
return Err(create_error!(NotPrivileged));
} }
// Exit out early if nothing is changed // Exit out early if nothing is changed