Page MenuHomePhabricator

D8988.id30725.diff
No OneTemporary

D8988.id30725.diff

diff --git a/services/reports/src/database/item.rs b/services/reports/src/database/item.rs
--- a/services/reports/src/database/item.rs
+++ b/services/reports/src/database/item.rs
@@ -115,44 +115,6 @@
}
size
}
-
- /// Creates a report item from a report input payload
- ///
- /// WARN: Note that this method stores content as [`ReportStorage::Database`]
- /// regardless of its size. Use [`ensure_size_constraints`] to move content to
- /// blob storage if necessary.
- pub fn from_input(
- payload: ReportInput,
- user_id: Option<String>,
- ) -> Result<Self, serde_json::Error> {
- let ReportInput {
- platform_details,
- report_type,
- time,
- mut report_content,
- } = payload;
-
- let platform = platform_details.platform.clone();
-
- // Add "platformDetails" back to report content
- let platform_details_value = serde_json::to_value(platform_details)?;
- report_content
- .insert("platformDetails".to_string(), platform_details_value);
-
- // serialize report JSON to bytes
- let content_bytes = serde_json::to_vec(&report_content)?;
- let content = ReportContent::Database(content_bytes);
-
- Ok(ReportItem {
- id: ReportID::default(),
- user_id: user_id.unwrap_or("[null]".to_string()),
- platform,
- report_type,
- creation_time: time.unwrap_or_else(Utc::now),
- encryption_key: None,
- content,
- })
- }
}
impl TryFrom<AttributeMap> for ReportItem {
diff --git a/services/reports/src/service.rs b/services/reports/src/service.rs
--- a/services/reports/src/service.rs
+++ b/services/reports/src/service.rs
@@ -1,4 +1,5 @@
use actix_web::FromRequest;
+use chrono::Utc;
use comm_services_lib::{
auth::UserIdentity,
blob::client::{BlobServiceClient, BlobServiceError},
@@ -15,9 +16,9 @@
use crate::{
database::{
client::{DatabaseClient, ReportsPage},
- item::ReportItem,
+ item::{ReportContent, ReportItem},
},
- email::config::EmailConfig,
+ email::{config::EmailConfig, ReportEmail},
report_types::{ReportID, ReportInput, ReportOutput, ReportType},
};
@@ -77,20 +78,20 @@
pub async fn save_reports(
&self,
- reports: Vec<ReportInput>,
+ inputs: Vec<ReportInput>,
) -> ServiceResult<Vec<ReportID>> {
- let mut items = Vec::with_capacity(reports.len());
+ let mut reports = Vec::with_capacity(inputs.len());
let mut tasks = tokio::task::JoinSet::new();
- // 1. Concurrently upload reports to blob service if needed
- for input in reports {
+ // 1. Concurrently prepare reports. Upload them to blob service if needed
+ for input in inputs {
let blob_client = self.blob_client.clone();
let user_id = self.requesting_user_id.clone();
tasks.spawn(async move {
- let mut item = ReportItem::from_input(input, user_id)
+ let mut report = process_report(input, user_id)
.map_err(ReportsServiceError::SerdeError)?;
- item.ensure_size_constraints(&blob_client).await?;
- Ok(item)
+ report.db_item.ensure_size_constraints(&blob_client).await?;
+ Ok(report)
});
}
@@ -101,12 +102,23 @@
error!("Task failed to join: {err}");
ReportsServiceError::Unexpected
})?;
- items.push(result?);
+ reports.push(result?);
}
- // 3. Store reports in database
- let ids = items.iter().map(|item| item.id.clone()).collect();
- self.db.save_reports(items).await?;
+ let (ids, (db_items, emails)): (Vec<_>, (Vec<_>, Vec<_>)) = reports
+ .into_iter()
+ .map(|ProcessedReport { id, db_item, email }| (id, (db_item, email)))
+ .unzip();
+
+ // 3. Store the reports in database
+ self.db.save_reports(db_items).await?;
+
+ // 4. Send e-mails asynchronously
+ tokio::spawn(async move {
+ if let Err(err) = crate::email::send_emails(emails).await {
+ error!("Failed to send e-mails: {err}");
+ }
+ });
Ok(ids)
}
@@ -201,6 +213,47 @@
}
}
+struct ProcessedReport {
+ id: ReportID,
+ db_item: ReportItem,
+ email: ReportEmail,
+}
+
+fn process_report(
+ input: ReportInput,
+ user_id: Option<String>,
+) -> Result<ProcessedReport, serde_json::Error> {
+ let id = ReportID::default();
+ let email = crate::email::prepare_email(&input, &id, user_id.as_deref());
+
+ let ReportInput {
+ platform_details,
+ report_type,
+ time,
+ mut report_content,
+ } = input;
+
+ // Add "platformDetails" back to report content.
+ // It was deserialized into a separate field.
+ let platform_details_value = serde_json::to_value(&platform_details)?;
+ report_content.insert("platformDetails".to_string(), platform_details_value);
+
+ // serialize report JSON to bytes
+ let content_bytes = serde_json::to_vec(&report_content)?;
+
+ let db_item = ReportItem {
+ id: id.clone(),
+ user_id: user_id.unwrap_or("[null]".to_string()),
+ platform: platform_details.platform.clone(),
+ report_type,
+ creation_time: time.unwrap_or_else(Utc::now),
+ encryption_key: None,
+ content: ReportContent::Database(content_bytes),
+ };
+
+ Ok(ProcessedReport { id, db_item, email })
+}
+
/// Transforms report content JSON into format that can be
/// imported into Redux DevTools.
fn prepare_redux_devtools_import(

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 4:19 AM (21 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2581770
Default Alt Text
D8988.id30725.diff (5 KB)

Event Timeline