Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2710edb76b | ||
|
|
8f1ff9e774 | ||
|
|
c09244039e | ||
|
|
bf9108408e | ||
|
|
304336d905 | ||
|
|
42b4906594 |
Generated
+4
-4
@@ -2170,7 +2170,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "optional_struct"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/insertish/OptionalStruct?rev=e275d2726595474632485934aa0887fa52281f70#e275d2726595474632485934aa0887fa52281f70"
|
||||
source = "git+https://github.com/insertish/OptionalStruct?rev=ee56427cee1f007839825d93d07fffd5a5e038c7#ee56427cee1f007839825d93d07fffd5a5e038c7"
|
||||
dependencies = [
|
||||
"quote 0.3.15",
|
||||
"syn 0.11.11",
|
||||
@@ -2792,7 +2792,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-tungstenite",
|
||||
@@ -2808,7 +2808,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-delta"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-std",
|
||||
@@ -2848,7 +2848,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-quark"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"async-recursion",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-delta"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
use revolt_quark::{
|
||||
models::{
|
||||
report::{PartialReport, ReportStatus},
|
||||
Report, User,
|
||||
},
|
||||
Db, Error, Ref, Result,
|
||||
};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::Deserialize;
|
||||
use validator::Validate;
|
||||
|
||||
/// # Report Data
|
||||
#[derive(Validate, Deserialize, JsonSchema)]
|
||||
pub struct DataEditReport {
|
||||
/// New report status
|
||||
status: Option<ReportStatus>,
|
||||
/// Report notes
|
||||
notes: Option<String>,
|
||||
}
|
||||
|
||||
/// # Edit Report
|
||||
///
|
||||
/// Edit a report.
|
||||
#[openapi(tag = "User Safety")]
|
||||
#[patch("/reports/<report>", data = "<edit>")]
|
||||
pub async fn edit_report(
|
||||
db: &Db,
|
||||
user: User,
|
||||
report: Ref,
|
||||
edit: Json<DataEditReport>,
|
||||
) -> Result<Json<Report>> {
|
||||
// Must be privileged for this route
|
||||
if !user.privileged {
|
||||
return Err(Error::NotPrivileged);
|
||||
}
|
||||
|
||||
// Validate data
|
||||
let edit = edit.into_inner();
|
||||
edit.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
// Create and apply update to report
|
||||
let mut report = report.as_report(db).await?;
|
||||
report
|
||||
.update(
|
||||
db,
|
||||
PartialReport {
|
||||
status: edit.status,
|
||||
notes: edit.notes,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(report))
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use revolt_quark::models::{Report, User};
|
||||
use revolt_quark::{Db, Error, Result};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Report
|
||||
///
|
||||
/// Fetch a report by its ID
|
||||
#[openapi(tag = "User Safety")]
|
||||
#[get("/report/<id>")]
|
||||
pub async fn fetch_report(db: &Db, user: User, id: String) -> Result<Json<Report>> {
|
||||
// Must be privileged for this route
|
||||
if !user.privileged {
|
||||
return Err(Error::NotPrivileged);
|
||||
}
|
||||
|
||||
db.fetch_report(&id).await.map(Json)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use revolt_quark::models::{Report, User};
|
||||
use revolt_quark::{Db, Error, Result};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Reports
|
||||
///
|
||||
/// Fetch all available reports
|
||||
#[openapi(tag = "User Safety")]
|
||||
#[get("/reports")]
|
||||
pub async fn fetch_reports(db: &Db, user: User) -> Result<Json<Vec<Report>>> {
|
||||
// Must be privileged for this route
|
||||
if !user.privileged {
|
||||
return Err(Error::NotPrivileged);
|
||||
}
|
||||
|
||||
db.fetch_reports().await.map(Json)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use revolt_quark::models::snapshot::{SnapshotContent, SnapshotWithContext};
|
||||
use revolt_quark::models::{Channel, User};
|
||||
use revolt_quark::{Db, Error, Result};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Snapshot
|
||||
///
|
||||
/// Fetch a snapshot for a given report
|
||||
#[openapi(tag = "User Safety")]
|
||||
#[get("/snapshot/<report_id>")]
|
||||
pub async fn fetch_snapshot(
|
||||
db: &Db,
|
||||
user: User,
|
||||
report_id: String,
|
||||
) -> Result<Json<SnapshotWithContext>> {
|
||||
// Must be privileged for this route
|
||||
if !user.privileged {
|
||||
return Err(Error::NotPrivileged);
|
||||
}
|
||||
|
||||
// Fetch snapshot
|
||||
let snapshot = db.fetch_snapshot(&report_id).await?;
|
||||
|
||||
// Resolve and fetch IDs of associated content
|
||||
let mut user_ids: HashSet<&str> = HashSet::new();
|
||||
let mut channel_ids: HashSet<&str> = HashSet::new();
|
||||
|
||||
match &snapshot.content {
|
||||
SnapshotContent::Message {
|
||||
prior_context,
|
||||
leading_context,
|
||||
message,
|
||||
} => {
|
||||
for msg in prior_context {
|
||||
user_ids.insert(&msg.author);
|
||||
}
|
||||
|
||||
for msg in leading_context {
|
||||
user_ids.insert(&msg.author);
|
||||
}
|
||||
|
||||
user_ids.insert(&message.author);
|
||||
channel_ids.insert(&message.channel);
|
||||
}
|
||||
_ => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// Collect user and channel IDs
|
||||
let user_ids: Vec<String> = user_ids.into_iter().map(|s| s.to_owned()).collect();
|
||||
let channel_ids: Vec<String> = channel_ids.into_iter().map(|s| s.to_owned()).collect();
|
||||
|
||||
// Fetch users and channels
|
||||
let users = db.fetch_users(&user_ids).await?;
|
||||
let channels = db.fetch_channels(&channel_ids).await?;
|
||||
|
||||
// Pull out first server from channels if possible
|
||||
let server = if let Some(server_id) = channels.iter().find_map(|channel| match channel {
|
||||
Channel::TextChannel { server, .. } => Some(server),
|
||||
_ => None,
|
||||
}) {
|
||||
Some(db.fetch_server(server_id).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Return snapshot with context
|
||||
Ok(Json(SnapshotWithContext {
|
||||
snapshot,
|
||||
users,
|
||||
channels,
|
||||
server,
|
||||
}))
|
||||
}
|
||||
@@ -1,11 +1,21 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod edit_report;
|
||||
mod fetch_report;
|
||||
mod fetch_reports;
|
||||
mod report_content;
|
||||
|
||||
mod fetch_snapshot;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
// Reports
|
||||
report_content::report_content
|
||||
edit_report::edit_report,
|
||||
fetch_report::fetch_report,
|
||||
fetch_reports::fetch_reports,
|
||||
report_content::report_content,
|
||||
// Snapshots
|
||||
fetch_snapshot::fetch_snapshot
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use revolt_quark::events::client::EventV1;
|
||||
use revolt_quark::models::report::ReportedContent;
|
||||
use revolt_quark::models::report::{ReportStatus, ReportedContent};
|
||||
use revolt_quark::models::snapshot::{Snapshot, SnapshotContent};
|
||||
use revolt_quark::models::{Report, User};
|
||||
use revolt_quark::{Db, Error, Result};
|
||||
@@ -149,6 +149,8 @@ pub async fn report_content(db: &Db, user: User, data: Json<DataReportContent>)
|
||||
author_id: user.id,
|
||||
content: data.content,
|
||||
additional_context: data.additional_context,
|
||||
status: ReportStatus::Created {},
|
||||
notes: String::new(),
|
||||
};
|
||||
|
||||
db.insert_report(&report).await?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-quark"
|
||||
version = "0.5.9"
|
||||
version = "0.5.12"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
|
||||
@@ -29,7 +29,7 @@ default = [ "test" ]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
validator = { version = "0.14", features = ["derive"] }
|
||||
iso8601-timestamp = { version = "0.1.8", features = ["schema", "bson"] }
|
||||
optional_struct = { git = "https://github.com/insertish/OptionalStruct", rev = "e275d2726595474632485934aa0887fa52281f70" }
|
||||
optional_struct = { git = "https://github.com/insertish/OptionalStruct", rev = "ee56427cee1f007839825d93d07fffd5a5e038c7" }
|
||||
|
||||
# Formats
|
||||
bincode = "1.3.3"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::models::report::PartialReport;
|
||||
use crate::models::Report;
|
||||
use crate::{AbstractReport, Result};
|
||||
|
||||
@@ -9,4 +10,16 @@ impl AbstractReport for DummyDb {
|
||||
info!("Insert {:?}", report);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_report(&self, _id: &str, _report: &PartialReport) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn fetch_report(&self, _report_id: &str) -> Result<Report> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn fetch_reports(&self) -> Result<Vec<Report>> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,8 @@ impl AbstractSnapshot for DummyDb {
|
||||
info!("Insert {:?}", snapshot);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn fetch_snapshot(&self, _report_id: &str) -> Result<Snapshot> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,3 +27,7 @@ pub mod users {
|
||||
pub mod user;
|
||||
pub mod user_settings;
|
||||
}
|
||||
|
||||
pub mod safety {
|
||||
pub mod report;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use crate::{models::report::PartialReport, models::Report, Database, Result};
|
||||
|
||||
impl Report {
|
||||
/// Update report data
|
||||
pub async fn update(&mut self, db: &Database, partial: PartialReport) -> Result<()> {
|
||||
self.apply_options(partial.clone());
|
||||
db.update_report(&self.id, &partial).await
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,14 @@ pub async fn create_database(db: &MongoDb) {
|
||||
.await
|
||||
.expect("Failed to create user_settings collection.");
|
||||
|
||||
db.create_collection("safety_reports", None)
|
||||
.await
|
||||
.expect("Failed to create safety_reports collection.");
|
||||
|
||||
db.create_collection("safety_snapshots", None)
|
||||
.await
|
||||
.expect("Failed to create safety_snapshots collection.");
|
||||
|
||||
db.create_collection("bots", None)
|
||||
.await
|
||||
.expect("Failed to create bots collection.");
|
||||
@@ -103,18 +111,18 @@ pub async fn create_database(db: &MongoDb) {
|
||||
},
|
||||
"name": "content"
|
||||
},
|
||||
{
|
||||
"key": {
|
||||
"channel": 1_i32
|
||||
},
|
||||
"name": "channel"
|
||||
},
|
||||
{
|
||||
"key": {
|
||||
"channel": 1_i32,
|
||||
"_id": 1_i32
|
||||
},
|
||||
"name": "channel_id_compound"
|
||||
},
|
||||
{
|
||||
"key": {
|
||||
"author": 1_i32
|
||||
},
|
||||
"name": "author"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ struct MigrationInfo {
|
||||
revision: i32,
|
||||
}
|
||||
|
||||
pub const LATEST_REVISION: i32 = 18;
|
||||
pub const LATEST_REVISION: i32 = 21;
|
||||
|
||||
pub async fn migrate_database(db: &MongoDb) {
|
||||
let migrations = db.col::<Document>("migrations");
|
||||
@@ -661,6 +661,103 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
.expect("Failed to update server members.");
|
||||
}
|
||||
|
||||
if revision <= 18 {
|
||||
info!("Running migration [revision 18 / 27-02-2022]: Create author index on messages. Drop plain channel index if exists.");
|
||||
|
||||
if db
|
||||
.db()
|
||||
.run_command(
|
||||
doc! {
|
||||
"dropIndexes": "messages",
|
||||
"index": ["channel"]
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
info!("Failed to drop `messages.channel` index but this is ok since that means it's probably gone.");
|
||||
}
|
||||
|
||||
db.db()
|
||||
.run_command(
|
||||
doc! {
|
||||
"createIndexes": "messages",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {
|
||||
"author": 1_i32,
|
||||
},
|
||||
"name": "author"
|
||||
}
|
||||
]
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create messages author index.");
|
||||
}
|
||||
|
||||
if revision <= 19 {
|
||||
info!("Running migration [revision 19 / 27-02-2023]: Create report / snapshot collections, migrate to new model if applicable.");
|
||||
|
||||
// TODO: make these fail once production is migrated
|
||||
if db
|
||||
.db()
|
||||
.create_collection("safety_reports", None)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
info!("Failed to create safety_reports collection but this is expected in production.");
|
||||
}
|
||||
|
||||
if db
|
||||
.db()
|
||||
.create_collection("safety_snapshots", None)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
info!(
|
||||
"Failed to create safety_snapshots collection but this is expected in production."
|
||||
);
|
||||
}
|
||||
|
||||
db.col::<Document>("safety_reports")
|
||||
.update_many(
|
||||
doc! {},
|
||||
doc! {
|
||||
"$set": {
|
||||
"status": "Created"
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if revision <= 20 {
|
||||
info!("Running migration [revision 20 / 28-02-2023]: Add index `snapshot.report_id`.");
|
||||
|
||||
db.db()
|
||||
.run_command(
|
||||
doc! {
|
||||
"createIndexes": "safety_snapshots",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {
|
||||
"report_id": 1_i32
|
||||
},
|
||||
"name": "report_id"
|
||||
}
|
||||
]
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create safety snapshot index.");
|
||||
}
|
||||
|
||||
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
|
||||
|
||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||
|
||||
@@ -97,7 +97,14 @@ impl MongoDb {
|
||||
operation: "find",
|
||||
with: collection,
|
||||
})?
|
||||
.filter_map(|s| async { s.ok() })
|
||||
.filter_map(|s| async {
|
||||
if cfg!(debug_assertions) {
|
||||
// Hard fail on invalid documents
|
||||
Some(s.unwrap())
|
||||
} else {
|
||||
s.ok()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<T>>()
|
||||
.await)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::models::report::PartialReport;
|
||||
use crate::models::Report;
|
||||
use crate::{AbstractReport, Result};
|
||||
|
||||
@@ -10,4 +11,18 @@ impl AbstractReport for MongoDb {
|
||||
async fn insert_report(&self, report: &Report) -> Result<()> {
|
||||
self.insert_one(COL, report).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn update_report(&self, id: &str, report: &PartialReport) -> Result<()> {
|
||||
self.update_one_by_id(COL, id, report, vec![], None)
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn fetch_report(&self, report_id: &str) -> Result<Report> {
|
||||
self.find_one_by_id(COL, report_id).await
|
||||
}
|
||||
|
||||
async fn fetch_reports(&self) -> Result<Vec<Report>> {
|
||||
self.find(COL, doc! {}).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,14 @@ impl AbstractSnapshot for MongoDb {
|
||||
async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()> {
|
||||
self.insert_one(COL, snapshot).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn fetch_snapshot(&self, report_id: &str) -> Result<Snapshot> {
|
||||
self.find_one(
|
||||
COL,
|
||||
doc! {
|
||||
"report_id": report_id
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ pub enum UserReportReason {
|
||||
Underage,
|
||||
}
|
||||
|
||||
/// The content being reported
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ReportedContent {
|
||||
@@ -70,8 +71,25 @@ pub enum ReportedContent {
|
||||
},
|
||||
}
|
||||
|
||||
/// User-generated platform moderation report.
|
||||
/// Status of the report
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
|
||||
#[serde(tag = "status")]
|
||||
pub enum ReportStatus {
|
||||
/// Report is waiting for triage / action
|
||||
Created {},
|
||||
|
||||
/// Report was rejected
|
||||
Rejected { rejection_reason: String },
|
||||
|
||||
/// Report was actioned and resolved
|
||||
Resolved {},
|
||||
}
|
||||
|
||||
/// User-generated platform moderation report.
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug, OptionalStruct, Clone)]
|
||||
#[optional_derive(Serialize, Deserialize, JsonSchema, Debug, Default, Clone)]
|
||||
#[optional_name = "PartialReport"]
|
||||
#[opt_skip_serializing_none]
|
||||
pub struct Report {
|
||||
/// Unique Id
|
||||
#[serde(rename = "_id")]
|
||||
@@ -82,4 +100,11 @@ pub struct Report {
|
||||
pub content: ReportedContent,
|
||||
/// Additional report context
|
||||
pub additional_context: String,
|
||||
/// Status of the report
|
||||
#[opt_passthrough]
|
||||
#[serde(flatten)]
|
||||
pub status: ReportStatus,
|
||||
/// Additional notes included on the report
|
||||
#[serde(default)]
|
||||
pub notes: String,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{Message, Server, User};
|
||||
use crate::models::{Channel, Message, Server, User};
|
||||
|
||||
/// Enum to map into different models
|
||||
/// that can be saved in a snapshot
|
||||
@@ -9,11 +9,11 @@ use crate::models::{Message, Server, User};
|
||||
pub enum SnapshotContent {
|
||||
Message {
|
||||
/// Context before the message
|
||||
#[serde(rename = "_prior_context")]
|
||||
#[serde(rename = "_prior_context", default)]
|
||||
prior_context: Vec<Message>,
|
||||
|
||||
/// Context after the message
|
||||
#[serde(rename = "_leading_context")]
|
||||
#[serde(rename = "_leading_context", default)]
|
||||
leading_context: Vec<Message>,
|
||||
|
||||
/// Message
|
||||
@@ -35,3 +35,20 @@ pub struct Snapshot {
|
||||
/// Snapshot of content
|
||||
pub content: SnapshotContent,
|
||||
}
|
||||
|
||||
/// Snapshot of some content with required data to render
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct SnapshotWithContext {
|
||||
/// Snapshot itself
|
||||
#[serde(flatten)]
|
||||
pub snapshot: Snapshot,
|
||||
/// Users involved in snapshot
|
||||
#[serde(rename = "_users", skip_serializing_if = "Vec::is_empty")]
|
||||
pub users: Vec<User>,
|
||||
/// Channels involved in snapshot
|
||||
#[serde(rename = "_channels", skip_serializing_if = "Vec::is_empty")]
|
||||
pub channels: Vec<Channel>,
|
||||
/// Server involved in snapshot
|
||||
#[serde(rename = "_server", skip_serializing_if = "Option::is_none")]
|
||||
pub server: Option<Server>,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::models::report::PartialReport;
|
||||
use crate::models::Report;
|
||||
use crate::Result;
|
||||
|
||||
@@ -5,4 +6,13 @@ use crate::Result;
|
||||
pub trait AbstractReport: Sync + Send {
|
||||
/// Insert a new report into the database
|
||||
async fn insert_report(&self, report: &Report) -> Result<()>;
|
||||
|
||||
/// Update a given report with new information
|
||||
async fn update_report(&self, id: &str, message: &PartialReport) -> Result<()>;
|
||||
|
||||
/// Fetch report
|
||||
async fn fetch_report(&self, report_id: &str) -> Result<Report>;
|
||||
|
||||
/// Fetch reports
|
||||
async fn fetch_reports(&self) -> Result<Vec<Report>>;
|
||||
}
|
||||
|
||||
@@ -5,4 +5,7 @@ use crate::Result;
|
||||
pub trait AbstractSnapshot: Sync + Send {
|
||||
/// Insert a new snapshot into the database
|
||||
async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()>;
|
||||
|
||||
/// Fetch a snapshot by a report's id
|
||||
async fn fetch_snapshot(&self, report_id: &str) -> Result<Snapshot>;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ use schemars::schema::{InstanceType, Schema, SchemaObject, SingleOrVec};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{Bot, Channel, Emoji, Invite, Member, Message, Server, ServerBan, User};
|
||||
use crate::models::{
|
||||
Bot, Channel, Emoji, Invite, Member, Message, Report, Server, ServerBan, User,
|
||||
};
|
||||
use crate::presence::presence_is_online;
|
||||
use crate::{Database, Error, Result};
|
||||
|
||||
@@ -78,6 +80,11 @@ impl Ref {
|
||||
pub async fn as_emoji(&self, db: &Database) -> Result<Emoji> {
|
||||
db.fetch_emoji(&self.id).await
|
||||
}
|
||||
|
||||
/// Fetch report from Ref
|
||||
pub async fn as_report(&self, db: &Database) -> Result<Report> {
|
||||
db.fetch_report(&self.id).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> FromParam<'r> for Ref {
|
||||
|
||||
@@ -75,6 +75,7 @@ pub enum Error {
|
||||
permission: UserPermission,
|
||||
},
|
||||
NotElevated,
|
||||
NotPrivileged,
|
||||
CannotGiveMissingPermissions,
|
||||
NotOwner,
|
||||
|
||||
@@ -174,6 +175,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
||||
Error::MissingPermission { .. } => Status::Forbidden,
|
||||
Error::MissingUserPermission { .. } => Status::Forbidden,
|
||||
Error::NotElevated => Status::Forbidden,
|
||||
Error::NotPrivileged => Status::Forbidden,
|
||||
Error::CannotGiveMissingPermissions => Status::Forbidden,
|
||||
Error::NotOwner => Status::Forbidden,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user