//! Email snooze and waiting-for-response state. //! //! The email analogue of `task_repo_state`'s six functions over `tasks`; the //! shared shape is deliberate and left visible rather than consolidated. use chrono::{DateTime, Utc}; use goingson_core::{Email, EmailId, Result, UserId}; use rusqlite::{Connection, params}; use crate::utils::{execute, format_datetime, format_datetime_now, format_datetime_opt, query_all}; use super::query; use super::row::{EMAIL_SELECT_COLUMNS, EmailRow}; /// Snooze one email until the given time. pub(super) fn snooze( conn: &Connection, id: EmailId, user_id: UserId, until: DateTime, ) -> Result> { let until_str = format_datetime(&until); let result = execute( conn, "UPDATE emails SET snoozed_until = ? WHERE id = ? AND user_id = ?", params![&until_str, id.to_string(), user_id.to_string()], )?; if result > 0 { query::get_by_id(conn, id, user_id) } else { Ok(None) } } /// Remove the snooze from one email. pub(super) fn unsnooze(conn: &Connection, id: EmailId, user_id: UserId) -> Result> { let result = execute( conn, "UPDATE emails SET snoozed_until = NULL WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; if result > 0 { query::get_by_id(conn, id, user_id) } else { Ok(None) } } /// Emails still snoozed into the future, soonest first. pub(super) fn list_snoozed(conn: &Connection, user_id: UserId) -> Result> { let query = format!( "SELECT {EMAIL_SELECT_COLUMNS} FROM emails e LEFT JOIN projects p ON e.project_id = p.id AND p.user_id = ? WHERE e.user_id = ? AND e.snoozed_until IS NOT NULL AND datetime(e.snoozed_until) > datetime('now') ORDER BY e.snoozed_until ASC" ); let rows = query_all( conn, &query, params![user_id.to_string(), user_id.to_string()], EmailRow::from_row, )?; rows.into_iter().map(Email::try_from).collect() } /// Flag one email as awaiting a reply, optionally by a date. pub(super) fn mark_waiting( conn: &Connection, id: EmailId, user_id: UserId, expected_response: Option>, ) -> Result> { let now = format_datetime_now(); let expected = format_datetime_opt(expected_response); let result = execute( conn, "UPDATE emails SET waiting_for_response = 1, waiting_since = ?, expected_response_date = ? WHERE id = ? AND user_id = ?", params![&now, &expected, id.to_string(), user_id.to_string()], )?; if result > 0 { query::get_by_id(conn, id, user_id) } else { Ok(None) } } /// Clear the waiting-for-response flag on one email. pub(super) fn clear_waiting( conn: &Connection, id: EmailId, user_id: UserId, ) -> Result> { let result = execute( conn, "UPDATE emails SET waiting_for_response = 0, waiting_since = NULL, expected_response_date = NULL WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; if result > 0 { query::get_by_id(conn, id, user_id) } else { Ok(None) } } /// Emails awaiting a reply, soonest expected response first. pub(super) fn list_waiting(conn: &Connection, user_id: UserId) -> Result> { let query = format!( "SELECT {EMAIL_SELECT_COLUMNS} FROM emails e LEFT JOIN projects p ON e.project_id = p.id AND p.user_id = ? WHERE e.user_id = ? AND e.waiting_for_response = 1 ORDER BY e.expected_response_date ASC" ); let rows = query_all( conn, &query, params![user_id.to_string(), user_id.to_string()], EmailRow::from_row, )?; rows.into_iter().map(Email::try_from).collect() }