forked from jmug/stoatchat
feat: policy changes API
chore: bump version to 0.8.7
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@@ -5954,7 +5954,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-autumn"
|
name = "revolt-autumn"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
@@ -5991,7 +5991,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.3.1",
|
"async-channel 2.3.1",
|
||||||
"async-std",
|
"async-std",
|
||||||
@@ -6021,7 +6021,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"cached",
|
"cached",
|
||||||
@@ -6038,7 +6038,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-crond"
|
name = "revolt-crond"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"revolt-config",
|
"revolt-config",
|
||||||
@@ -6050,7 +6050,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"amqprs",
|
"amqprs",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
@@ -6100,7 +6100,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"amqprs",
|
"amqprs",
|
||||||
"async-channel 1.9.0",
|
"async-channel 1.9.0",
|
||||||
@@ -6147,7 +6147,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-files"
|
name = "revolt-files"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"aws-config",
|
"aws-config",
|
||||||
@@ -6170,7 +6170,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-january"
|
name = "revolt-january"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -6198,7 +6198,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"iso8601-timestamp",
|
"iso8601-timestamp",
|
||||||
@@ -6217,14 +6217,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-parser"
|
name = "revolt-parser"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"logos",
|
"logos",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -6239,7 +6239,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"log",
|
"log",
|
||||||
@@ -6250,7 +6250,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-pushd"
|
name = "revolt-pushd"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"amqprs",
|
"amqprs",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -6278,7 +6278,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"revolt_okapi",
|
"revolt_okapi",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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.8.6", path = "../core/permissions" }
|
revolt-permissions = { version = "0.8.7", path = "../core/permissions" }
|
||||||
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
||||||
|
|
||||||
# redis
|
# redis
|
||||||
|
|||||||
@@ -100,6 +100,18 @@ impl State {
|
|||||||
let user = self.clone_user();
|
let user = self.clone_user();
|
||||||
self.cache.is_bot = user.bot.is_some();
|
self.cache.is_bot = user.bot.is_some();
|
||||||
|
|
||||||
|
// Fetch pending policy changes.
|
||||||
|
let policy_changes = if user.bot.is_some() {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
db.fetch_policy_changes()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter(|policy| policy.created_time > user.last_acknowledged_policy_change)
|
||||||
|
.map(Into::into)
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
// Find all relationships to the user.
|
// Find all relationships to the user.
|
||||||
let mut user_ids: HashSet<String> = user
|
let mut user_ids: HashSet<String> = user
|
||||||
.relations
|
.relations
|
||||||
@@ -227,6 +239,7 @@ impl State {
|
|||||||
for channel in &channels {
|
for channel in &channels {
|
||||||
self.insert_subscription(channel.id().to_string()).await;
|
self.insert_subscription(channel.id().to_string()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(EventV1::Ready {
|
Ok(EventV1::Ready {
|
||||||
users: if fields.contains(&ReadyPayloadFields::Users) {
|
users: if fields.contains(&ReadyPayloadFields::Users) {
|
||||||
Some(users)
|
Some(users)
|
||||||
@@ -252,6 +265,8 @@ impl State {
|
|||||||
|
|
||||||
user_settings,
|
user_settings,
|
||||||
channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()),
|
channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()),
|
||||||
|
|
||||||
|
policy_changes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -36,4 +36,4 @@ sentry = "0.31.5"
|
|||||||
sentry-anyhow = { version = "0.38.1", optional = true }
|
sentry-anyhow = { version = "0.38.1", optional = true }
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
revolt-result = { version = "0.8.6", path = "../result", optional = true }
|
revolt-result = { version = "0.8.7", path = "../result", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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>"]
|
||||||
@@ -24,19 +24,19 @@ default = ["mongodb", "async-std-runtime", "tasks"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.8.6", path = "../config", features = [
|
revolt-config = { version = "0.8.7", path = "../config", features = [
|
||||||
"report-macros",
|
"report-macros",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.8.6", path = "../result" }
|
revolt-result = { version = "0.8.7", path = "../result" }
|
||||||
revolt-models = { version = "0.8.6", path = "../models", features = [
|
revolt-models = { version = "0.8.7", path = "../models", features = [
|
||||||
"validator",
|
"validator",
|
||||||
] }
|
] }
|
||||||
revolt-presence = { version = "0.8.6", path = "../presence" }
|
revolt-presence = { version = "0.8.7", path = "../presence" }
|
||||||
revolt-permissions = { version = "0.8.6", path = "../permissions", features = [
|
revolt-permissions = { version = "0.8.7", path = "../permissions", features = [
|
||||||
"serde",
|
"serde",
|
||||||
"bson",
|
"bson",
|
||||||
] }
|
] }
|
||||||
revolt-parser = { version = "0.8.6", path = "../parser" }
|
revolt-parser = { version = "0.8.7", path = "../parser" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use futures::lock::Mutex;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, FileHash, Invite, Member,
|
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, FileHash, Invite, Member,
|
||||||
MemberCompositeKey, Message, RatelimitEvent, Report, Server, ServerBan, Snapshot, User,
|
MemberCompositeKey, Message, PolicyChange, RatelimitEvent, Report, Server, ServerBan, Snapshot,
|
||||||
UserSettings, Webhook,
|
User, UserSettings, Webhook,
|
||||||
};
|
};
|
||||||
|
|
||||||
database_derived!(
|
database_derived!(
|
||||||
@@ -21,6 +21,7 @@ database_derived!(
|
|||||||
pub file_hashes: Arc<Mutex<HashMap<String, FileHash>>>,
|
pub file_hashes: Arc<Mutex<HashMap<String, FileHash>>>,
|
||||||
pub files: Arc<Mutex<HashMap<String, File>>>,
|
pub files: Arc<Mutex<HashMap<String, File>>>,
|
||||||
pub messages: Arc<Mutex<HashMap<String, Message>>>,
|
pub messages: Arc<Mutex<HashMap<String, Message>>>,
|
||||||
|
pub policy_changes: Arc<Mutex<HashMap<String, PolicyChange>>>,
|
||||||
pub ratelimit_events: Arc<Mutex<HashMap<String, RatelimitEvent>>>,
|
pub ratelimit_events: Arc<Mutex<HashMap<String, RatelimitEvent>>>,
|
||||||
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
||||||
pub users: Arc<Mutex<HashMap<String, User>>>,
|
pub users: Arc<Mutex<HashMap<String, User>>>,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use revolt_models::v0::{
|
|||||||
AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsMessage,
|
AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsMessage,
|
||||||
FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message,
|
FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message,
|
||||||
PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser,
|
PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser,
|
||||||
PartialWebhook, RemovalIntention, Report, Server, User, UserSettings, Webhook,
|
PartialWebhook, PolicyChange, RemovalIntention, Report, Server, User, UserSettings, Webhook,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
@@ -62,6 +62,8 @@ pub enum EventV1 {
|
|||||||
user_settings: Option<UserSettings>,
|
user_settings: Option<UserSettings>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
channel_unreads: Option<Vec<ChannelUnread>>,
|
channel_unreads: Option<Vec<ChannelUnread>>,
|
||||||
|
|
||||||
|
policy_changes: Vec<PolicyChange>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Ping response
|
/// Ping response
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ pub async fn create_database(db: &MongoDb) {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to create user_settings collection.");
|
.expect("Failed to create user_settings collection.");
|
||||||
|
|
||||||
|
db.create_collection("policy_changes")
|
||||||
|
.await
|
||||||
|
.expect("Failed to create policy_changes collection.");
|
||||||
|
|
||||||
db.create_collection("safety_reports")
|
db.create_collection("safety_reports")
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create safety_reports collection.");
|
.expect("Failed to create safety_reports collection.");
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ use crate::{
|
|||||||
bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document},
|
bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document},
|
||||||
options::FindOptions,
|
options::FindOptions,
|
||||||
},
|
},
|
||||||
AbstractChannels, AbstractServers, Channel, Invite, MongoDb, DISCRIMINATOR_SEARCH_SPACE,
|
AbstractChannels, AbstractServers, Channel, Invite, MongoDb, User, DISCRIMINATOR_SEARCH_SPACE,
|
||||||
};
|
};
|
||||||
use bson::oid::ObjectId;
|
use bson::{oid::ObjectId, to_bson};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
|
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
|
||||||
use revolt_result::{Error, ErrorType};
|
use revolt_result::{Error, ErrorType};
|
||||||
@@ -21,7 +22,7 @@ struct MigrationInfo {
|
|||||||
revision: i32,
|
revision: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LATEST_REVISION: i32 = 33; // MUST BE +1 to last migration
|
pub const LATEST_REVISION: i32 = 41; // MUST BE +1 to last migration
|
||||||
|
|
||||||
pub async fn migrate_database(db: &MongoDb) {
|
pub async fn migrate_database(db: &MongoDb) {
|
||||||
let migrations = db.col::<Document>("migrations");
|
let migrations = db.col::<Document>("migrations");
|
||||||
@@ -1139,6 +1140,31 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if revision <= 40 {
|
||||||
|
info!(
|
||||||
|
"Running migration [revision |> 40 / 30-05-2025]: Set last policy acknowlegement date to now and create policy changes collection."
|
||||||
|
);
|
||||||
|
|
||||||
|
db.db()
|
||||||
|
.create_collection("policy_changes")
|
||||||
|
.await
|
||||||
|
.expect("Failed to create policy_changes collection.");
|
||||||
|
|
||||||
|
db.db()
|
||||||
|
.collection::<User>("users")
|
||||||
|
.update_many(
|
||||||
|
doc! {},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"last_acknowledged_policy_change": to_bson(&Timestamp::now_utc())
|
||||||
|
.expect("failed to serialise timestamp")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("failed to update users");
|
||||||
|
}
|
||||||
|
|
||||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||||
LATEST_REVISION.max(revision)
|
LATEST_REVISION.max(revision)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ mod emojis;
|
|||||||
mod file_hashes;
|
mod file_hashes;
|
||||||
mod files;
|
mod files;
|
||||||
mod messages;
|
mod messages;
|
||||||
|
mod policy_changes;
|
||||||
mod ratelimit_events;
|
mod ratelimit_events;
|
||||||
mod safety_reports;
|
mod safety_reports;
|
||||||
mod safety_snapshots;
|
mod safety_snapshots;
|
||||||
@@ -27,6 +28,7 @@ pub use emojis::*;
|
|||||||
pub use file_hashes::*;
|
pub use file_hashes::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
pub use messages::*;
|
pub use messages::*;
|
||||||
|
pub use policy_changes::*;
|
||||||
pub use ratelimit_events::*;
|
pub use ratelimit_events::*;
|
||||||
pub use safety_reports::*;
|
pub use safety_reports::*;
|
||||||
pub use safety_snapshots::*;
|
pub use safety_snapshots::*;
|
||||||
@@ -51,6 +53,7 @@ pub trait AbstractDatabase:
|
|||||||
+ file_hashes::AbstractAttachmentHashes
|
+ file_hashes::AbstractAttachmentHashes
|
||||||
+ files::AbstractAttachments
|
+ files::AbstractAttachments
|
||||||
+ messages::AbstractMessages
|
+ messages::AbstractMessages
|
||||||
|
+ policy_changes::AbstractPolicyChange
|
||||||
+ ratelimit_events::AbstractRatelimitEvents
|
+ ratelimit_events::AbstractRatelimitEvents
|
||||||
+ safety_reports::AbstractReport
|
+ safety_reports::AbstractReport
|
||||||
+ safety_snapshots::AbstractSnapshot
|
+ safety_snapshots::AbstractSnapshot
|
||||||
|
|||||||
5
crates/core/database/src/models/policy_changes/mod.rs
Normal file
5
crates/core/database/src/models/policy_changes/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod model;
|
||||||
|
mod ops;
|
||||||
|
|
||||||
|
pub use model::*;
|
||||||
|
pub use ops::*;
|
||||||
20
crates/core/database/src/models/policy_changes/model.rs
Normal file
20
crates/core/database/src/models/policy_changes/model.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
|
|
||||||
|
auto_derived!(
|
||||||
|
/// Platform policy change
|
||||||
|
pub struct PolicyChange {
|
||||||
|
/// Unique Id
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
pub id: String,
|
||||||
|
|
||||||
|
/// Time at which this policy was created
|
||||||
|
pub created_time: Timestamp,
|
||||||
|
/// Time at which this policy is effective
|
||||||
|
pub effective_time: Timestamp,
|
||||||
|
|
||||||
|
/// Message shown to users
|
||||||
|
pub description: String,
|
||||||
|
/// URL with details about changes
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
15
crates/core/database/src/models/policy_changes/ops.rs
Normal file
15
crates/core/database/src/models/policy_changes/ops.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use revolt_result::Result;
|
||||||
|
|
||||||
|
use crate::PolicyChange;
|
||||||
|
|
||||||
|
mod mongodb;
|
||||||
|
mod reference;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait AbstractPolicyChange: Sync + Send {
|
||||||
|
/// Fetch all policy changes
|
||||||
|
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>>;
|
||||||
|
|
||||||
|
/// Acknowledge policy changes
|
||||||
|
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use bson::to_bson;
|
||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
|
use revolt_result::Result;
|
||||||
|
|
||||||
|
use crate::MongoDb;
|
||||||
|
use crate::PolicyChange;
|
||||||
|
use crate::User;
|
||||||
|
|
||||||
|
use super::AbstractPolicyChange;
|
||||||
|
|
||||||
|
static COL: &str = "policy_changes";
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl AbstractPolicyChange for MongoDb {
|
||||||
|
/// Fetch all policy changes
|
||||||
|
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>> {
|
||||||
|
query!(self, find, COL, doc! {})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acknowledge policy changes
|
||||||
|
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()> {
|
||||||
|
let latest_policy = self
|
||||||
|
.fetch_policy_changes()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|policy| policy.created_time)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(Timestamp::UNIX_EPOCH);
|
||||||
|
|
||||||
|
self.col::<User>("users")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": user_id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"last_acknowledged_policy_change": to_bson(&latest_policy)
|
||||||
|
.map_err(|_| create_database_error!("to_bson", "timestamp"))?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| create_database_error!("update_one", COL))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
|
use revolt_result::Result;
|
||||||
|
|
||||||
|
use crate::PolicyChange;
|
||||||
|
use crate::ReferenceDb;
|
||||||
|
|
||||||
|
use super::AbstractPolicyChange;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl AbstractPolicyChange for ReferenceDb {
|
||||||
|
/// Fetch all policy changes
|
||||||
|
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>> {
|
||||||
|
let policy_changes = self.policy_changes.lock().await;
|
||||||
|
Ok(policy_changes.values().cloned().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acknowledge policy changes
|
||||||
|
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()> {
|
||||||
|
let mut users = self.users.lock().await;
|
||||||
|
let user = users.get_mut(user_id).expect("user doesn't exist");
|
||||||
|
user.last_acknowledged_policy_change = self
|
||||||
|
.fetch_policy_changes()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|policy| policy.created_time)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(Timestamp::UNIX_EPOCH);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,8 @@ auto_derived_partial!(
|
|||||||
/// Time until user is unsuspended
|
/// Time until user is unsuspended
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub suspended_until: Option<Timestamp>,
|
pub suspended_until: Option<Timestamp>,
|
||||||
|
/// Last acknowledged policy change
|
||||||
|
pub last_acknowledged_policy_change: Timestamp,
|
||||||
},
|
},
|
||||||
"PartialUser"
|
"PartialUser"
|
||||||
);
|
);
|
||||||
@@ -178,6 +180,7 @@ impl Default for User {
|
|||||||
privileged: Default::default(),
|
privileged: Default::default(),
|
||||||
bot: Default::default(),
|
bot: Default::default(),
|
||||||
suspended_until: Default::default(),
|
suspended_until: Default::default(),
|
||||||
|
last_acknowledged_policy_change: Timestamp::UNIX_EPOCH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,6 +203,7 @@ impl User {
|
|||||||
id: account_id.into().unwrap_or_else(|| Ulid::new().to_string()),
|
id: account_id.into().unwrap_or_else(|| Ulid::new().to_string()),
|
||||||
discriminator: User::find_discriminator(db, &username, None).await?,
|
discriminator: User::find_discriminator(db, &username, None).await?,
|
||||||
username,
|
username,
|
||||||
|
last_acknowledged_policy_change: Timestamp::now_utc(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
use revolt_models::v0::*;
|
use revolt_models::v0::*;
|
||||||
use revolt_permissions::{calculate_user_permissions, UserPermission};
|
use revolt_permissions::{calculate_user_permissions, UserPermission};
|
||||||
|
|
||||||
@@ -597,6 +598,17 @@ impl From<Masquerade> for crate::Masquerade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<crate::PolicyChange> for PolicyChange {
|
||||||
|
fn from(value: crate::PolicyChange) -> Self {
|
||||||
|
PolicyChange {
|
||||||
|
created_time: value.created_time,
|
||||||
|
effective_time: value.effective_time,
|
||||||
|
description: value.description,
|
||||||
|
url: value.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<crate::Report> for Report {
|
impl From<crate::Report> for Report {
|
||||||
fn from(value: crate::Report) -> Self {
|
fn from(value: crate::Report) -> Self {
|
||||||
Report {
|
Report {
|
||||||
@@ -1188,6 +1200,7 @@ impl From<User> for crate::User {
|
|||||||
privileged: value.privileged,
|
privileged: value.privileged,
|
||||||
bot: value.bot.map(Into::into),
|
bot: value.bot.map(Into::into),
|
||||||
suspended_until: None,
|
suspended_until: None,
|
||||||
|
last_acknowledged_policy_change: Timestamp::UNIX_EPOCH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-files"
|
name = "revolt-files"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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>"]
|
||||||
@@ -20,10 +20,10 @@ typenum = "1.17.0"
|
|||||||
aws-config = "1.5.5"
|
aws-config = "1.5.5"
|
||||||
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }
|
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }
|
||||||
|
|
||||||
revolt-config = { version = "0.8.6", path = "../config", features = [
|
revolt-config = { version = "0.8.7", path = "../config", features = [
|
||||||
"report-macros",
|
"report-macros",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.8.6", path = "../result" }
|
revolt-result = { version = "0.8.7", path = "../result" }
|
||||||
|
|
||||||
# image processing
|
# image processing
|
||||||
jxl-oxide = "0.8.1"
|
jxl-oxide = "0.8.1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -20,8 +20,8 @@ default = ["serde", "partials", "rocket"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.8.6", path = "../config" }
|
revolt-config = { version = "0.8.7", path = "../config" }
|
||||||
revolt-permissions = { version = "0.8.6", path = "../permissions" }
|
revolt-permissions = { version = "0.8.7", path = "../permissions" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
regex = "1.11"
|
regex = "1.11"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ mod embeds;
|
|||||||
mod emojis;
|
mod emojis;
|
||||||
mod files;
|
mod files;
|
||||||
mod messages;
|
mod messages;
|
||||||
|
mod policy_changes;
|
||||||
mod safety_reports;
|
mod safety_reports;
|
||||||
mod server_bans;
|
mod server_bans;
|
||||||
mod server_members;
|
mod server_members;
|
||||||
@@ -23,6 +24,7 @@ pub use embeds::*;
|
|||||||
pub use emojis::*;
|
pub use emojis::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
pub use messages::*;
|
pub use messages::*;
|
||||||
|
pub use policy_changes::*;
|
||||||
pub use safety_reports::*;
|
pub use safety_reports::*;
|
||||||
pub use server_bans::*;
|
pub use server_bans::*;
|
||||||
pub use server_members::*;
|
pub use server_members::*;
|
||||||
|
|||||||
16
crates/core/models/src/v0/policy_changes.rs
Normal file
16
crates/core/models/src/v0/policy_changes.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use iso8601_timestamp::Timestamp;
|
||||||
|
|
||||||
|
auto_derived!(
|
||||||
|
/// Platform policy change
|
||||||
|
pub struct PolicyChange {
|
||||||
|
/// Time at which this policy was created
|
||||||
|
pub created_time: Timestamp,
|
||||||
|
/// Time at which this policy is effective
|
||||||
|
pub effective_time: Timestamp,
|
||||||
|
|
||||||
|
/// Message shown to users
|
||||||
|
pub description: String,
|
||||||
|
/// URL with details about changes
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-parser"
|
name = "revolt-parser"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
description = "Revolt Backend: Message Parser"
|
description = "Revolt Backend: Message Parser"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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.8.6", path = "../result" }
|
revolt-result = { version = "0.8.7", path = "../result" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
auto_ops = "0.3.0"
|
auto_ops = "0.3.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-crond"
|
name = "revolt-crond"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -16,7 +16,7 @@ log = "0.4"
|
|||||||
tokio = { version = "1" }
|
tokio = { version = "1" }
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
revolt-database = { version = "0.8.6", path = "../../core/database" }
|
revolt-database = { version = "0.8.7", path = "../../core/database" }
|
||||||
revolt-result = { version = "0.8.6", path = "../../core/result" }
|
revolt-result = { version = "0.8.7", path = "../../core/result" }
|
||||||
revolt-config = { version = "0.8.6", path = "../../core/config" }
|
revolt-config = { version = "0.8.7", path = "../../core/config" }
|
||||||
revolt-files = { version = "0.8.6", path = "../../core/files" }
|
revolt-files = { version = "0.8.7", path = "../../core/files" }
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-pushd"
|
name = "revolt-pushd"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
revolt-result = { version = "0.8.6", path = "../../core/result" }
|
revolt-result = { version = "0.8.7", path = "../../core/result" }
|
||||||
revolt-config = { version = "0.8.6", path = "../../core/config", features = [
|
revolt-config = { version = "0.8.7", path = "../../core/config", features = [
|
||||||
"report-macros",
|
"report-macros",
|
||||||
] }
|
] }
|
||||||
revolt-database = { version = "0.8.6", path = "../../core/database" }
|
revolt-database = { version = "0.8.7", path = "../../core/database" }
|
||||||
revolt-models = { version = "0.8.6", path = "../../core/models", features = [
|
revolt-models = { version = "0.8.7", path = "../../core/models", features = [
|
||||||
"validator",
|
"validator",
|
||||||
] }
|
] }
|
||||||
revolt-presence = { version = "0.8.6", path = "../../core/presence", features = [
|
revolt-presence = { version = "0.8.7", path = "../../core/presence", features = [
|
||||||
"redis-is-patched",
|
"redis-is-patched",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
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"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ mod channels;
|
|||||||
mod customisation;
|
mod customisation;
|
||||||
mod invites;
|
mod invites;
|
||||||
mod onboard;
|
mod onboard;
|
||||||
|
mod policy;
|
||||||
mod push;
|
mod push;
|
||||||
mod root;
|
mod root;
|
||||||
mod safety;
|
mod safety;
|
||||||
@@ -36,6 +37,7 @@ pub fn mount(config: Settings, mut rocket: Rocket<Build>) -> Rocket<Build> {
|
|||||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||||
"/onboard" => onboard::routes(),
|
"/onboard" => onboard::routes(),
|
||||||
|
"/policy" => policy::routes(),
|
||||||
"/push" => push::routes(),
|
"/push" => push::routes(),
|
||||||
"/sync" => sync::routes(),
|
"/sync" => sync::routes(),
|
||||||
"/webhooks" => webhooks::routes()
|
"/webhooks" => webhooks::routes()
|
||||||
@@ -56,6 +58,7 @@ pub fn mount(config: Settings, mut rocket: Rocket<Build>) -> Rocket<Build> {
|
|||||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||||
"/onboard" => onboard::routes(),
|
"/onboard" => onboard::routes(),
|
||||||
|
"/policy" => policy::routes(),
|
||||||
"/push" => push::routes(),
|
"/push" => push::routes(),
|
||||||
"/sync" => sync::routes()
|
"/sync" => sync::routes()
|
||||||
};
|
};
|
||||||
|
|||||||
17
crates/delta/src/routes/policy/acknowledge_policy_changes.rs
Normal file
17
crates/delta/src/routes/policy/acknowledge_policy_changes.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use revolt_database::{events::client::EventV1, Database, Report, Snapshot, SnapshotContent, User};
|
||||||
|
use revolt_models::v0::{ReportStatus, ReportedContent};
|
||||||
|
use revolt_result::{create_error, Result};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use ulid::Ulid;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
use rocket::{serde::json::Json, State};
|
||||||
|
|
||||||
|
/// # Acknowledge Policy Changes
|
||||||
|
///
|
||||||
|
/// Accept/acknowledge changes to platform policy.
|
||||||
|
#[openapi(tag = "Policy")]
|
||||||
|
#[post("/acknowledge")]
|
||||||
|
pub async fn acknowledge_policy_changes(db: &State<Database>, user: User) -> Result<()> {
|
||||||
|
db.acknowledge_policy_changes(&user.id).await
|
||||||
|
}
|
||||||
11
crates/delta/src/routes/policy/mod.rs
Normal file
11
crates/delta/src/routes/policy/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||||
|
use rocket::Route;
|
||||||
|
|
||||||
|
mod acknowledge_policy_changes;
|
||||||
|
|
||||||
|
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||||
|
openapi_get_routes_spec![
|
||||||
|
// Policy
|
||||||
|
acknowledge_policy_changes::acknowledge_policy_changes,
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-autumn"
|
name = "revolt-autumn"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ tracing = "0.1"
|
|||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
# Core crates
|
# Core crates
|
||||||
revolt-files = { version = "0.8.6", path = "../../core/files" }
|
revolt-files = { version = "0.8.7", path = "../../core/files" }
|
||||||
revolt-config = { version = "0.8.6", path = "../../core/config" }
|
revolt-config = { version = "0.8.7", path = "../../core/config" }
|
||||||
revolt-database = { version = "0.8.6", path = "../../core/database", features = [
|
revolt-database = { version = "0.8.7", path = "../../core/database", features = [
|
||||||
"axum-impl",
|
"axum-impl",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.8.6", path = "../../core/result", features = [
|
revolt-result = { version = "0.8.7", path = "../../core/result", features = [
|
||||||
"utoipa",
|
"utoipa",
|
||||||
"axum",
|
"axum",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-january"
|
name = "revolt-january"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
@@ -32,13 +32,13 @@ tracing = "0.1"
|
|||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
# Core crates
|
# Core crates
|
||||||
revolt-config = { version = "0.8.6", path = "../../core/config" }
|
revolt-config = { version = "0.8.7", path = "../../core/config" }
|
||||||
revolt-models = { version = "0.8.6", path = "../../core/models" }
|
revolt-models = { version = "0.8.7", path = "../../core/models" }
|
||||||
revolt-result = { version = "0.8.6", path = "../../core/result", features = [
|
revolt-result = { version = "0.8.7", path = "../../core/result", features = [
|
||||||
"utoipa",
|
"utoipa",
|
||||||
"axum",
|
"axum",
|
||||||
] }
|
] }
|
||||||
revolt-files = { version = "0.8.6", path = "../../core/files" }
|
revolt-files = { version = "0.8.7", path = "../../core/files" }
|
||||||
|
|
||||||
# Axum / web server
|
# Axum / web server
|
||||||
axum = { version = "0.7.5" }
|
axum = { version = "0.7.5" }
|
||||||
|
|||||||
Reference in New Issue
Block a user