use std::error::Error;
use bb8_postgres::bb8::Pool;
use bb8_postgres::PostgresConnectionManager;
use bb8_postgres::tokio_postgres::{GenericClient, NoTls, Row};
use chrono::{Local, NaiveDateTime, TimeDelta};
use frankenstein::{AsyncTelegramApi};
use frankenstein::client_reqwest::Bot;
use frankenstein::methods::SendMessageParams;
use paperclip::actix::Apiv2Schema;
use serde::{Deserialize, Serialize};
use crate::task::Task;
use crate::user::User;
const GET_TASK_NOTIFICATIONS_BY_TASK_ID: &str = "SELECT notify.id, notify.notify_date, notify.repeat, notify.last_notify_date, notify.text, notify.task_id FROM rec23.notify notify WHERE notify.task_id = $1";
const INSERT_NOTIFY: &str = "INSERT INTO rec23.notify (notify_date, repeat, last_notify_date, text, task_id) VALUES($1, $2, $3, $4, $5) RETURNING id";
const UPDATE_NOTIFY: &str = "UPDATE rec23.notify SET notify_date = $2, repeat = $3, last_notify_date = $4, text = $5, task_id = $6 WHERE id = $1";
const DELETE_NOTIFY_BY_ID: &str = "UPDATE rec23.notify SET repeat = false, deleted = true WHERE id = $1";
const DELETE_NOTIFY_BY_TASK_ID: &str = "UPDATE rec23.notify SET repeat = false, deleted = true WHERE task_id = $1";
const GET_NOTIFICATIONS: &str = "SELECT notify.id, notify.notify_date, notify.repeat, notify.last_notify_date, notify.text, notify.task_id FROM rec23.notify notify WHERE notify.deleted = FALSE AND EXISTS (SELECT 1 FROM rec23.task task WHERE task.id = notify.task_id AND task.task_status_id != 2)";
const DELETE_COMPLETED_NOTIFICATION: &str = "DELETE FROM rec23.task_sub_completed task_sub_completed WHERE task_sub_completed.task_id = $1";
#[derive(Serialize, Deserialize, Apiv2Schema)]
pub struct Notification {
pub id: Option<i32>,
pub notify_date: NaiveDateTime,
pub repeat: bool,
pub last_notify_date: Option<NaiveDateTime>,
pub text: String,
pub task_id: Option<i32>,
}
#[derive(Debug, Clone)]
pub struct ClientNotification {
pub notify_date: NaiveDateTime,
pub repeat: bool,
pub last_notify_date: Option<NaiveDateTime>,
pub text: String,
pub task_id: Option<i32>
}
impl Into<Notification> for ClientNotification {
fn into(self) -> Notification {
Notification {
id: None,
notify_date: self.notify_date,
repeat: self.repeat,
last_notify_date: self.last_notify_date,
text: self.text,
task_id: self.task_id,
}
}
}
impl ClientNotification {
pub fn new(notify_date: NaiveDateTime, repeat: bool, last_notify_date: Option<NaiveDateTime>, text: String, task_id: Option<i32>) -> Self {
Self {
notify_date,
repeat,
last_notify_date,
text,
task_id,
}
}
pub async fn save(self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Notification, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let row = client.query_one(INSERT_NOTIFY, &[&self.notify_date, &self.repeat, &self.last_notify_date, &self.text, &self.task_id]).await?;
let mut result: Notification = self.into();
result.id = Some(row.get(0));
Ok(result)
}
}
impl Notification {
pub async fn get_by_task_id(pool: &Pool<PostgresConnectionManager<NoTls>>, id: i32) -> Result<Vec<Self>, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let rows = client.query(GET_TASK_NOTIFICATIONS_BY_TASK_ID, &[&id]).await?;
let mut notifications = Vec::new();
for row in rows {
let notification = Self::convert_from_row(row);
notifications.push(notification);
}
Ok(notifications)
}
pub fn convert_from_row(row: Row) -> Self {
Self {
id: row.get("id"),
notify_date: row.get("notify_date"),
repeat: row.get("repeat"),
last_notify_date: row.get("last_notify_date"),
text: row.get("text"),
task_id: row.get("task_id"),
}
}
pub async fn save(&self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(UPDATE_NOTIFY, &[&self.id, &self.notify_date, &self.repeat, &self.last_notify_date, &self.text, &self.task_id]).await?;
Ok(())
}
pub fn is_employee_notification(&self) -> bool {
self.text.contains("[EmployeeNotification]")
}
pub fn is_assignee_notification(&self) -> bool {
self.text.contains("[AssigneeNotification]")
}
pub async fn push_notify(&self, chat_id: i64, api: &Bot, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<i32, Box<dyn Error + Sync + Send>> {
let task = Task::get_by_id(self.task_id.unwrap(), pool).await?;
let mut text = self.text.clone();
if task.task_type != 3 {
if let Some(task_header) = task.header {
text = format!("{}\n{}", task_header, text);
}
if let Some(employee_id) = task.employee_id {
if let Some(employee) = User::get_user_by_id(employee_id, pool).await? {
if let Some(telegram_name) = employee.telegram_name {
text.push_str(&format!("\n{}", telegram_name));
}
if task.task_type == 2 && (employee.dept_id.unwrap() == 3 || employee.dept_id.unwrap() == 5) {
if let Some(assignee) = User::get_user_by_id(task.assignee_id, pool).await? {
if let Some(telegram_name) = assignee.telegram_name {
text.push_str(&format!("\n{}", telegram_name));
}
}
}
}
}
} else {
if self.is_assignee_notification() {
{
if let Some(assignee) = User::get_user_by_id(task.assignee_id, pool).await? {
if let Some(telegram_name) = assignee.telegram_name {
text.push_str(&format!("\n{}", telegram_name));
}
}
}
}
if self.is_employee_notification() {
if let Some(employee) = User::get_user_by_id(task.employee_id.unwrap(), pool).await? {
if let Some(telegram_name) = employee.telegram_name {
text.push_str(&format!("\n{}", telegram_name));
}
}
}
text = text.replace("[EmployeeNotification]", "");
text = text.replace("[AssigneeNotification]", "");
}
if text.len() == 0 {
text = "-".to_string();
}
let send_message_params = SendMessageParams::builder().chat_id(chat_id).text(text).build();
let result = api.send_message(&send_message_params).await?;
Ok(result.result.message_id)
}
pub async fn push_notify_short(&self, chat_id: i64, api: &Bot, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<i32, Box<dyn Error + Sync + Send>> {
let task = Task::get_by_id(self.task_id.unwrap(), pool).await?;
let mut text = self.text.clone();
if let Some(task_header) = task.header {
text = format!("{}\n{}", task_header, text);
}
if let Some(employee_id) = task.employee_id {
if let Some(employee) = User::get_user_by_id(employee_id, pool).await? {
if let Some(telegram_name) = employee.telegram_name {
text.push_str(&format!("\n{}", telegram_name));
}
}
}
if text.len() == 0 {
text = "-".to_string();
}
let send_message_params = SendMessageParams::builder().chat_id(chat_id).text(text).build();
let result = api.send_message(&send_message_params).await?;
Ok(result.result.message_id)
}
pub async fn push_notify_header(&self, chat_id: i64, api: &Bot, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<i32, Box<dyn Error + Sync + Send>> {
let task = Task::get_by_id(self.task_id.unwrap(), pool).await?;
let mut text = self.text.clone();
if let Some(task_header) = task.header {
text = format!("{}\n{}", task_header, text);
}
if text.len() == 0 {
text = "-".to_string();
}
let send_message_params = SendMessageParams::builder().chat_id(chat_id).text(text).build();
let result = api.send_message(&send_message_params).await?;
Ok(result.result.message_id)
}
pub async fn delete(self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(DELETE_NOTIFY_BY_ID, &[&self.id]).await?;
Ok(())
}
pub async fn delete_completed_notification(id: i32, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(DELETE_COMPLETED_NOTIFICATION, &[&id]).await?;
Ok(())
}
pub async fn delete_by_task_id(task_id: &i32, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(DELETE_NOTIFY_BY_TASK_ID, &[task_id]).await?;
Ok(())
}
pub async fn get(pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Vec<Notification>, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let rows = client.query(GET_NOTIFICATIONS, &[]).await?;
let result = rows.into_iter().map(|row| Notification::convert_from_row(row)).collect();
Ok(result)
}
pub fn last_notify_date_checked_add_signed(&mut self, rhs: TimeDelta) {
self.last_notify_date = Some(self.last_notify_date.unwrap_or(Local::now().naive_local()).checked_add_signed(rhs).unwrap());
}
pub fn signed_duration(&self) -> TimeDelta {
let difference = Local::now().naive_local().signed_duration_since(self.last_notify_date.unwrap_or(Local::now().naive_local()));
TimeDelta::new(difference.num_seconds(), 0).unwrap()
}
}