Models: add basic binarycache/project/token machinery
Build nomnom / Build-NomNom (push) Successful in 3m38s Details

This commit is contained in:
Félix Baylac Jacqué 2023-11-29 12:10:04 +01:00
parent b508bbe18b
commit 0920bf7adb
4 changed files with 110 additions and 8 deletions

View File

@ -1,11 +1,10 @@
CREATE TABLE Users (
id UUID NOT NULL,
user_name text NOT NULL,
PRIMARY KEY (id)
id UUID PRIMARY KEY NOT NULL,
user_name text NOT NULL
);
CREATE TABLE Keys (
id SERIAL PRIMARY KEY,
id SERIAL PRIMARY KEY NOT NULL,
name text NOT NULL,
key_dump jsonb NOT NULL,
user_id UUID NOT NULL,
@ -13,10 +12,39 @@ CREATE TABLE Keys (
);
CREATE TABLE PendingRegistrations (
id uuid NOT NULL,
id uuid PRIMARY KEY NOT NULL,
user_id UUID NOT NULL,
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES Users(id),
PRIMARY KEY (id)
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES Users(id)
);
CREATE TABLE BinaryCaches (
id SERIAL PRIMARY KEY NOT NULL,
name text NOT NULL,
access_key text NOT NULL,
secret_key text NOT NULL,
region text NOT NULL
);
CREATE TABLE Projects (
id SERIAL PRIMARY KEY NOT NULL,
name text NOT NULL UNIQUE,
binary_cache_id integer NOT NULL,
-- TODO: figure out rules
CONSTRAINT fk_project_binary_cache FOREIGN KEY (binary_cache_id) REFERENCES BinaryCaches(id)
);
CREATE TABLE ProjectTokens (
id SERIAL PRIMARY KEY NOT NULL,
token UUID NOT NULL,
project_id integer NOT NULL,
CONSTRAINT fk_project_project_token FOREIGN KEY (project_id) REFERENCES Projects(id)
);
CREATE TABLE Closures (
id SERIAL PRIMARY KEY NOT NULL,
project_id integer NOT NULL,
objects text[] NOT NULL,
CONSTRAINT fk_project_closure FOREIGN KEY (project_id) REFERENCES Projects(id)
);
-- We'll mostly querying the Keys using the associated uid.

View File

@ -20,7 +20,11 @@ pub async fn landing_page (app_state: web::Data<AppState<'_>>, req: HttpRequest)
}
/**
Checks if the user requesting the page is authenticated.
*/
async fn check_authentication(app_state: web::Data<AppState<'_>>, req: HttpRequest) -> Result<User, HttpResponse> {
fn redirect_to_login<T>(e: T, req: &HttpRequest) -> HttpResponse
where T: ToString
{

View File

@ -56,6 +56,9 @@ pub struct UserUuid(pub Uuid);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SessionUuid(pub Uuid);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ProjectUuid(pub Uuid);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct User {
pub uuid: UserUuid,
@ -81,6 +84,19 @@ pub struct Key {
pub key: Passkey
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BinaryCache {
pub name: String,
pub access_key: String,
pub secret_key: String,
pub region: String
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Project {
pub name: String,
}
impl AppState<'_> {
pub fn new(conf: Configuration) -> Self {
let rp = "localhost";
@ -169,4 +185,42 @@ impl AppState<'_> {
pub async fn update_user_keys(&self, user_id: &UserUuid, auth_res: AuthenticationResult) -> Result<()> {
authentication::update_user_keys(&self.db, user_id, auth_res).await
}
pub async fn create_binary_cache(&self, binary_cache: &BinaryCache) -> Result<()> {
let conn = self.db.get().await?;
let stmt = conn.prepare_cached("INSERT INTO BinaryCaches (name, access_key, secret_key, region) VALUES ($1, $2, $3, $4)").await?;
let _ = conn.execute(&stmt, &[&binary_cache.name, &binary_cache.access_key, &binary_cache.secret_key, &binary_cache.region]).await?;
Ok(())
}
pub async fn create_project(&self, binary_cache: &BinaryCache, project: &Project) -> Result<()> {
let conn = self.db.get().await?;
let stmt = conn.prepare_cached("INSERT INTO Projects (name, binary_cache_id) \
SELECT $1, b.id FROM BinaryCaches b \
WHERE b.name = $2").await?;
let _ = conn.execute(&stmt, &[&project.name, &binary_cache.name]).await?;
Ok(())
}
pub async fn create_project_token(&self, project: &Project) -> Result<ProjectUuid> {
let conn = self.db.get().await?;
let token = Uuid::new_v4();
let stmt = conn.prepare_cached("INSERT INTO ProjectTokens (token, project_id) \
SELECT $1, p.id FROM Projects p \
WHERE name = $2").await?;
let _ = conn.execute(&stmt, &[&token, &project.name]).await?;
Ok(ProjectUuid(token))
}
pub async fn get_project(&self, token: &ProjectUuid) -> Result<Project> {
let conn = self.db.get().await?;
let stmt = conn.prepare_cached("SELECT name FROM Projects p \
INNER JOIN ProjectTokens t ON p.id = t.project_id \
WHERE t.token = $1").await?;
let row = conn.query_one(&stmt, &[&token.0]).await?;
Ok(Project {
name: row.get(0)
})
}
}

View File

@ -1,6 +1,6 @@
use std::{process::{Command, Child}, env::temp_dir, path::PathBuf, fs::remove_dir_all, time::Duration};
use nom_nom_gc::models::{Configuration, AppState, User, UserUuid};
use nom_nom_gc::models::{Configuration, AppState, User, UserUuid, BinaryCache, Project};
use tokio::time::sleep;
use uuid::Uuid;
use anyhow::Result;
@ -64,6 +64,22 @@ async fn test_db() {
let usr2 = state.retrieve_registration_user(&reg_uuid).await.expect("should retrieve user from reg uuid");
let usr2 = usr2.expect("should retrieve user from reg uuid");
assert_eq!(test_user, usr2);
let binary_cache = BinaryCache {
name: "test-cache".to_string(),
access_key: "access key".to_string(),
secret_key: "secret key".to_string(),
region: "reg-01".to_string(),
};
state.create_binary_cache(&binary_cache).await.unwrap();
let project = Project {
name: "super-duper-project".to_string()
};
state.create_project(&binary_cache, &project).await.unwrap();
let token = state.create_project_token(&project).await.unwrap();
let project2 = state.get_project(&token).await.unwrap();
assert_eq!(project, project2);
teardown_db(db).expect("Failed to teardown DB.");