diff --git a/core/migration/src/m20230001_000001_create_mail_account.rs b/core/migration/src/m20230001_000001_create_mail_account.rs new file mode 100644 index 0000000..f633535 --- /dev/null +++ b/core/migration/src/m20230001_000001_create_mail_account.rs @@ -0,0 +1,67 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(MailAccount::Table) + .if_not_exists() + .col( + ColumnDef::new(MailAccount::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(MailAccount::Email).string().not_null()) + .col(ColumnDef::new(MailAccount::DisplayName).string().not_null()) + .col(ColumnDef::new(MailAccount::ImapHost).string().not_null()) + .col(ColumnDef::new(MailAccount::ImapPort).integer().not_null()) + .col(ColumnDef::new(MailAccount::SmtpHost).string().not_null()) + .col(ColumnDef::new(MailAccount::SmtpPort).integer().not_null()) + .col(ColumnDef::new(MailAccount::Username).string().not_null()) + .col(ColumnDef::new(MailAccount::Password).string().not_null()) + .col( + ColumnDef::new(MailAccount::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(Expr::current_timestamp()), + ) + .col( + ColumnDef::new(MailAccount::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(Expr::current_timestamp()), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(MailAccount::Table).to_owned()) + .await + } +} + +#[derive(DeriveIden)] +enum MailAccount { + Table, + Id, + Email, + DisplayName, + ImapHost, + ImapPort, + SmtpHost, + SmtpPort, + Username, + Password, + CreatedAt, + UpdatedAt, +} \ No newline at end of file diff --git a/core/src/dal.rs b/core/src/dal.rs index 764ea75..0a5a03b 100644 --- a/core/src/dal.rs +++ b/core/src/dal.rs @@ -1,15 +1,61 @@ use anyhow::Result; use sqlx::SqlitePool; -pub struct PanoramaDatabase(SqlitePool); +use crate::entity::mail_account; +use sea_orm::{DatabaseConnection, EntityTrait}; +use uuid::Uuid; -pub struct EnsureMailAccount { - imap_server_host: String, - imap_server_port: u16, +#[derive(Default)] +pub struct MailAccountOptions { + pub id: Option, + pub email: Option, + pub display_name: Option, + pub imap_host: Option, + pub imap_port: Option, + pub smtp_host: Option, + pub smtp_port: Option, + pub username: Option, + pub password: Option, +} + +pub struct PanoramaDatabase { + connection: DatabaseConnection, } impl PanoramaDatabase { - pub async fn ensure_mail_account(&self) -> Result<()> { - Ok(()) + pub async fn new(connection: DatabaseConnection) -> Self { + Self { connection } + } + + async fn ensure_mail_account( + &self, + options: MailAccountOptions, + ) -> Result { + let account = mail_account::ActiveModel { + id: Set(options.id.unwrap_or_else(Uuid::new_v4)), + email: Set(options.email.unwrap_or_default()), + display_name: Set(options.display_name.unwrap_or_default()), + imap_host: Set(options.imap_host.unwrap_or_default()), + imap_port: Set(options.imap_port.unwrap_or(993)), + smtp_host: Set(options.smtp_host.unwrap_or_default()), + smtp_port: Set(options.smtp_port.unwrap_or(587)), + username: Set(options.username.unwrap_or_default()), + password: Set(options.password.unwrap_or_default()), + }; + + mail_account::Entity::insert(account).exec(&self.connection) } } + +// pub struct PanoramaDatabase(SqlitePool); + +// pub struct EnsureMailAccount { +// imap_server_host: String, +// imap_server_port: u16, +// } + +// impl PanoramaDatabase { +// pub async fn ensure_mail_account(&self) -> Result<()> { +// Ok(()) +// } +// } diff --git a/core/src/entity/mail_account.rs b/core/src/entity/mail_account.rs new file mode 100644 index 0000000..bdd0d23 --- /dev/null +++ b/core/src/entity/mail_account.rs @@ -0,0 +1,23 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "mail_accounts")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub email: String, + pub display_name: String, + pub imap_host: String, + pub imap_port: i32, + pub smtp_host: String, + pub smtp_port: i32, + pub username: String, + pub password: String, // Note: In production, consider encryption + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} \ No newline at end of file diff --git a/core/src/entity/mod.rs b/core/src/entity/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/core/src/server.rs b/core/src/server.rs index afa4be0..d591fcc 100644 --- a/core/src/server.rs +++ b/core/src/server.rs @@ -1,4 +1,5 @@ use tonic::{Request, Response, Result}; +use sea_orm::DatabaseConnection; use crate::dal::PanoramaDatabase; use crate::server_proto::panorama_server::Panorama as PanoramaServerProto; @@ -8,7 +9,13 @@ pub struct Panorama { db: PanoramaDatabase, } -impl Panorama {} +impl Panorama { + pub async fn new(connection: DatabaseConnection) -> Self { + Self { + db: PanoramaDatabase::new(connection).await + } + } +} #[tonic::async_trait] impl PanoramaServerProto for Panorama { diff --git a/src/components/HorizontalPanels/HorizontalPanels.tsx b/src/components/HorizontalPanels/HorizontalPanels.tsx new file mode 100644 index 0000000..e69de29