use std::error::Error;
use bb8_postgres::bb8::Pool;
use bb8_postgres::PostgresConnectionManager;
use bb8_postgres::tokio_postgres::{GenericClient, NoTls, Row};
use chrono::NaiveDateTime;
use paperclip::actix::Apiv2Schema;
use serde::{Deserialize, Serialize};
use crate::user::User;
const INSERT_TASK: &str = "INSERT INTO rec23.task (header, dt_cre, dt_beg, mark_color_id, main_color_id, content, note, task_status_id, assignee_id, employee_id, dept_id, task_type) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING id";
const UPDATE_TASK: &str = "UPDATE rec23.task SET header = $2, dt_cre = $3, dt_beg = $4, mark_color_id = $5, main_color_id = $6, content = $7, note = $8, task_status_id = $9, assignee_id = $10, employee_id = $11, dept_id = $12, task_type = $13 WHERE id = $1";
const COMPLETE_TASK_BY_ID: &str = "UPDATE rec23.task SET main_color_id = 6, task_status_id = 2 WHERE id = $1";
const COMPLETE_TASK_BY_ID_SUB: &str = "INSERT INTO rec23.task_sub_completed (task_id) VALUES ($1)";
const GET_TASK_BY_ID: &str = "SELECT task.id, task.header, task.dt_cre, task.dt_beg, task.mark_color_id, task.main_color_id, task.content, task.note, task.task_status_id, task.assignee_id, task.employee_id, task.dept_id, task.task_type FROM rec23.task task where task.id = $1 AND dt_cre IS NOT NULL";
const SET_TASK_EMPLOYEE: &str = "UPDATE rec23.task SET employee_id = $2, dept_id = $3 WHERE id = $1";
const GET_TASK_SUBSCRIBERS: &str = "SELECT employee.id, employee.name, employee.dept_id, employee.post_id, employee.telegram_name FROM rec23.notify_subscription notify_subscription JOIN rec23.employee employee ON employee.id = notify_subscription.user_id WHERE notify_subscription.task_id = $1";
const GET: &str = "SELECT id, header, dt_cre, dt_beg, mark_color_id, main_color_id, content, note, task_status_id, assignee_id, employee_id, dept_id, task_type FROM rec23.task WHERE dt_cre IS NOT NULL";
#[derive(Serialize, Deserialize, Apiv2Schema)]
pub struct Task {
pub id: Option<i32>,
pub header: Option<String>,
pub dt_cre: NaiveDateTime,
pub dt_beg: Option<NaiveDateTime>,
pub mark_color_id: i32,
pub main_color_id: i32,
pub content: Option<String>,
pub note: Option<String>,
pub task_status_id: i32,
pub assignee_id: i32,
pub employee_id: Option<i32>,
pub dept_id: i32,
pub task_type: i32,
}
#[derive(Debug, Clone)]
pub struct ClientTask {
pub header: Option<String>,
pub dt_cre: NaiveDateTime,
pub dt_beg: Option<NaiveDateTime>,
pub mark_color_id: i32,
pub main_color_id: i32,
pub content: Option<String>,
pub note: Option<String>,
pub task_status_id: i32,
pub assignee_id: i32,
pub employee_id: Option<i32>,
pub dept_id: i32,
pub task_type: i32,
}
impl Into<Task> for ClientTask {
fn into(self) -> Task {
Task {
id: None,
header: self.header,
dt_cre: self.dt_cre,
dt_beg: self.dt_beg,
mark_color_id: self.mark_color_id,
main_color_id: self.main_color_id,
content: self.content,
note: self.note,
task_status_id: self.task_status_id,
assignee_id: self.assignee_id,
employee_id: self.employee_id,
dept_id: self.dept_id,
task_type: self.task_type,
}
}
}
impl ClientTask {
pub fn new(header: Option<String>, dt_cre: NaiveDateTime, dt_beg: Option<NaiveDateTime>, mark_color_id: i32, main_color_id: i32, content: Option<String>, note: Option<String>, task_status_id: i32, assignee_id: i32, employee_id: Option<i32>, dept_id: i32, task_type: i32) -> Self {
Self {
header,
dt_cre,
dt_beg,
mark_color_id,
main_color_id,
content,
note,
task_status_id,
assignee_id,
employee_id,
dept_id,
task_type,
}
}
pub async fn save(self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Task, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let row = client.query_one(INSERT_TASK, &[&self.header, &self.dt_cre, &self.dt_beg, &self.mark_color_id, &self.main_color_id, &self.content, &self.note, &self.task_status_id, &self.assignee_id, &self.employee_id, &self.dept_id, &self.task_type]).await?;
let mut result: Task = self.into();
result.id = Some(row.get(0));
Ok(result)
}
}
impl Task {
pub async fn get(pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Vec<Self>, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let rows = connection.query(GET, &[]).await?;
Ok(rows.iter().map(|row|Self::convert_from_row(row)).collect())
}
pub fn convert_from_row(row: &Row) -> Self {
Self {
id: row.get("id"),
header: row.get("header"),
dt_cre: row.get("dt_cre"),
dt_beg: row.get("dt_beg"),
mark_color_id: row.get("mark_color_id"),
main_color_id: row.get("main_color_id"),
content: row.get("content"),
note: row.get("note"),
task_status_id: row.get("task_status_id"),
assignee_id: row.get("assignee_id"),
employee_id: row.get("employee_id"),
dept_id: row.get("dept_id"),
task_type: row.get("task_type"),
}
}
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_TASK, &[&self.id, &self.header, &self.dt_cre, &self.dt_beg, &self.mark_color_id, &self.main_color_id, &self.content, &self.note, &self.task_status_id, &self.assignee_id, &self.employee_id, &self.dept_id, &self.task_type]).await?;
Ok(())
}
pub async fn complete(&mut self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(COMPLETE_TASK_BY_ID, &[&self.id]).await?;
client.execute(COMPLETE_TASK_BY_ID_SUB, &[&self.id]).await?;
self.main_color_id = 6;
self.task_status_id = 2;
Ok(())
}
pub async fn set_employee(&mut self, pool: &Pool<PostgresConnectionManager<NoTls>>, employee_id: i32) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
if let Some(employee) = User::get_user_by_id(employee_id, pool).await? {
client.execute(SET_TASK_EMPLOYEE, &[&self.id, &employee.id, &employee.dept_id]).await?;
self.employee_id = Some(employee.id);
self.dept_id = employee.dept_id.unwrap();
}
Ok(())
}
pub async fn set_employee_and_dept(&mut self, pool: &Pool<PostgresConnectionManager<NoTls>>, employee_id: &i32, dept_id: &i32) -> Result<(), Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
client.execute(SET_TASK_EMPLOYEE, &[&self.id, employee_id, dept_id]).await?;
self.employee_id = Some(employee_id.clone());
self.dept_id = dept_id.clone();
Ok(())
}
pub async fn get_by_id(id: i32, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Self, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let row = client.query_one(GET_TASK_BY_ID, &[&id]).await?;
Ok(Self::convert_from_row(&row))
}
pub fn get_task_color_from_str(str: &str) -> i32 {
let mut color_id = 11;
if str.to_uppercase().contains("ПЛОТН") {
color_id = 5;
}
if str.to_uppercase().contains("САНТЕ") {
color_id = 7;
} else if str.to_uppercase().contains("ТАКЕЛ") || str.to_uppercase().contains("ГРУЗ") || str.to_uppercase().contains("НОСИЛ") {
color_id = 10;
} else if str.to_uppercase().contains("ЭЛЕКТ") {
color_id = 1;
} else if str.to_uppercase().contains("IT") || str.to_uppercase().contains("АТИ") || str.to_uppercase().contains("АЙТИ") || str.to_uppercase().contains("КОМП") {
color_id = 2;
} else if str.to_uppercase().contains("СТРОИ") {
color_id = 3;
}
color_id
}
pub async fn get_subscribers(&self, pool: &Pool<PostgresConnectionManager<NoTls>>) -> Result<Vec<User>, Box<dyn Error + Sync + Send>> {
let connection = pool.get().await?;
let client = connection.client();
let rows = client.query(GET_TASK_SUBSCRIBERS, &[&self.id]).await?;
let result = rows.into_iter().map(|row| User::convert_from_row(&row)).collect();
Ok(result)
}
}