diff --git a/.gitignore b/.gitignore index ea8c4bf7..b3041e56 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +dbml-error.log diff --git a/Cargo.lock b/Cargo.lock index 1b333958..e2b2feae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -630,15 +630,17 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", - "windows-targets 0.48.5", + "wasm-bindgen", + "windows-targets 0.52.0", ] [[package]] @@ -851,8 +853,10 @@ name = "entity" version = "0.1.0" dependencies = [ "axum-login", + "chrono", "sea-orm", "serde", + "uuid", ] [[package]] diff --git a/README.md b/README.md index 239ecc5b..c891b48d 100644 --- a/README.md +++ b/README.md @@ -11,41 +11,86 @@ The platform itself is useful for professional independent coaches, informal men ## Basic Local DB Setup and Management -### Set Up Database +## Running the Database Setup Script -Note: these are commands meant to run against a real Postgresql server. +1. Ensure you have PostgreSQL installed and running on your machine. If you're using macOS, you can use +[Postgres.app](https://postgresapp.com/) or install it with Homebrew: + + ```shell + brew install postgresql + ``` + +2. Make sure you have the `dbml2sql` tool installed. You can install it with npm: + + ```shell + npm install -g @dbml/cli + ``` + +3. Run the script with default settings: + + ```shell + ./scripts/rebuild_db.sh + ``` + + This will create a database named `refactor_platform`, a user named `refactor`, and a schema named `refactor_platform`. + +4. If you want to use different settings, you can provide them as arguments to the script: + + ```shell + ./scripts/rebuild_db.sh my_database my_user my_schema + ``` + + This will create a database named `my_database`, a user named `my_user`, and a schema named `my_schema`. + +Please note that the script assumes that the password for the new PostgreSQL user is `password`. If you want to use a different password, you'll need to modify the script accordingly. + +### Set Up Database Manually + +Note: these are commands meant to run against a real Postgresql server with an admin level user. ```sql ---create user -CREATE USER refactor_rs WITH PASSWORD 'password'; ---create schema -CREATE SCHEMA IF NOT EXISTS refactor_platform_rs; ---Check to see that the schema exists -SELECT schema_name FROM information_schema.schemata; ---Grant schema access to user -GRANT CREATE ON SCHEMA public TO refactor_rs; +--create new database `refactor_platform` +CREATE DATABASE refactor_platform; ``` -### Generate a New Migration -```bash -sea-orm-cli migrate generate your_table_name +Change to the refactor_platform DB visually if using app like Postico, otherwise change using the +Postgresql CLI: + +```sh +\c refactor_platform +``` + +```sql +--create new database user `refactor` +CREATE USER refactor WITH PASSWORD 'password'; +--create a new schema owned by user `refactor` +CREATE SCHEMA IF NOT EXISTS refactor_platform AUTHORIZATION refactor; +--Check to see that the schema `refactor_platform` exists in the results +SELECT schema_name FROM information_schema.schemata; +--Grant all privileges on schema `refactor_platform` to user `refactor` +GRANT ALL PRIVILEGES ON SCHEMA refactor_platform TO refactor; ``` ### Run Migrations -Note: this assumes a database name of `refactor_platform_rs` +Note: this assumes a database name of `refactor_platform` ```bash -DATABASE_URL=postgres://refactor_rs:password@localhost:5432/refactor_platform_rs sea-orm-cli migrate up -s refactor_platform_rs +DATABASE_URL=postgres://refactor:password@localhost:5432/refactor_platform sea-orm-cli migrate up -s refactor_platform ``` -### Generate Entity from Database +### Generate a new Entity from Database +Note that to generate a new Entity using the CLI you must ignore all other tables using the `--ignore-tables` option. You must add the option for _each_ table you are ignoring. + + ```bash - DATABASE_URL=postgres://refactor_rs:password@localhost:5432/refactor_platform_rs sea-orm-cli generate entity -s refactor_platform_rs -o entity/src + DATABASE_URL=postgres://refactor:password@localhost:5432/refactor_platform sea-orm-cli generate entity -s refactor_platform -o entity/src -v --with-serde both --serde-skip-deserializing-primary-key --ignore-tables {table to ignore} --ignore-tables {other table to ignore} ``` ## Project Directory Structure +`docs` - project documentation including architectural records, DB schema, API docs, etc + `entity_api` - data operations on the various `Entity` models `entity` - shape of the data models and the relationships to each other diff --git a/docs/db/refactor_platform_rs.dbml b/docs/db/refactor_platform_rs.dbml new file mode 100644 index 00000000..bcc3fb55 --- /dev/null +++ b/docs/db/refactor_platform_rs.dbml @@ -0,0 +1,114 @@ +// Use DBML to define your database structure +// Docs: https://dbml.dbdiagram.io/docs + +Table refactor_platform.organizations { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + name varchar [note: 'The name of the organization that the coach <--> coachee belong to'] + logo varchar [note: 'A URI pointing to the organization\'s logo icon file'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time fields were changed'] +} + +// Coaching relationship type belonging to the refactor_platform schema +// from the perspective of the coach +Table refactor_platform.coaching_relationships { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + organization_id integer [not null, note: 'The organization associated with this coaching relationship'] + coach_id integer [not null, note: 'The coach associated with this coaching relationship'] + coachee_id integer [not null, note: 'The coachee associated with this coaching relationship'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time fields were changed'] +} + +Table refactor_platform.users { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + email varchar [unique, not null] + first_name varchar + last_name varchar + display_name varchar [note: 'If a user wants to go by something other than first & last names'] + password varchar + github_username varchar // Specifically GH for now, can generalize later + github_profile_url varchar + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time fields were changed'] +} + +Table refactor_platform.coaching_sessions { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + coaching_relationship_id integer [not null, note: 'The coaching relationship (i.e. what coach & coachee under what organization) associated with this coaching session'] + date timestamp [note: 'The date and time of a session'] + timezone varchar [note: 'The baseline timezone used for the `date` field'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time fields were changed'] +} + +Table refactor_platform.overarching_goals { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + coaching_session_id integer [note: 'The coaching session that an overarching goal is associated with'] + title varchar [note: 'A short description of an overarching goal'] + details varchar [note: 'A long description of an overarching goal'] + completed_at timestamptz [note: 'The date and time an overarching goal was completed'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time fields were changed'] +} + +Table refactor_platform.notes { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + coaching_session_id integer [not null] + body varchar [note: 'Main text of the note supporting Markdown'] + user_id integer [not null, note: 'User that created (owns) the note'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time an overarching note\'s fields were changed'] +} + +Table refactor_platform.agreements { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + coaching_session_id integer [not null] + details varchar [note: 'Either a short or long description of an agreement reached between coach and coachee in a coaching session'] + user_id integer [not null, note: 'User that created (owns) the agreement'] + created_at timestamptz [default: `now()`] + updated_at timestamptz [default: `now()`, note: 'The last date and time an overarching agreement\'s fields were changed'] +} + +Table refactor_platform.actions { + id integer [primary key, unique, not null, increment] + external_id uuid [unique, not null, default: `gen_random_uuid()`, note: 'The publicly visible identifier for a record'] + // The first session where this action was created + // It will carry forward to every future session until + // its due_by is passed or it was completed by the coachee + coaching_session_id integer [not null] + due_by timestamptz + completed boolean // May be unnecessary if there's a valid completed_at timestamp + completed_at timestamptz + created_at timestamp [default: `now()`] + updated_at timestamp [default: `now()`] +} + +// coaching_relationships relationships +Ref: refactor_platform.coaching_relationships.organization_id > refactor_platform.organizations.id +Ref: refactor_platform.coaching_relationships.coachee_id > refactor_platform.users.id +Ref: refactor_platform.coaching_relationships.coach_id > refactor_platform.users.id + +// coaching_sessions relationships +Ref: refactor_platform.coaching_sessions.coaching_relationship_id > refactor_platform.coaching_relationships.id + +// overarching_goals relationships +Ref: refactor_platform.overarching_goals.coaching_session_id > refactor_platform.coaching_sessions.id + +// notes relationships +Ref: refactor_platform.notes.coaching_session_id > refactor_platform.coaching_sessions.id +Ref: refactor_platform.notes.user_id > refactor_platform.users.id + +// agreements relationships +Ref: refactor_platform.agreements.coaching_session_id > refactor_platform.coaching_sessions.id +Ref: refactor_platform.agreements.user_id > refactor_platform.users.id + +// actions relationships +Ref: refactor_platform.actions.coaching_session_id > refactor_platform.coaching_sessions.id diff --git a/entity/Cargo.toml b/entity/Cargo.toml index f9030066..6ace53d0 100644 --- a/entity/Cargo.toml +++ b/entity/Cargo.toml @@ -9,8 +9,10 @@ path = "src/lib.rs" [dependencies] axum-login = "0.12.0" +chrono = { version = "0.4.34", features = ["serde"] } serde = { version = "1", features = ["derive"] } - +uuid = "1.7.0" [dependencies.sea-orm] version = "0.12" +features = [ "with-uuid" ] diff --git a/entity/README.md b/entity/README.md index a7b26150..a2a0cdd9 100644 --- a/entity/README.md +++ b/entity/README.md @@ -1,10 +1,6 @@ ## Entity Schema Diagram - Definitions and Relationships -![refactor_entity_schema](https://github.com/Jim-Hodapp-Coaching/refactor-platform-rs/assets/3219120/1656ee0f-da18-41fb-9472-379fcca29500) - -## Example Data - A Journey with Multiple Steps - -![refactor_entity_example_multiple_journey_steps](https://github.com/Jim-Hodapp-Coaching/refactor-platform-rs/assets/3219120/e933a0f5-8651-4638-8d72-e4903b54d026) +![refactor_entity_schema](https://github.com/Jim-Hodapp-Coaching/refactor-platform-rs/assets/3219120/d8e25a4d-376e-40aa-99de-532f8be06fb0) ## Example Data - A User as a Coach and Coachee in Two Different Organizations diff --git a/entity/src/actions.rs b/entity/src/actions.rs new file mode 100644 index 00000000..d4c3286d --- /dev/null +++ b/entity/src/actions.rs @@ -0,0 +1,40 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "actions")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + #[sea_orm(unique)] + pub external_id: Uuid, + pub coaching_session_id: i32, + pub due_by: Option, + pub completed: Option, + pub completed_at: Option, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::coaching_sessions::Entity", + from = "Column::CoachingSessionId", + to = "super::coaching_sessions::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CoachingSessions, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CoachingSessions.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/agreements.rs b/entity/src/agreements.rs new file mode 100644 index 00000000..a26574b8 --- /dev/null +++ b/entity/src/agreements.rs @@ -0,0 +1,53 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "agreements")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + #[sea_orm(unique)] + pub external_id: Uuid, + pub coaching_session_id: i32, + pub details: Option, + pub user_id: i32, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::coaching_sessions::Entity", + from = "Column::CoachingSessionId", + to = "super::coaching_sessions::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CoachingSessions, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CoachingSessions.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/coaching_relationship.rs b/entity/src/coaching_relationship.rs index ff18de05..db9c4d75 100644 --- a/entity/src/coaching_relationship.rs +++ b/entity/src/coaching_relationship.rs @@ -1,17 +1,18 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 +use crate::Id; use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] #[sea_orm( - schema_name = "refactor_platform_rs", + schema_name = "refactor_platform", table_name = "coaching_relationships" )] pub struct Model { #[sea_orm(primary_key)] #[serde(skip_deserializing)] - pub id: i32, + pub id: Id, pub coachee_id: String, pub coach_id: String, pub organization_id: String, diff --git a/entity/src/coaching_sessions.rs b/entity/src/coaching_sessions.rs new file mode 100644 index 00000000..e15f6457 --- /dev/null +++ b/entity/src/coaching_sessions.rs @@ -0,0 +1,71 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "coaching_sessions")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + #[sea_orm(unique)] + pub external_id: Uuid, + pub coaching_relationship_id: i32, + pub date: Option, + pub timezone: Option, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::actions::Entity")] + Actions, + #[sea_orm(has_many = "super::agreements::Entity")] + Agreements, + #[sea_orm( + belongs_to = "super::coaching_relationships::Entity", + from = "Column::CoachingRelationshipId", + to = "super::coaching_relationships::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CoachingRelationships, + #[sea_orm(has_many = "super::notes::Entity")] + Notes, + #[sea_orm(has_many = "super::overarching_goals::Entity")] + OverarchingGoals, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Actions.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Agreements.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CoachingRelationships.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Notes.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::OverarchingGoals.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/lib.rs b/entity/src/lib.rs index b0954dc4..79895d5e 100644 --- a/entity/src/lib.rs +++ b/entity/src/lib.rs @@ -3,4 +3,4 @@ pub mod organization; pub mod user; /// A type alias that represents any Entity's id field data type -pub type Id = i32; // TODO: consider changing this to a u64 +pub type Id = i32; diff --git a/entity/src/mod.rs b/entity/src/mod.rs index 817ad2dd..49ed2372 100644 --- a/entity/src/mod.rs +++ b/entity/src/mod.rs @@ -2,6 +2,9 @@ pub mod prelude; -pub mod coaching_relationship; -pub mod organization; -pub mod user; +pub mod actions; +pub mod agreements; +pub mod coaching_sessions; +pub mod notes; +pub mod overarching_goals; +pub mod seaql_migrations; diff --git a/entity/src/notes.rs b/entity/src/notes.rs new file mode 100644 index 00000000..7424b0f1 --- /dev/null +++ b/entity/src/notes.rs @@ -0,0 +1,53 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "notes")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + #[sea_orm(unique)] + pub external_id: Uuid, + pub coaching_session_id: i32, + pub body: Option, + pub user_id: i32, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::coaching_sessions::Entity", + from = "Column::CoachingSessionId", + to = "super::coaching_sessions::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CoachingSessions, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CoachingSessions.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/organization.rs b/entity/src/organization.rs index 3ca749b3..0c52bc3c 100644 --- a/entity/src/organization.rs +++ b/entity/src/organization.rs @@ -1,15 +1,14 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 +use crate::Id; use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; - #[derive(Clone, Debug, Default, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] -#[sea_orm(schema_name = "refactor_platform_rs", table_name = "organizations")] +#[sea_orm(schema_name = "refactor_platform", table_name = "organizations")] pub struct Model { #[sea_orm(primary_key)] #[serde(skip_deserializing)] - // TODO: consider changing this to a u64 - pub id: i32, + pub id: Id, pub name: String, } diff --git a/entity/src/overarching_goals.rs b/entity/src/overarching_goals.rs new file mode 100644 index 00000000..5be58155 --- /dev/null +++ b/entity/src/overarching_goals.rs @@ -0,0 +1,40 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "overarching_goals")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + #[sea_orm(unique)] + pub external_id: Uuid, + pub coaching_session_id: Option, + pub title: Option, + pub details: Option, + pub completed_at: Option, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::coaching_sessions::Entity", + from = "Column::CoachingSessionId", + to = "super::coaching_sessions::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CoachingSessions, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CoachingSessions.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/prelude.rs b/entity/src/prelude.rs index a2a78f2e..7979ec41 100644 --- a/entity/src/prelude.rs +++ b/entity/src/prelude.rs @@ -1,5 +1,8 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 -pub use super::coaching_relationships::Entity as CoachingRelationships; -pub use super::organizations::Entity as Organizations; -pub use super::users::Entity as Users; +pub use super::actions::Entity as Actions; +pub use super::agreements::Entity as Agreements; +pub use super::coaching_sessions::Entity as CoachingSessions; +pub use super::notes::Entity as Notes; +pub use super::overarching_goals::Entity as OverarchingGoals; +pub use super::seaql_migrations::Entity as SeaqlMigrations; diff --git a/entity/src/seaql_migrations.rs b/entity/src/seaql_migrations.rs new file mode 100644 index 00000000..093c3db9 --- /dev/null +++ b/entity/src/seaql_migrations.rs @@ -0,0 +1,18 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "seaql_migrations")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + #[serde(skip_deserializing)] + pub version: String, + pub applied_at: i64, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/user.rs b/entity/src/user.rs index a20c605a..05e48cf1 100644 --- a/entity/src/user.rs +++ b/entity/src/user.rs @@ -2,20 +2,26 @@ use crate::Id; use axum_login::AuthUser; +use chrono::{DateTime, Utc}; use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)] -#[sea_orm(schema_name = "refactor_platform_rs", table_name = "users")] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] +#[sea_orm(schema_name = "refactor_platform", table_name = "users")] pub struct Model { #[sea_orm(primary_key)] #[serde(skip_deserializing)] pub id: Id, #[sea_orm(unique, indexed)] pub email: String, - pub password: String, pub first_name: String, pub last_name: String, + pub display_name: String, + pub password: String, + pub github_username: String, + pub github_profile_url: String, + pub created_at: DateTime, + pub updated_at: DateTime, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/entity_api/src/user.rs b/entity_api/src/user.rs index 1968feb6..618a727e 100644 --- a/entity_api/src/user.rs +++ b/entity_api/src/user.rs @@ -76,14 +76,24 @@ pub(crate) async fn seed_database(db: &DatabaseConnection) { email: ActiveValue::Set("james.hodapp@gmail.com".to_owned()), first_name: ActiveValue::Set("Jim".to_owned()), last_name: ActiveValue::Set("Hodapp".to_owned()), + display_name: ActiveValue::Set("Jim H".to_owned()), password: ActiveValue::Set(generate_hash("password1").to_owned()), + github_username: ActiveValue::Set("jhodapp".to_owned()), + github_profile_url: ActiveValue::Set("https://github.com/jhodapp".to_owned()), + created_at: ActiveValue::NotSet, + updated_at: ActiveValue::NotSet, }, user::ActiveModel { id: ActiveValue::NotSet, email: ActiveValue::Set("test@gmail.com".to_owned()), first_name: ActiveValue::Set("Test First".to_owned()), last_name: ActiveValue::Set("Test Last".to_owned()), + display_name: ActiveValue::Set("Test User".to_owned()), password: ActiveValue::Set(generate_hash("password2").to_owned()), + github_username: ActiveValue::Set("test".to_owned()), + github_profile_url: ActiveValue::Set("https://github.com/test".to_owned()), + created_at: ActiveValue::NotSet, + updated_at: ActiveValue::NotSet, }, ]; @@ -91,7 +101,7 @@ pub(crate) async fn seed_database(db: &DatabaseConnection) { debug!("user: {:?}", user); // Upserts seeded user data: - let _res = user::Entity::insert(user) + match user::Entity::insert(user) .on_conflict( // on conflict do update sea_query::OnConflict::column(user::Column::Email) @@ -101,6 +111,10 @@ pub(crate) async fn seed_database(db: &DatabaseConnection) { .to_owned(), ) .exec(db) - .await; + .await + { + Ok(_) => info!("Succeeded in seeding user data."), + Err(e) => error!("Failed to insert or update user when seeding user data: {e}"), + }; } } diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 10f25928..0a61a398 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -1,18 +1,12 @@ pub use sea_orm_migration::prelude::*; -mod m20230930_182906_create_organizations; -mod m20230930_195750_coaching_relationships; -mod m20230930_200501_users; +mod m20240211_174355_base_migration; pub struct Migrator; #[async_trait::async_trait] impl MigratorTrait for Migrator { fn migrations() -> Vec> { - vec![ - Box::new(m20230930_182906_create_organizations::Migration), - Box::new(m20230930_195750_coaching_relationships::Migration), - Box::new(m20230930_200501_users::Migration), - ] + vec![Box::new(m20240211_174355_base_migration::Migration)] } } diff --git a/migration/src/m20230930_182906_create_organizations.rs b/migration/src/m20230930_182906_create_organizations.rs deleted file mode 100644 index 8d8d3355..00000000 --- a/migration/src/m20230930_182906_create_organizations.rs +++ /dev/null @@ -1,39 +0,0 @@ -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(Organizations::Table) - .if_not_exists() - .col( - ColumnDef::new(Organizations::Id) - .integer() - .not_null() - .auto_increment() - .primary_key(), - ) - .col(ColumnDef::new(Organizations::Name).string().not_null()) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Organizations::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum Organizations { - Table, - Id, - Name, -} diff --git a/migration/src/m20230930_195750_coaching_relationships.rs b/migration/src/m20230930_195750_coaching_relationships.rs deleted file mode 100644 index 66aa5015..00000000 --- a/migration/src/m20230930_195750_coaching_relationships.rs +++ /dev/null @@ -1,55 +0,0 @@ -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(CoachingRelationships::Table) - .if_not_exists() - .col( - ColumnDef::new(CoachingRelationships::Id) - .integer() - .not_null() - .auto_increment() - .primary_key(), - ) - .col( - ColumnDef::new(CoachingRelationships::CoacheeId) - .string() - .not_null(), - ) - .col( - ColumnDef::new(CoachingRelationships::CoachId) - .string() - .not_null(), - ) - .col( - ColumnDef::new(CoachingRelationships::OrganizationId) - .string() - .not_null(), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(CoachingRelationships::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum CoachingRelationships { - Table, - Id, - CoacheeId, - CoachId, - OrganizationId, -} diff --git a/migration/src/m20230930_200501_users.rs b/migration/src/m20230930_200501_users.rs deleted file mode 100644 index d3123ccb..00000000 --- a/migration/src/m20230930_200501_users.rs +++ /dev/null @@ -1,50 +0,0 @@ -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(Users::Table) - .if_not_exists() - .col( - ColumnDef::new(Users::Id) - .integer() - .not_null() - .auto_increment() - .primary_key(), - ) - .col( - ColumnDef::new(Users::Email) - .string() - .not_null() - .unique_key(), - ) - .col(ColumnDef::new(Users::Password).string().not_null()) - .col(ColumnDef::new(Users::FirstName).string().not_null()) - .col(ColumnDef::new(Users::LastName).string().not_null()) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Users::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum Users { - Table, - Id, - Email, - Password, - FirstName, - LastName, -} diff --git a/migration/src/m20240211_174355_base_migration.rs b/migration/src/m20240211_174355_base_migration.rs new file mode 100644 index 00000000..e3800e6f --- /dev/null +++ b/migration/src/m20240211_174355_base_migration.rs @@ -0,0 +1,43 @@ +use sea_orm_migration::prelude::*; +use std::fs::File; +use std::io::Read; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let db = manager.get_connection(); + + let stringify_err = |err| -> DbErr { + let string = format!("Migration error: {:?}", err); + DbErr::Migration(string) + }; + let mut file = + File::open("migration/src/refactor_platform_rs.sql").map_err(stringify_err)?; + + let mut sql = String::new(); + + file.read_to_string(&mut sql).map_err(stringify_err)?; + + process_sql(&sql); + + db.execute_unprepared(&sql).await?; + + Ok(()) + } + + async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> { + Ok(()) + } +} + +// format sql as valid sql statements +fn process_sql(sql: &str) -> String { + sql.replace(';', ";\n") + .lines() + .filter(|line| !line.trim().starts_with("--")) + .collect::>() + .join("\n") +} diff --git a/migration/src/refactor_platform_rs.sql b/migration/src/refactor_platform_rs.sql new file mode 100644 index 00000000..938e2d13 --- /dev/null +++ b/migration/src/refactor_platform_rs.sql @@ -0,0 +1,173 @@ +-- SQL dump generated using DBML (dbml-lang.org) +-- Database: PostgreSQL +-- Generated at: 2024-02-18T13:46:48.698Z + + +CREATE TABLE "refactor_platform"."organizations" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "name" varchar, + "logo" varchar, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."coaching_relationships" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "organization_id" integer NOT NULL, + "coach_id" integer NOT NULL, + "coachee_id" integer NOT NULL, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."users" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "email" varchar UNIQUE NOT NULL, + "first_name" varchar, + "last_name" varchar, + "display_name" varchar, + "password" varchar, + "github_username" varchar, + "github_profile_url" varchar, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."coaching_sessions" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "coaching_relationship_id" integer NOT NULL, + "date" timestamp, + "timezone" varchar, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."overarching_goals" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "coaching_session_id" integer, + "title" varchar, + "details" varchar, + "completed_at" timestamptz, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."notes" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "coaching_session_id" integer NOT NULL, + "body" varchar, + "user_id" integer NOT NULL, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."agreements" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "coaching_session_id" integer NOT NULL, + "details" varchar, + "user_id" integer NOT NULL, + "created_at" timestamptz DEFAULT (now()), + "updated_at" timestamptz DEFAULT (now()) +); + +CREATE TABLE "refactor_platform"."actions" ( + "id" INTEGER GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY NOT NULL, + "external_id" uuid UNIQUE NOT NULL DEFAULT (gen_random_uuid()), + "coaching_session_id" integer NOT NULL, + "due_by" timestamptz, + "completed" boolean, + "completed_at" timestamptz, + "created_at" timestamp DEFAULT (now()), + "updated_at" timestamp DEFAULT (now()) +); + +COMMENT ON COLUMN "refactor_platform"."organizations"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."organizations"."name" IS 'The name of the organization that the coach <--> coachee belong to'; + +COMMENT ON COLUMN "refactor_platform"."organizations"."logo" IS 'A URI pointing to the organization''s logo icon file'; + +COMMENT ON COLUMN "refactor_platform"."organizations"."updated_at" IS 'The last date and time fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."coaching_relationships"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."coaching_relationships"."organization_id" IS 'The organization associated with this coaching relationship'; + +COMMENT ON COLUMN "refactor_platform"."coaching_relationships"."coach_id" IS 'The coach associated with this coaching relationship'; + +COMMENT ON COLUMN "refactor_platform"."coaching_relationships"."coachee_id" IS 'The coachee associated with this coaching relationship'; + +COMMENT ON COLUMN "refactor_platform"."coaching_relationships"."updated_at" IS 'The last date and time fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."users"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."users"."display_name" IS 'If a user wants to go by something other than first & last names'; + +COMMENT ON COLUMN "refactor_platform"."users"."updated_at" IS 'The last date and time fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."coaching_sessions"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."coaching_sessions"."coaching_relationship_id" IS 'The coaching relationship (i.e. what coach & coachee under what organization) associated with this coaching session'; + +COMMENT ON COLUMN "refactor_platform"."coaching_sessions"."date" IS 'The date and time of a session'; + +COMMENT ON COLUMN "refactor_platform"."coaching_sessions"."timezone" IS 'The baseline timezone used for the `date` field'; + +COMMENT ON COLUMN "refactor_platform"."coaching_sessions"."updated_at" IS 'The last date and time fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."coaching_session_id" IS 'The coaching session that an overarching goal is associated with'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."title" IS 'A short description of an overarching goal'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."details" IS 'A long description of an overarching goal'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."completed_at" IS 'The date and time an overarching goal was completed'; + +COMMENT ON COLUMN "refactor_platform"."overarching_goals"."updated_at" IS 'The last date and time fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."notes"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."notes"."body" IS 'Main text of the note supporting Markdown'; + +COMMENT ON COLUMN "refactor_platform"."notes"."user_id" IS 'User that created (owns) the note'; + +COMMENT ON COLUMN "refactor_platform"."notes"."updated_at" IS 'The last date and time an overarching note''s fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."agreements"."external_id" IS 'The publicly visible identifier for a record'; + +COMMENT ON COLUMN "refactor_platform"."agreements"."details" IS 'Either a short or long description of an agreement reached between coach and coachee in a coaching session'; + +COMMENT ON COLUMN "refactor_platform"."agreements"."user_id" IS 'User that created (owns) the agreement'; + +COMMENT ON COLUMN "refactor_platform"."agreements"."updated_at" IS 'The last date and time an overarching agreement''s fields were changed'; + +COMMENT ON COLUMN "refactor_platform"."actions"."external_id" IS 'The publicly visible identifier for a record'; + +ALTER TABLE "refactor_platform"."coaching_relationships" ADD FOREIGN KEY ("organization_id") REFERENCES "refactor_platform"."organizations" ("id"); + +ALTER TABLE "refactor_platform"."coaching_relationships" ADD FOREIGN KEY ("coachee_id") REFERENCES "refactor_platform"."users" ("id"); + +ALTER TABLE "refactor_platform"."coaching_relationships" ADD FOREIGN KEY ("coach_id") REFERENCES "refactor_platform"."users" ("id"); + +ALTER TABLE "refactor_platform"."coaching_sessions" ADD FOREIGN KEY ("coaching_relationship_id") REFERENCES "refactor_platform"."coaching_relationships" ("id"); + +ALTER TABLE "refactor_platform"."overarching_goals" ADD FOREIGN KEY ("coaching_session_id") REFERENCES "refactor_platform"."coaching_sessions" ("id"); + +ALTER TABLE "refactor_platform"."notes" ADD FOREIGN KEY ("coaching_session_id") REFERENCES "refactor_platform"."coaching_sessions" ("id"); + +ALTER TABLE "refactor_platform"."notes" ADD FOREIGN KEY ("user_id") REFERENCES "refactor_platform"."users" ("id"); + +ALTER TABLE "refactor_platform"."agreements" ADD FOREIGN KEY ("coaching_session_id") REFERENCES "refactor_platform"."coaching_sessions" ("id"); + +ALTER TABLE "refactor_platform"."agreements" ADD FOREIGN KEY ("user_id") REFERENCES "refactor_platform"."users" ("id"); + +ALTER TABLE "refactor_platform"."actions" ADD FOREIGN KEY ("coaching_session_id") REFERENCES "refactor_platform"."coaching_sessions" ("id"); diff --git a/scripts/rebuild_db.sh b/scripts/rebuild_db.sh new file mode 100755 index 00000000..ab176334 --- /dev/null +++ b/scripts/rebuild_db.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Define default variables +DB_NAME=${1:-"refactor_platform"} +DB_USER=${2:-"refactor"} +SCHEMA_NAME=${3:-"refactor_platform"} + +echo "Using the following configuration:" +echo "Database Name: $DB_NAME" +echo "Database User: $DB_USER" +echo "Schema Name: $SCHEMA_NAME" + +# Check if postgres is installed with its client CLI +[ -f $(which postgres) ] && +[ -f $(which pg_ctl ) ] && +[ -f $(which psql) ] > /dev/null 2>&1 || + { echo "Postgres and psql are not completely installed. Please install postgres with your package manager or Postgres.app and try again"; exit 1; } + +if [[ -z "${PGDATA}" ]]; then + echo 'Environment variable PGDATA unset. See `pg_ctl --help for more information.' +fi + +# Ensure postgres is running and start postgres with homebrew if it is not running +pg_ctl status > /dev/null 2>&1 || { echo "Starting Postgres..."; pg_ctl -w -t 15 start; } + +# Check if the postgres database exists and create it if it doesn't +POSTGRES_DB_EXISTS=$(psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname='postgres'") +if [ "$POSTGRES_DB_EXISTS" != "1" ]; then + echo "Creating 'postgres' database..." + createdb -U postgres postgres || { echo "Failed to create 'postgres' database"; exit 1; } +fi + +# Check if the user exists and create it if it doesn't +USER_EXISTS=$(psql -U postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'") +if [ "$USER_EXISTS" != "1" ]; then + echo "Creating user $DB_USER..." + psql -U postgres -c "CREATE USER $DB_USER;" || { echo "Failed to create user $DB_USER"; exit 1; } +fi + +# Check if the database exists +DB_EXISTS=$(psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'") + +# If the database exists, drop it +if [ "$DB_EXISTS" = "1" ]; then + echo "Database $DB_NAME exists. Dropping the database..." + psql -U postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" || { echo "Failed to drop database $DB_NAME"; exit 1; } +fi + +echo "Creating the database $DB_NAME..." +psql -U postgres -c "CREATE DATABASE $DB_NAME;" || { echo "Failed to create database $DB_NAME"; exit 1; } + +echo "Granting privileges to $DB_USER on $DB_NAME..." +psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;" + +# Check if the schema exists +SCHEMA_EXISTS=$(psql -U $DB_USER -d $DB_NAME -tAc "SELECT 1 FROM information_schema.schemata WHERE schema_name = '$SCHEMA_NAME'") + +# If the schema does not exist, create it +if [ "$SCHEMA_EXISTS" != "1" ]; then + echo "Creating schema $SCHEMA_NAME..." + psql -U $DB_USER -d $DB_NAME -c "CREATE SCHEMA $SCHEMA_NAME;" || { echo "Failed to create schema $SCHEMA_NAME"; exit 1; } +fi + +# Generating SQL for the migrations using dbml2sql +echo "Generating SQL for the migrations..." +dbml2sql docs/db/refactor_platform_rs.dbml -o migration/src/refactor_platform_rs.sql || { echo "Error generating SQL file"; exit 1; } + +# Remove the line to create a schema from the generated SQL file +echo "Modifying the generated SQL file..." +sed -i '' '/CREATE SCHEMA/d' migration/src/refactor_platform_rs.sql + +echo "Running the migrations..." +DATABASE_URL=postgres://$DB_USER:password@localhost:5432/$DB_NAME sea-orm-cli migrate up -s $SCHEMA_NAME || { echo "Failed to run migrations"; exit 1; } + +echo "Database setup and migrations completed successfully" \ No newline at end of file diff --git a/service/Cargo.toml b/service/Cargo.toml index f847da10..30d6bb7d 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -10,7 +10,8 @@ version = "0.12" # sea-orm version features = [ "debug-print", "runtime-tokio-native-tls", - "sqlx-postgres" + "sqlx-postgres", + "with-uuid" ] [dependencies] @@ -18,6 +19,6 @@ clap = { version = "4.4.6", features = ["cargo", "derive", "env"] } log = "0.4" simplelog = { version = "0.12", features = ["paris"] } serde_json = "1.0.107" -sqlx = { version = "0.7.3", features = ["sqlite", "time", "runtime-tokio"] } +sqlx = { version = "0.7.3", features = ["time", "runtime-tokio"] } tokio = { version = "1.35", features = ["full"] } tower = "0.4.13" diff --git a/service/src/config.rs b/service/src/config.rs index 34500cea..b1b0d064 100644 --- a/service/src/config.rs +++ b/service/src/config.rs @@ -10,7 +10,7 @@ pub struct Config { short, long, env, - default_value = "postgres://refactor_rs:password@localhost:5432/refactor_platform_rs" + default_value = "postgres://refactor:password@localhost:5432/refactor_platform" )] database_uri: Option, diff --git a/service/src/lib.rs b/service/src/lib.rs index 947910dd..3bd1b83a 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -16,7 +16,7 @@ pub async fn init_database(database_uri: &str) -> Result, + _next: Option, } pub struct UserSessionController {} @@ -63,7 +63,8 @@ impl UserSessionController { Ok(Redirect::to(next).into_response()) } else { let response_json = Json( - json!({"first_name": user.first_name, "last_name": user.last_name, "email": user.email}), + json!({"first_name": user.first_name, "last_name": user.last_name, + "email": user.email, "display_name": user.display_name}), ); debug!("JSON response with 200 OK: {:?}", response_json); Ok(response_json.into_response()) diff --git a/web/src/lib.rs b/web/src/lib.rs index 233ff1a2..6c364f34 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -10,8 +10,8 @@ use service::AppState; use std::net::SocketAddr; use std::str::FromStr; use time::Duration; -use tower_http::cors::CorsLayer; use tokio::net::TcpListener; +use tower_http::cors::CorsLayer; mod controller; mod error; @@ -24,11 +24,12 @@ pub async fn init_server(app_state: AppState) -> Result<()> { .db_conn_ref() .get_postgres_connection_pool() .to_owned(), - ); - // TODO: this put the created session under the tower_sessions/sessions in the DB, do we want this to - // be under refactor_platform_rs/user_sessions or something? - // See the following for setting the schema/table name pair: - // https://docs.rs/tower-sessions/latest/tower_sessions/struct.PostgresStore.html + ) + .with_schema_name("refactor_platform") // FIXME: consolidate all schema strings into a config field with default option + .unwrap() + .with_table_name("authorized_sessions") + .unwrap(); + session_store.migrate().await.unwrap(); let deletion_task = tokio::task::spawn(