Skip to content

Commit

Permalink
Introduce LogEntry & cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
lucemans committed Dec 1, 2024
1 parent 49dbcb0 commit 75ff4b6
Show file tree
Hide file tree
Showing 18 changed files with 110 additions and 41 deletions.
2 changes: 1 addition & 1 deletion engine/migrations/0001_init.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ CREATE TABLE users (
);

-- Insert a system user
INSERT INTO users (user_id, oauth_sub, oauth_data, nickname) VALUES (0, '$$SYSTEM$$', '{}', 'System');
INSERT INTO users (user_id, oauth_sub, oauth_data, nickname) VALUES (1, '$$SYSTEM$$', '{}', 'System');

-- Create Sessions table
CREATE TABLE sessions (
Expand Down
1 change: 1 addition & 0 deletions engine/migrations/0002_logentry.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE logentries;
25 changes: 25 additions & 0 deletions engine/migrations/0002_logentry.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- Create the logs table
CREATE TABLE logs (
log_id SERIAL PRIMARY KEY,
resource_type TEXT NOT NULL,
resource_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
action TEXT NOT NULL,
data TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- Insert a test log entry
INSERT INTO logs (resource_type, resource_id, user_id, action, data) VALUES ('test', 1, 1, 'test', 'test');

-- Create indexes for common queries
CREATE INDEX logs_resource_type_idx ON logs(resource_type);
CREATE INDEX logs_resource_id_idx ON logs(resource_id);
CREATE INDEX logs_user_id_idx ON logs(user_id);
CREATE INDEX logs_action_idx ON logs(action);
CREATE INDEX logs_created_at_idx ON logs(created_at);

-- Add foreign key constraint to users table
ALTER TABLE logs
ADD CONSTRAINT logs_user_id_fkey
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE;
4 changes: 2 additions & 2 deletions engine/src/models/field/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::database::Database;
use crate::models::field::kind::FieldKind;
use serde::{Deserialize, Serialize};
use poem_openapi::Object;
use sqlx::FromRow;
use sqlx::{query_as, FromRow};

#[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)]
pub struct FieldDefinition {
Expand All @@ -19,7 +19,7 @@ impl FieldDefinition {
name: String,
database: &Database,
) -> Result<FieldDefinition, sqlx::Error> {
sqlx::query_as!(
query_as!(
FieldDefinition,
"INSERT INTO field_definitions (kind, name) VALUES ($1, $2) RETURNING *",
kind.to_string(),
Expand Down
5 changes: 0 additions & 5 deletions engine/src/models/field/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
use serde::{Deserialize, Serialize};
use sqlx::prelude::*;

use crate::database::Database;

pub mod kind;
pub mod definition;
3 changes: 2 additions & 1 deletion engine/src/models/item/field.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

use crate::database::Database;
use serde::{Deserialize, Serialize};
use sqlx::query_as;

#[derive(sqlx::FromRow, poem_openapi::Object, Debug, Clone, Serialize, Deserialize)]
pub struct ItemField {
Expand All @@ -18,7 +19,7 @@ impl ItemField {
value: serde_json::Value,
database: &Database,
) -> Result<ItemField, sqlx::Error> {
sqlx::query_as!(
query_as!(
ItemField,
"INSERT INTO item_fields (item_id, definition_id, value) VALUES ($1, $2, $3) RETURNING *",
item_id,
Expand Down
3 changes: 2 additions & 1 deletion engine/src/models/item/media.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::database::Database;
use serde::{Deserialize, Serialize};
use sqlx::query_as;

#[derive(sqlx::FromRow, poem_openapi::Object, Debug, Clone, Serialize, Deserialize)]
pub struct ItemMedia {
Expand All @@ -13,7 +14,7 @@ impl ItemMedia {
media_id: i32,
database: &Database,
) -> Result<ItemMedia, sqlx::Error> {
sqlx::query_as!(
query_as!(
ItemMedia,
"INSERT INTO item_media (item_id, media_id) VALUES ($1, $2) RETURNING *",
item_id,
Expand Down
15 changes: 8 additions & 7 deletions engine/src/models/item/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use serde::{Deserialize, Serialize};
use sqlx::prelude::*;
use sqlx::{query, query_as};
use tracing::info;
use chrono::{DateTime, Utc};

use crate::database::Database;

Expand All @@ -14,8 +15,8 @@ pub struct Item {
pub product_id: Option<i32>,
pub owner_id: Option<i32>,
pub location_id: Option<i32>,
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
pub created_at: Option<DateTime<Utc>>,
pub updated_at: Option<DateTime<Utc>>,
}

impl Default for Item {
Expand All @@ -41,7 +42,7 @@ impl Item {
product_id: Option<i32>,
database: &Database,
) -> Result<Item, sqlx::Error> {
sqlx::query_as!(
query_as!(
Item,
"INSERT INTO items (item_id, name, owner_id, location_id, product_id) VALUES ($1, $2, $3, $4, $5) RETURNING *",
item_id,
Expand All @@ -58,13 +59,13 @@ impl Item {
owner_id: i32,
database: &Database,
) -> Result<Vec<Item>, sqlx::Error> {
sqlx::query_as!(Item, "SELECT * FROM items WHERE owner_id = $1", owner_id)
query_as!(Item, "SELECT * FROM items WHERE owner_id = $1", owner_id)
.fetch_all(&database.pool)
.await
}

pub async fn get_by_id(item_id: String, database: &Database) -> Result<Option<Item>, sqlx::Error> {
sqlx::query_as!(Item, "SELECT * FROM items WHERE item_id = $1", item_id)
query_as!(Item, "SELECT * FROM items WHERE item_id = $1", item_id)
.fetch_optional(&database.pool)
.await
}
Expand All @@ -78,7 +79,7 @@ impl Item {
loop {
let id_str = id.to_string();
info!("Checking if id {} is taken", id_str);
if sqlx::query("SELECT 1 FROM items WHERE item_id = $1")
if query("SELECT 1 FROM items WHERE item_id = $1")
.bind(id_str.clone())
.fetch_optional(&database.pool)
.await
Expand Down
4 changes: 2 additions & 2 deletions engine/src/models/location.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use poem_openapi::Object;
use sqlx::FromRow;
use sqlx::{query_as, FromRow};

use crate::database::Database;

Expand All @@ -15,7 +15,7 @@ pub struct Location {

impl Location {
pub async fn create(name: String, database: &Database) -> Result<Location, sqlx::Error> {
sqlx::query_as!(
query_as!(
Location,
"INSERT INTO locations (name) VALUES ($1) RETURNING *",
name
Expand Down
45 changes: 45 additions & 0 deletions engine/src/models/log/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use sqlx::{prelude::FromRow, query_as};
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use poem_openapi::Object;

use crate::database::Database;

/// Represents a log entry
/// When an action is performed on a resource, a log entry is created
/// This resource can then be queried by user, resource_type, (resource_type + resource_id), or action
#[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)]
pub struct LogEntry {
pub log_id: i32,
pub resource_type: String,
pub resource_id: i32,
pub user_id: i32,
pub action: String,
pub data: String,
pub created_at: DateTime<Utc>,
}

impl LogEntry {
/// Create a new log entry
/// Let postgres generate the id and created_at
pub async fn new(db: &Database, resource_type: String, resource_id: i32, user_id: i32, action: String, data: String) -> Result<Self, sqlx::Error> {
let log_entry = query_as!(
LogEntry,
"INSERT INTO logs (resource_type, resource_id, user_id, action, data) VALUES ($1, $2, $3, $4, $5) RETURNING *",
resource_type, resource_id, user_id, action, data
).fetch_one(&db.pool).await?;

Ok(log_entry)
}

/// Find by log_id
pub async fn find_by_log_id(db: &Database, log_id: i32) -> Result<Self, sqlx::Error> {
let log_entry = query_as!(
LogEntry,
"SELECT * FROM logs WHERE log_id = $1",
log_id
).fetch_one(&db.pool).await?;

Ok(log_entry)
}
}
6 changes: 3 additions & 3 deletions engine/src/models/media.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use sqlx::{query_as, FromRow};
use poem_openapi::Object;
use chrono::{DateTime, Utc};
use crate::database::Database;
Expand All @@ -21,7 +21,7 @@ impl Media {
kind: String,
database: &Database,
) -> Result<Media, sqlx::Error> {
sqlx::query_as!(
query_as!(
Media,
"INSERT INTO media (description, url, kind) VALUES ($1, $2, $3) RETURNING *",
Some(description),
Expand All @@ -36,7 +36,7 @@ impl Media {
media_id: i32,
database: &Database,
) -> Result<Media, sqlx::Error> {
sqlx::query_as!(Media, "SELECT * FROM media WHERE media_id = $1", media_id)
query_as!(Media, "SELECT * FROM media WHERE media_id = $1", media_id)
.fetch_one(&database.pool)
.await
}
Expand Down
1 change: 1 addition & 0 deletions engine/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod products;
pub mod sessions;
pub mod tags;
pub mod users;
pub mod log;
6 changes: 3 additions & 3 deletions engine/src/models/products.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use sqlx::{query_as, FromRow};
use poem_openapi::Object;
use chrono::{DateTime, Utc};
use crate::database::Database;
Expand All @@ -14,7 +14,7 @@ pub struct Product {

impl Product {
pub async fn create(name: String, database: &Database) -> Result<Product, sqlx::Error> {
sqlx::query_as!(
query_as!(
Product,
"INSERT INTO products (name) VALUES ($1) RETURNING *",
name
Expand All @@ -24,7 +24,7 @@ impl Product {
}

pub async fn get_by_id(product_id: i32, database: &Database) -> Result<Option<Product>, sqlx::Error> {
sqlx::query_as!(Product, "SELECT * FROM products WHERE product_id = $1", product_id)
query_as!(Product, "SELECT * FROM products WHERE product_id = $1", product_id)
.fetch_optional(&database.pool)
.await
}
Expand Down
16 changes: 8 additions & 8 deletions engine/src/models/sessions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use poem_openapi::Object;
use serde::{Deserialize, Serialize};
use sqlx::types::ipnetwork::IpNetwork;
use sqlx::{query_as, types::ipnetwork::IpNetwork};
use chrono::{DateTime, Utc};

use crate::database::Database;
Expand All @@ -25,7 +25,7 @@ impl Session {
user_ip: &IpNetwork,
database: &Database,
) -> Result<Self, sqlx::Error> {
let session = sqlx::query_as!(Session,
let session = query_as!(Session,
"INSERT INTO sessions (session_id, user_id, user_agent, user_ip) VALUES ($1, $2, $3, $4) RETURNING *",
session_id, user_id, user_agent, user_ip.to_string()
)
Expand All @@ -35,7 +35,7 @@ impl Session {
}

pub async fn _get_by_id(id: &str, database: &Database) -> Result<Option<Self>, sqlx::Error> {
let session = sqlx::query_as!(
let session = query_as!(
Session,
"SELECT * FROM sessions WHERE session_id = $1 AND valid = TRUE",
id
Expand All @@ -47,7 +47,7 @@ impl Session {
}

pub async fn try_access(id: &str, database: &Database) -> Result<Option<Self>, sqlx::Error> {
let session = sqlx::query_as!(
let session = query_as!(
Session,
"UPDATE sessions SET last_access = NOW() WHERE session_id = $1 AND valid = TRUE RETURNING *",
id
Expand All @@ -63,7 +63,7 @@ impl Session {
user_id: i32,
database: &Database,
) -> Result<Vec<Self>, sqlx::Error> {
let sessions = sqlx::query_as!(
let sessions = query_as!(
Session,
"SELECT * FROM sessions WHERE user_id = $1 AND valid = TRUE",
user_id
Expand All @@ -79,7 +79,7 @@ impl Session {
user_id: i32,
database: &Database,
) -> Result<Vec<Self>, sqlx::Error> {
let sessions = sqlx::query_as!(
let sessions = query_as!(
Session,
"UPDATE sessions SET valid = FALSE WHERE user_id = $1 RETURNING *",
user_id
Expand All @@ -96,7 +96,7 @@ impl Session {
user_id: i32,
database: &Database,
) -> Result<Vec<Self>, sqlx::Error> {
let sessions = sqlx::query_as!(
let sessions = query_as!(
Session,
"UPDATE sessions SET valid = FALSE WHERE user_id = $1 AND session_id = $2 RETURNING *",
user_id,
Expand All @@ -114,7 +114,7 @@ impl Session {
database: &Database,
_invalidate_before: chrono::DateTime<chrono::Utc>,
) -> Result<Vec<Self>, sqlx::Error> {
let sessions = sqlx::query_as!(
let sessions = query_as!(
Session,
"UPDATE sessions SET valid = FALSE WHERE user_id = $1 AND last_access < $2 RETURNING *",
user_id,
Expand Down
4 changes: 2 additions & 2 deletions engine/src/models/tags.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use sqlx::{query_as, FromRow};
use chrono::{DateTime, Utc};
use poem_openapi::Object;
use crate::database::Database;
Expand All @@ -14,7 +14,7 @@ pub struct Tag {

impl Tag {
pub async fn create(name: String, database: &Database) -> Result<Tag, sqlx::Error> {
sqlx::query_as!(Tag, "INSERT INTO tags (name) VALUES ($1) RETURNING *", name)
query_as!(Tag, "INSERT INTO tags (name) VALUES ($1) RETURNING *", name)
.fetch_one(&database.pool)
.await
}
Expand Down
8 changes: 4 additions & 4 deletions engine/src/models/users.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use openid::Userinfo;
use serde::{Deserialize, Serialize};
use sqlx::{types::Json, FromRow};
use sqlx::{query, query_as, types::Json, FromRow};
use url::Url;
use chrono::{DateTime, Utc};
use poem_openapi::Object;
Expand Down Expand Up @@ -31,7 +31,7 @@ impl UserEntry {
let oauth_data_json: Json<Userinfo> = Json(oauth_userinfo.clone());

// upsert into users table and select the result
sqlx::query("INSERT INTO users (oauth_sub, oauth_data, nickname) VALUES ($1, $2, $3) ON CONFLICT (oauth_sub) DO UPDATE SET oauth_data = $2, nickname = $3 RETURNING user_id, oauth_sub, oauth_data, nickname, created_at, updated_at")
query("INSERT INTO users (oauth_sub, oauth_data, nickname) VALUES ($1, $2, $3) ON CONFLICT (oauth_sub) DO UPDATE SET oauth_data = $2, nickname = $3 RETURNING user_id, oauth_sub, oauth_data, nickname, created_at, updated_at")
.bind(oauth_sub)
.bind(oauth_data_json)
.bind(nickname)
Expand All @@ -44,7 +44,7 @@ impl UserEntry {
oauth_sub: String,
database: &Database,
) -> Result<Option<UserEntry>, sqlx::Error> {
sqlx::query_as!(
query_as!(
UserEntry,
r#"SELECT user_id, oauth_sub, oauth_data::text::json as "oauth_data!: Json<Userinfo>",
nickname, created_at, updated_at FROM users WHERE oauth_sub = $1"#,
Expand All @@ -58,7 +58,7 @@ impl UserEntry {
user_id: i32,
database: &Database,
) -> Result<Option<UserEntry>, sqlx::Error> {
sqlx::query_as!(
query_as!(
UserEntry,
r#"SELECT user_id, oauth_sub, oauth_data::text::json as "oauth_data!: Json<Userinfo>",
nickname, created_at, updated_at FROM users WHERE user_id = $1"#,
Expand Down
2 changes: 1 addition & 1 deletion engine/src/routes/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use poem::web::{Data};
use poem_openapi::{payload::Json, Enum, Object, OpenApi};
use serde::{Deserialize, Serialize};

use crate::{auth::middleware::AuthToken, models::users::User, state::AppState};
use crate::{auth::middleware::AuthToken, state::AppState};

pub struct ApiInstance;

Expand Down
Loading

0 comments on commit 75ff4b6

Please sign in to comment.