Page MenuHomePhabricator

D8938.diff
No OneTemporary

D8938.diff

diff --git a/services/reports/Cargo.lock b/services/reports/Cargo.lock
--- a/services/reports/Cargo.lock
+++ b/services/reports/Cargo.lock
@@ -1377,6 +1377,7 @@
dependencies = [
"anyhow",
"aws-config",
+ "aws-sdk-dynamodb",
"chrono",
"clap",
"comm-services-lib",
diff --git a/services/reports/Cargo.toml b/services/reports/Cargo.toml
--- a/services/reports/Cargo.toml
+++ b/services/reports/Cargo.toml
@@ -9,6 +9,7 @@
[dependencies]
anyhow = "1.0"
aws-config = "0.55"
+aws-sdk-dynamodb = "0.27"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.0", features = ["derive", "env"] }
comm-services-lib = { path = "../comm-services-lib", features = [
diff --git a/services/reports/src/database/item.rs b/services/reports/src/database/item.rs
new file mode 100644
--- /dev/null
+++ b/services/reports/src/database/item.rs
@@ -0,0 +1,116 @@
+use aws_sdk_dynamodb::types::AttributeValue;
+use comm_services_lib::database::{self, DBItemError, TryFromAttribute};
+use num_traits::FromPrimitive;
+use tracing::debug;
+
+use super::constants::*;
+
+use crate::report_types::*;
+
+// DB conversions for report types
+
+// ReportID
+impl From<ReportID> for AttributeValue {
+ fn from(value: ReportID) -> Self {
+ AttributeValue::S(value.into())
+ }
+}
+impl From<&ReportID> for AttributeValue {
+ fn from(value: &ReportID) -> Self {
+ AttributeValue::S(value.clone().into())
+ }
+}
+impl TryFrom<Option<AttributeValue>> for ReportID {
+ type Error = database::DBItemError;
+
+ fn try_from(value: Option<AttributeValue>) -> Result<Self, Self::Error> {
+ let raw = String::try_from_attr(ATTR_REPORT_ID, value)?;
+ Ok(ReportID::from(raw))
+ }
+}
+
+// ReportType
+impl From<ReportType> for AttributeValue {
+ fn from(value: ReportType) -> Self {
+ let num = value as u8;
+ AttributeValue::N(num.to_string())
+ }
+}
+impl TryFromAttribute for ReportType {
+ fn try_from_attr(
+ attribute_name: impl Into<String>,
+ attribute: Option<AttributeValue>,
+ ) -> Result<Self, database::DBItemError> {
+ let attr_name = attribute_name.into();
+ let num: u8 = database::parse_int_attribute(&attr_name, attribute)?;
+ <ReportType as FromPrimitive>::from_u8(num).ok_or_else(|| {
+ database::DBItemError::new(
+ attr_name,
+ database::Value::String(num.to_string()),
+ database::DBItemAttributeError::IncorrectType,
+ )
+ })
+ }
+}
+
+// ReportPlatform
+impl From<ReportPlatform> for AttributeValue {
+ fn from(value: ReportPlatform) -> Self {
+ let raw = value.to_string().to_lowercase();
+ AttributeValue::S(raw)
+ }
+}
+impl TryFromAttribute for ReportPlatform {
+ fn try_from_attr(
+ attribute_name: impl Into<String>,
+ attribute: Option<AttributeValue>,
+ ) -> Result<Self, DBItemError> {
+ let attr_name = attribute_name.into();
+ let raw = String::try_from_attr(&attr_name, attribute)?;
+ // serde_json understands only quoted strings
+ let quoted = format!("\"{raw}\"");
+ serde_json::from_str(&quoted).map_err(|err| {
+ debug!("Failed to deserialize ReportPlatform: {}", err);
+ DBItemError::new(
+ attr_name,
+ database::Value::String(raw),
+ database::DBItemAttributeError::IncorrectType,
+ )
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use comm_services_lib::database::AttributeTryInto;
+
+ use super::*;
+
+ #[test]
+ fn test_platform_conversions() -> anyhow::Result<()> {
+ let platform = ReportPlatform::MacOS;
+
+ let attribute: AttributeValue = platform.into();
+
+ assert_eq!(attribute, AttributeValue::S("macos".to_string()));
+
+ let converted_back: ReportPlatform =
+ Some(attribute).attr_try_into("foo")?;
+
+ assert!(matches!(converted_back, ReportPlatform::MacOS));
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_type_conversions() -> anyhow::Result<()> {
+ let report_type = ReportType::MediaMission;
+ let numeric_type = (report_type as u8).to_string();
+ let attr: AttributeValue = report_type.into();
+ assert_eq!(attr, AttributeValue::N(numeric_type.to_string()));
+
+ let converted_back: ReportType = Some(attr).attr_try_into("foo")?;
+ assert!(matches!(converted_back, ReportType::MediaMission));
+ Ok(())
+ }
+}
diff --git a/services/reports/src/database/mod.rs b/services/reports/src/database/mod.rs
new file mode 100644
--- /dev/null
+++ b/services/reports/src/database/mod.rs
@@ -0,0 +1,14 @@
+pub mod item;
+
+mod constants {
+ pub const TABLE_NAME: &str = "reports-service-reports";
+
+ pub const ATTR_REPORT_ID: &str = "reportID";
+ pub const ATTR_USER_ID: &str = "userID";
+ pub const ATTR_REPORT_TYPE: &str = "type";
+ pub const ATTR_PLATFORM: &str = "platform";
+ pub const ATTR_BLOB_INFO: &str = "blobInfo";
+ pub const ATTR_REPORT_CONTENT: &str = "content";
+ pub const ATTR_ENCRYPTION_KEY: &str = "encryptionKey";
+ pub const ATTR_CREATION_TIME: &str = "creationTime";
+}
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 database;
pub mod report_types;
use anyhow::Result;
diff --git a/services/terraform/modules/shared/dynamodb.tf b/services/terraform/modules/shared/dynamodb.tf
--- a/services/terraform/modules/shared/dynamodb.tf
+++ b/services/terraform/modules/shared/dynamodb.tf
@@ -289,3 +289,14 @@
type = "S"
}
}
+
+resource "aws_dynamodb_table" "reports-service-reports" {
+ name = "reports-service-reports"
+ hash_key = "reportID"
+ billing_mode = "PAY_PER_REQUEST"
+
+ attribute {
+ name = "reportID"
+ type = "S"
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 22, 11:01 PM (17 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2566341
Default Alt Text
D8938.diff (5 KB)

Event Timeline