Add data models

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 4 years ago
parent efc2f1cb8b
commit 8890c048f0
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -13,17 +13,13 @@
</component>
<component name="ChangeListManager">
<list default="true" id="db10ba0c-1d72-449d-b24f-24b5a4951941" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/.env" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/mod.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/users.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/server/mod.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/server/rpc_methods.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/server/user_rpc.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/permissions.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/role_permissions.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/roles.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/user_roles.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/database/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/database/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/database/users.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/database/users.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@ -51,6 +47,7 @@
<property name="cf.first.check.clang-format" value="false" />
<property name="nodejs_package_manager_path" value="npm" />
<property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" />
<property name="settings.editor.selected.configurable" value="language.rust.rustfmt" />
</component>
<component name="RunManager">
<configuration name="Run" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
@ -83,6 +80,7 @@
</configuration>
</component>
<component name="RustProjectSettings">
<option name="runRustfmtOnSave" value="true" />
<option name="toolchainHomeDirectory" value="/usr/bin" />
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
@ -93,7 +91,7 @@
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1599728150675</updated>
<workItem from="1599728152100" duration="2954000" />
<workItem from="1599728152100" duration="4301000" />
</task>
<servers />
</component>
@ -101,22 +99,38 @@
<option name="version" value="3" />
</component>
<component name="WindowStateProjectService">
<state width="1874" height="304" key="GridCell.Tab.0.bottom" timestamp="1599731076402">
<state x="769" y="295" key="#com.intellij.ide.util.MemberChooser" timestamp="1599732127954">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.bottom/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731076402" />
<state width="1874" height="304" key="GridCell.Tab.0.center" timestamp="1599731076402">
<state x="769" y="295" key="#com.intellij.ide.util.MemberChooser/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732127954" />
<state width="1874" height="304" key="GridCell.Tab.0.bottom" timestamp="1599732449376">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.center/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731076402" />
<state width="1874" height="304" key="GridCell.Tab.0.left" timestamp="1599731076402">
<state width="1874" height="304" key="GridCell.Tab.0.bottom/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732449376" />
<state width="1874" height="304" key="GridCell.Tab.0.center" timestamp="1599732449376">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.left/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731076402" />
<state width="1874" height="304" key="GridCell.Tab.0.right" timestamp="1599731076402">
<state width="1874" height="304" key="GridCell.Tab.0.center/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732449376" />
<state width="1874" height="304" key="GridCell.Tab.0.left" timestamp="1599732449376">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.right/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731076402" />
<state width="1874" height="304" key="GridCell.Tab.0.left/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732449376" />
<state width="1874" height="304" key="GridCell.Tab.0.right" timestamp="1599732449376">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.right/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732449376" />
<state x="457" y="211" key="SettingsEditor" timestamp="1599731723387">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state x="457" y="211" key="SettingsEditor/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731723387" />
<state x="763" y="489" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1599732361387">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state x="763" y="489" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732361387" />
<state x="620" y="265" key="run.anything.popup" timestamp="1599731922994">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state x="620" y="265" key="run.anything.popup/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599731922994" />
<state x="623" y="256" width="672" height="678" key="search.everywhere.popup" timestamp="1599730769441">
<screen x="0" y="0" width="1920" height="1158" />
</state>

@ -1,45 +1,64 @@
use crate::database::permissions::Permissions;
use crate::database::role_permissions::RolePermissions;
use crate::database::roles::Roles;
use crate::database::user_roles::UserRoles;
use crate::database::users::Users;
use dotenv;
use postgres::{Client, Error, NoTls};
use std::sync::{Arc, Mutex};
pub mod permissions;
pub mod role_permissions;
pub mod roles;
pub mod user_roles;
pub mod users;
use dotenv;
const DB_CONNECTION_URL: &str = "POSTGRES_CONNECTION_URL";
const DEFAULT_CONNECTION: &str = "postgres://postgres:postgres@localhost/postgrees";
pub trait Model {
fn new(connection: Arc<Mutex<Client>>) -> Self;
fn init(&self) -> Result<(), Error>;
}
#[derive(Clone)]
pub struct Database {
connection: Arc<Mutex<Client>>,
pub users: Users,
pub roles: Roles,
pub permissions: Permissions,
role_permission: RolePermissions,
user_roles: UserRoles,
}
type PostgresResult<T> = Result<T, Error>;
impl Database {
pub fn new() -> PostgresResult<Self> {
let connection = Arc::new(Mutex::new(get_connection()?));
Ok(Self {
users: Users::new(Arc::clone(&connection)),
roles: Roles::new(Arc::clone(&connection)),
permissions: Permissions::new(Arc::clone(&connection)),
user_roles: UserRoles::new(Arc::clone(&connection)),
role_permission: RolePermissions::new(Arc::clone(&connection)),
connection,
})
}
/// Inits all database models
pub fn init(&self) -> PostgresResult<()> {
self.users.init()?;
self.roles.init()?;
self.permissions.init()?;
self.user_roles.init()?;
self.role_permission.init()?;
Ok(())
}
}
/// Returns a database connection
pub fn get_connection() -> Result<Client, Error> {
fn get_connection() -> Result<Client, Error> {
let conn_url = dotenv::var(DB_CONNECTION_URL).unwrap_or(DEFAULT_CONNECTION.to_string());
Client::connect(conn_url.as_str(), NoTls)
}
/// Inits the database
pub fn init_database(client: &mut Client) -> Result<(), Error> {
client.batch_execute("
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(32) NOT NULL,
salt VARCHAR(16) NOT NULL
);
CREATE TABLE IF NOT EXISTS roles (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description VARCHAR(512)
);
CREATE TABLE IF NOT EXISTS user_roles (
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);
CREATE TABLE IF NOT EXISTS permissions (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description VARCHAR(512)
);
CREATE TABLE IF NOT EXISTS role_permissions (
role_id INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
permission_id INT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);
")
}

@ -0,0 +1,24 @@
use crate::database::Model;
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct Permissions {
connection: Arc<Mutex<Client>>,
}
impl Model for Permissions {
fn new(connection: Arc<Mutex<Client>>) -> Self {
Self { connection }
}
fn init(&self) -> Result<(), Error> {
self.connection.lock().unwrap().batch_execute(
"CREATE TABLE IF NOT EXISTS permissions (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description VARCHAR(512)
);",
)
}
}

@ -0,0 +1,25 @@
use crate::database::Model;
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct RolePermissions {
connection: Arc<Mutex<Client>>,
}
impl Model for RolePermissions {
fn new(connection: Arc<Mutex<Client>>) -> Self {
Self { connection }
}
fn init(&self) -> Result<(), Error> {
self.connection.lock().unwrap().batch_execute(
"
CREATE TABLE IF NOT EXISTS role_permissions (
role_id INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
permission_id INT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);",
)
}
}

@ -0,0 +1,30 @@
use crate::database::role_permissions::RolePermissions;
use crate::database::Model;
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct Roles {
connection: Arc<Mutex<Client>>,
role_permission: RolePermissions,
}
impl Model for Roles {
fn new(connection: Arc<Mutex<Client>>) -> Self {
Self {
role_permission: RolePermissions::new(Arc::clone(&connection)),
connection,
}
}
fn init(&self) -> Result<(), Error> {
self.connection.lock().unwrap().batch_execute(
"
CREATE TABLE IF NOT EXISTS roles (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description VARCHAR(512)
);",
)
}
}

@ -0,0 +1,25 @@
use crate::database::Model;
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct UserRoles {
connection: Arc<Mutex<Client>>,
}
impl Model for UserRoles {
fn new(connection: Arc<Mutex<Client>>) -> Self {
Self { connection }
}
fn init(&self) -> Result<(), Error> {
self.connection.lock().unwrap().batch_execute(
"
CREATE TABLE IF NOT EXISTS user_roles (
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);",
)
}
}

@ -0,0 +1,31 @@
use crate::database::user_roles::UserRoles;
use crate::database::Model;
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct Users {
connection: Arc<Mutex<Client>>,
user_roles: UserRoles,
}
impl Model for Users {
fn new(connection: Arc<Mutex<Client>>) -> Self {
Self {
user_roles: UserRoles::new(Arc::clone(&connection)),
connection,
}
}
fn init(&self) -> Result<(), Error> {
self.connection.lock().unwrap().batch_execute(
"CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(32) NOT NULL,
salt VARCHAR(16) NOT NULL
);",
)
}
}

@ -1,6 +1,6 @@
use flotte_user_management::database::{get_connection, init_database};
use flotte_user_management::database::Database;
fn main() {
let mut client = get_connection().unwrap();
init_database(&mut client).unwrap()
let database = Database::new().unwrap();
database.init().unwrap();
}

Loading…
Cancel
Save