Skip to content

Commit

Permalink
add sqlite and postgres database draft
Browse files Browse the repository at this point in the history
  • Loading branch information
thebino committed Sep 15, 2023
1 parent 3d063af commit e54caca
Show file tree
Hide file tree
Showing 26 changed files with 631 additions and 261 deletions.
1 change: 1 addition & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --all-targets

lints:
name: Lints
Expand Down
12 changes: 8 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ reqwest = { version = "0.11", default-features = false, features = ["blocking",

serde = "1.0.183"
serde_json = { version = "1.0.104", features = ["raw_value"] }
serde_with = "3.3.0"
serde_urlencoded = "0.7.1"
smallvec = "1.8.0"
sqlx = "0.7.1"
Expand Down
3 changes: 3 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ doctest = false
async-trait.workspace = true
axum.workspace = true
http.workspace = true
photos_network_plugin = { path = "../plugin_interface" }

serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
serde_with.workspace = true
time.workspace = true
tracing.workspace = true
uuid = { workspace = true, features = ["serde"] }
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
/* Photos.network · A privacy first photo storage and sharing service for fediverse.
* Copyright (C) 2020 Photos network developers
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use crate::sensitive::Sensitive;

//! Login request
//!
//! Provides an abstraction over a vlue for sensitive data like passwords.
//! It is not printing its value to logs or tracing
//!
//!
use serde::{Deserialize, Serialize};

use crate::model::sensitive::Sensitive;

#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Login {
pub username_or_email: Sensitive<String>,
pub password: Sensitive<String>,
pub totp_2fa_token: Option<String>,
pub username_or_email: Sensitive<String>,
pub password: Sensitive<String>,
pub totp_2fa_token: Option<String>,
}

//! Login response
//!
//! * `jwt` - None if email verification is enabled.
//! * `verify_email_sent` - Indicates if an email verification is needed.
//!
#[skip_serializing_none]
// Login response
//
// * `jwt` - None if email verification is enabled.
// * `verify_email_sent` - Indicates if an email verification is needed.
//
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct LoginResponse {
pub jwt: Option<Sensitive<String>>,
pub registration_created: bool,
pub verify_email_sent: bool,
pub jwt: Option<Sensitive<String>>,
pub registration_created: bool,
pub verify_email_sent: bool,
}
2 changes: 2 additions & 0 deletions crates/common/src/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod login;
pub mod user;
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ use uuid::Uuid;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct User {
pub uuid: Uuid,
email: String,
password: Option<String>,
lastname: Option<String>,
firstname: Option<String>,
is_locked: bool,
created_at: OffsetDateTime,
updated_at: Option<OffsetDateTime>,
last_login: Option<OffsetDateTime>,
pub uuid: String, //Uuid,
pub email: String,
pub password: Option<String>,
pub lastname: Option<String>,
pub firstname: Option<String>,
pub is_locked: bool,
pub created_at: OffsetDateTime,
pub updated_at: Option<OffsetDateTime>,
pub last_login: Option<OffsetDateTime>,
}

impl fmt::Display for User {
Expand All @@ -45,7 +45,7 @@ impl fmt::Display for User {
impl User {
pub(crate) fn new(email: String) -> User {
User {
uuid: Uuid::new_v4(),
uuid: Uuid::new_v4().hyphenated().to_string(),
email,
password: Option::None,
lastname: Option::None,
Expand Down
12 changes: 12 additions & 0 deletions crates/common/src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use async_trait::async_trait;
use std::error::Error;

use crate::auth::user::User;

#[async_trait]
pub trait Database {
async fn setup(&mut self) -> Result<(), Box<dyn Error>>;
async fn create_user(&self, user: &User) -> Result<(), Box<dyn Error>>;
async fn update_email(&self, email: &str, user_id: &str) -> Result<(), Box<dyn Error>>;
async fn get_users(&self) -> Result<Vec<User>, Box<dyn Error>>;
}
2 changes: 1 addition & 1 deletion crates/common/src/http/extractors/optuser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! This extractor checks if an `Authorization` is header and contains a valid JWT token.
//! Otherwise it will respond `Some(None)` to indicate an unauthorized user or a visiter without an account at all.
//!
use crate::model::auth::user::User;
use crate::auth::user::User;
use async_trait::async_trait;
use axum::extract::FromRequestParts;
use http::request::Parts;
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/http/extractors/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use axum::extract::FromRequestParts;
use axum::http::StatusCode;
use http::request::Parts;

use crate::model::auth::user::User;
use crate::auth::user::User;

#[async_trait]
impl<S> FromRequestParts<S> for User
Expand Down
34 changes: 33 additions & 1 deletion crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,41 @@

//! This crate offers shared data models for [Photos.network](https://photos.network) core application.
//!

use std::collections::HashMap;

use axum::Router;
use config::configuration::Configuration;
use database::Database;
use photos_network_plugin::{PluginFactoryRef, PluginId};

pub mod auth;
pub mod config;
pub mod database;
pub mod http;
pub mod model {
pub mod auth;
pub mod sensitive;
}

/// Aggregates the applications configuration, its loaded plugins and the router for all REST APIs
#[derive(Clone)]
pub struct ApplicationState<D> {
pub config: Configuration,
pub plugins: HashMap<PluginId, PluginFactoryRef>,
pub router: Option<Router>,
pub database: D,
}

impl<D> ApplicationState<D>
where
D: Database,
{
pub fn new(config: Configuration, database: D) -> Self {
Self {
config,
plugins: HashMap::new(),
router: None,
database,
}
}
}
1 change: 0 additions & 1 deletion crates/common/src/model/auth/mod.rs

This file was deleted.

4 changes: 4 additions & 0 deletions crates/database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ path = "src/lib.rs"
doctest = false

[dependencies]
common.workspace = true
async-trait.workspace = true
tracing.workspace = true
uuid.workspace = true
tokio.workspace = true
sqlx = { workspace = true, features = ["runtime-tokio", "tls-native-tls", "postgres", "mysql", "sqlite", "any", "macros", "migrate", "time" ] }

[dev-dependencies]
testdir.workspace = true
2 changes: 1 addition & 1 deletion crates/database/migrations/0001_initial.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS users (
--auto generated
uuid VARCHAR NOT NULL,
email VARCHAR,
email VARCHAR UNIQUE,
password VARCHAR,
lastname VARCHAR,
firstname VARCHAR,
Expand Down
115 changes: 3 additions & 112 deletions crates/database/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,112 +1,3 @@
/* Photos.network · A privacy first photo storage and sharing service for fediverse.
* Copyright (C) 2020 Photos network developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

//! This crate offers a database abstraction for [Photos.network](https://photos.network) core application.
//!
use async_trait::async_trait;
use sqlx::PgPool;
use sqlx::Row;
use std::error::Error;
use tracing::{error, info};
use uuid::Uuid;

pub struct User {
pub uuid: String,
pub email: String,
pub password: String,
pub lastname: String,
pub firstname: String,
}

#[async_trait]
pub trait Database {
async fn setup(&mut self) -> Result<(), Box<dyn Error>>;
async fn create_user(&self, user: &User) -> Result<(), Box<dyn Error>>;
async fn update_user(&self, user: &User) -> Result<(), Box<dyn Error>>;
async fn get_users(&self) -> Result<Vec<User>, Box<dyn Error>>;
}

pub struct PostgresDatabase {
pub pool: PgPool,
}

impl PostgresDatabase {
pub async fn new(db_url: &str) -> Self {
let pool = sqlx::postgres::PgPool::connect(db_url).await.unwrap();

PostgresDatabase { pool }
}
}

#[async_trait]
impl Database for PostgresDatabase {
async fn setup(&mut self) -> Result<(), Box<dyn Error>> {
// run migrations from `migrations` directory
sqlx::migrate!("./migrations").run(&self.pool).await?;

Ok(())
}

async fn create_user(&self, user: &User) -> Result<(), Box<dyn Error>> {
let query = "INSERT INTO users (uuid, email, password, lastname, firstname) VALUES ($1, $2, $3, $4, $5)";
let id = Uuid::new_v4().hyphenated().to_string();
info!("create new user with id `{}`.", id);
sqlx::query(query)
.bind(id)
.bind(&user.email)
.bind(&user.password)
.bind(&user.lastname)
.bind(&user.firstname)
.execute(&self.pool)
.await?;

Ok(())
}

async fn update_user(&self, user: &User) -> Result<(), Box<dyn Error>> {
let query = "UPDATE users SET email = %1 WHERE uuid = $2";

sqlx::query(query)
.bind(&user.email)
.bind(&user.uuid)
.execute(&self.pool)
.await?;

Ok(())
}

async fn get_users(&self) -> Result<Vec<User>, Box<dyn Error>> {
let query = "SELECT uuid, email, password, lastname, firstname FROM users";

let res = sqlx::query(query);

let rows = res.fetch_all(&self.pool).await?;

let users = rows
.iter()
.map(|row| User {
uuid: row.get("uuid"),
email: row.get("email"),
password: row.get("password"),
lastname: row.get("lastname"),
firstname: row.get("firstname"),
})
.collect();

Ok(users)
}
}
//pub mod postgres;
pub mod postgres;
pub mod sqlite;
Loading

0 comments on commit e54caca

Please sign in to comment.