use super::*;
const NO_SUBJECT: &str = "No Subject";
const NO_TOPICAL_ERR: &str = "No \"topical asset\" found in your message. Message must be about some Production Asset. Please choose one and try again.";
const NO_TOPICAL_RECEIPT_ERR: &str =
"Expected at least one \"topical asset\" for system message. Found none";
#[derive(Debug)]
pub struct MsgReadBuilder(QueryMsg);
impl MsgReadBuilder {
pub fn new(msg: QueryMsg) -> Self {
Self(msg)
}
fn created_at_local(mut self) -> Self {
let local: DateTime<Local> = DateTime::from(self.0.created_at);
self.0.ext.created_at_local = format!("{}", local.format(YEAR_MONTH_DAY_FORMAT));
self
}
fn optimize_hyperlinks(mut self) -> Self {
if let Some(links) = &self.0.hyperlinks {
if links.is_empty() {
self.0.hyperlinks.take();
};
};
self
}
fn subject(mut self) -> Self {
if !self.0.is_handwritten() && self.0.subject.is_empty() {
self.0.subject = NO_SUBJECT.to_owned();
};
self
}
fn seen_by_str(mut self) -> Self {
self.0.ext.seen_by_str = match self.0.seen_by_names.is_empty() {
true => "Seen by no one".to_string(),
false => format!("👁 Seen by: {}", self.0.seen_by_names.join(", ")),
};
self
}
fn content_with_sender(mut self) -> Self {
if !self.0.is_handwritten() {
if self.0.content.is_empty() {
self.0.content = format!("sent by {}", self.0.sender_name);
} else {
self.0.content = format!("{}; sent by {}", self.0.content, self.0.sender_name);
};
};
self
}
fn build(self) -> Self {
self
.created_at_local()
.seen_by_str()
.optimize_hyperlinks()
.subject()
}
pub fn finish(self) -> QueryMsg {
self.build()
.content_with_sender()
.0
}
pub fn finish_as_sent(self) -> QueryMsg {
self.build().0
}
}
pub struct MsgEditBuilder(QueryMsg);
impl MsgEditBuilder {
pub fn new(msg: QueryMsg) -> Self {
Self(msg)
}
pub fn finish(self) -> QueryMsg {
self.0
}
}
pub struct SystemMsgWriteBuilder {
msg: QueryMsg,
working_step: Option<AssetStatus>,
phase: Option<VcsLiteSession>,
}
impl SystemMsgWriteBuilder {
pub fn new(user: Staff, topic: MsgTopic, asset: ProductionAsset) -> AnyResult<Self> {
let topical: Option<AssetExcerpt> = asset.into();
let msg = QueryMsg::sent_by_current_user(user)
.with_topic(topic)
.with_topical_asset_id(topical.as_ref())?
.with_topical_asset(topical);
Ok(Self {
msg,
working_step: None,
phase: None,
})
}
pub fn working_step(mut self, working_step: Option<AssetStatus>) -> Self {
self.working_step = working_step;
self
}
pub fn phase(mut self, phase: Option<VcsLiteSession>) -> Self {
self.phase = phase;
self
}
fn receipt_subject_from_topic(mut self) -> AnyResult<Self> {
let asset = self
.msg
.ext
.topical_asset()
.context(NO_TOPICAL_RECEIPT_ERR)?;
self.msg.subject = self.msg.topic.subject(asset);
Ok(self)
}
fn receipt_content(
mut self,
assignees: &[Staff],
ticket_tally: Option<&TicketTally>,
) -> AnyResult<Self> {
let content = self.msg.topic.receipt_content(
assignees,
self.working_step.as_ref(),
self.phase.as_ref(),
ticket_tally,
)?;
self.msg.content = content;
Ok(self)
}
fn receipt_recipients(mut self, assignees: &[Staff], layout: &RoleMap) -> AnyResult<Self> {
let recipients = self.msg.topic.receipt_recipients(assignees, layout)?;
self.msg.ext.recipients_mut(recipients);
Ok(self)
}
pub fn finish(
mut self,
project: &Project,
assignees: &[Staff],
layout: &RoleMap,
ticket_tally: Option<&TicketTally>,
) -> AnyResult<QueryMsg> {
self = self
.receipt_content(assignees, ticket_tally)?
.receipt_subject_from_topic()?
.receipt_recipients(assignees, layout)?;
self.msg = MsgWriteBuilder::new(self.msg)
.created_now()
.finish(project)?;
Ok(self.msg)
}
}
pub struct MsgWriteBuilder {
msg: QueryMsg,
}
impl MsgWriteBuilder {
pub fn new(msg: QueryMsg) -> Self {
Self { msg }
}
fn sender_name(mut self) -> Self {
self.msg.sender_name = self.msg.ext.sender.name_unwrap().to_owned();
self
}
pub fn topical_asset_bson_ids(
mut self,
mut topical_alternative: Option<AssetExcerpt>,
favor_alternative: bool,
) -> AnyResult<Self> {
let asset = match favor_alternative {
false => {
self.msg.ext.topical_asset_clone()
}
true => {
topical_alternative.take()
}
};
if let Some(asset) = asset {
let id = asset.id.context("Bad AssetExcerpt with no ObjectId")?;
self.msg.topical_asset_bson_ids = vec![id];
};
Ok(self)
}
fn as_reply_to_bson_ids(mut self) -> AnyResult<Self> {
if let Some(reply) = self.msg.ext.as_reply_to.take() {
let id = reply.id.context("Bad reply excerpt with no ObjectId")?;
self.msg.as_reply_to_bson_ids = Some(vec![id]);
} else {
self.msg.as_reply_to_bson_ids = Some(vec![]);
};
Ok(self)
}
fn project(mut self, project: &Project) -> Self {
self.msg.project = Some(format!("{}", project));
self
}
pub fn created_now(mut self) -> Self {
self.msg.created_at = Utc::now();
self
}
fn recipient_names(mut self) -> Self {
self.msg.recipient_names = self
.msg
.ext
.recipients()
.iter()
.map(|s| s.name_unwrap().to_owned())
.collect();
self
}
fn instantiated_for(mut self) -> Self {
self.msg
.instantiated_for
.push(self.msg.sender_name.to_owned());
self
}
fn hyperlinks(mut self) -> Self {
if self.msg.hyperlinks.is_none() {
self.msg.hyperlinks = Some(vec![]);
}
self
}
pub fn finish(self, project: &Project) -> AnyResult<QueryMsg> {
Ok(self
.sender_name()
.as_reply_to_bson_ids()?
.project(project)
.recipient_names()
.instantiated_for()
.hyperlinks()
.msg)
}
}
pub struct MsgWriteScanBuilder<'a>(&'a QueryMsg);
impl<'a> MsgWriteScanBuilder<'a> {
pub fn new(msg: &'a QueryMsg) -> Self {
Self(msg)
}
fn has_topical_asset(self) -> AnyResult<Self> {
if self.0.topical_asset_bson_ids.is_empty() {
Err(anyhow!(NO_TOPICAL_ERR))
} else {
Ok(self)
}
}
fn has_recipient(self) -> AnyResult<Self> {
if !self.0.is_handwritten() {
return Ok(self);
};
if self.0.ext.is_recipient_empty() {
Err(anyhow!(
"Your message has no recipient. Message must have at least one recipient. Please select some and try again."
))
} else {
Ok(self)
}
}
fn has_content(self) -> AnyResult<Self> {
match self.0.content.is_empty() {
true => Err(anyhow!(
"Your message has no content. Please type your message and try again."
)),
false => Ok(self),
}
}
pub fn scanned(self) -> AnyResult<bool> {
self.has_topical_asset()?.has_recipient()?.has_content()?;
Ok(true)
}
}