Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32899187
D8937.1768185283.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D8937.1768185283.diff
View Options
diff --git a/services/reports/Cargo.lock b/services/reports/Cargo.lock
--- a/services/reports/Cargo.lock
+++ b/services/reports/Cargo.lock
@@ -518,6 +518,7 @@
"iana-time-zone",
"js-sys",
"num-traits",
+ "serde",
"time 0.1.45",
"wasm-bindgen",
"winapi",
@@ -813,6 +814,17 @@
"version_check",
]
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
[[package]]
name = "gimli"
version = "0.28.0"
@@ -1133,6 +1145,17 @@
"winapi",
]
+[[package]]
+name = "num-derive"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.29",
+]
+
[[package]]
name = "num-integer"
version = "0.1.45"
@@ -1354,13 +1377,21 @@
dependencies = [
"anyhow",
"aws-config",
+ "chrono",
"clap",
"comm-services-lib",
+ "derive_more",
+ "num-derive",
+ "num-traits",
"once_cell",
+ "serde",
+ "serde_json",
+ "serde_repr",
"tokio",
"tokio-stream",
"tracing",
"tracing-subscriber",
+ "uuid",
]
[[package]]
@@ -1564,6 +1595,17 @@
"serde",
]
+[[package]]
+name = "serde_repr"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.29",
+]
+
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -1983,6 +2025,15 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+[[package]]
+name = "uuid"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
+dependencies = [
+ "getrandom",
+]
+
[[package]]
name = "valuable"
version = "0.1.0"
diff --git a/services/reports/Cargo.toml b/services/reports/Cargo.toml
--- a/services/reports/Cargo.toml
+++ b/services/reports/Cargo.toml
@@ -9,12 +9,20 @@
[dependencies]
anyhow = "1.0"
aws-config = "0.55"
+chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.0", features = ["derive", "env"] }
comm-services-lib = { path = "../comm-services-lib", features = [
"blob-client",
] }
+derive_more = "0.99"
+num-traits = "0.2"
+num-derive = "0.4"
once_cell = "1.17"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+serde_repr = "0.1"
tokio = { version = "1.32", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+uuid = { version = "1.2", features = ["v4"] }
diff --git a/services/reports/src/main.rs b/services/reports/src/main.rs
--- a/services/reports/src/main.rs
+++ b/services/reports/src/main.rs
@@ -1,4 +1,5 @@
pub mod config;
+pub mod report_types;
use anyhow::Result;
use tracing_subscriber::filter::{EnvFilter, LevelFilter};
diff --git a/services/reports/src/report_types.rs b/services/reports/src/report_types.rs
new file mode 100644
--- /dev/null
+++ b/services/reports/src/report_types.rs
@@ -0,0 +1,114 @@
+// Report ID
+
+use std::collections::HashMap;
+
+use chrono::{serde::ts_milliseconds_option, DateTime, Utc};
+use derive_more::{Deref, Display, Into};
+use num_derive::FromPrimitive;
+use serde::{de::Error, Deserialize, Serialize};
+use serde_repr::Deserialize_repr;
+
+#[derive(Clone, Debug, Deref, Serialize, Into)]
+#[repr(transparent)]
+pub struct ReportID(String);
+impl Default for ReportID {
+ fn default() -> Self {
+ let uuid = uuid::Uuid::new_v4();
+ ReportID(uuid.to_string())
+ }
+}
+impl From<String> for ReportID {
+ fn from(value: String) -> Self {
+ ReportID(value)
+ }
+}
+
+/// Serialized / deserialized report type.
+/// We receive report type from clients as a number,
+/// but want to display it as a string.
+#[derive(
+ Copy, Clone, Debug, Default, FromPrimitive, Serialize, Deserialize_repr,
+)]
+#[repr(u8)]
+#[serde(rename_all(serialize = "snake_case"))]
+pub enum ReportType {
+ // NOTE: Keep these in sync with `reportTypes` in lib/types/report-types.js
+ #[default]
+ ErrorReport = 0,
+ ThreadInconsistency = 1,
+ EntryInconsistency = 2,
+ MediaMission = 3,
+ UserInconsistency = 4,
+}
+
+/// Report platform
+#[derive(Clone, Debug, Serialize, Deserialize, Display)]
+#[serde(rename_all = "lowercase")]
+pub enum ReportPlatform {
+ Android,
+ IOS,
+ Web,
+ Windows,
+ MacOS,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PlatformDetails {
+ pub platform: ReportPlatform,
+ code_version: Option<u16>,
+ state_version: Option<u16>,
+}
+
+/// Input report payload - this is the JSON we receive from clients
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[serde(remote = "Self")] // we delegate to our custom validation trait
+pub struct ReportInput {
+ pub platform_details: PlatformDetails,
+
+ #[serde(rename = "type")]
+ #[serde(default)]
+ pub report_type: ReportType,
+
+ #[serde(default)]
+ #[serde(with = "ts_milliseconds_option")]
+ pub time: Option<DateTime<Utc>>,
+
+ // we usually don't care about the rest of the fields
+ // so we just keep them as a JSON object
+ #[serde(flatten)]
+ pub report_content: HashMap<String, serde_json::Value>,
+}
+
+// We can do additional validation here
+impl<'de> serde::de::Deserialize<'de> for ReportInput {
+ fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let mut this = Self::deserialize(deserializer)?;
+ if this.time.is_none() {
+ if !matches!(this.report_type, ReportType::ThreadInconsistency) {
+ return Err(Error::custom(
+ "The 'time' field is optional only for thread inconsistency reports",
+ ));
+ }
+ this.time = Some(Utc::now());
+ }
+ Ok(this)
+ }
+}
+
+/// Report output payload - this is used to view the report
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ReportOutput {
+ pub id: ReportID,
+ #[serde(rename = "userID")]
+ pub user_id: String,
+ pub platform: ReportPlatform,
+ pub report_type: ReportType,
+ pub creation_time: DateTime<Utc>,
+ pub content: HashMap<String, serde_json::Value>,
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 12, 2:34 AM (9 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5921318
Default Alt Text
D8937.1768185283.diff (6 KB)
Attached To
Mode
D8937: [report-service] Add report types structs
Attached
Detach File
Event Timeline
Log In to Comment