Skip to content

Commit

Permalink
Introduce basic item logs
Browse files Browse the repository at this point in the history
  • Loading branch information
lucemans committed Dec 4, 2024
1 parent 73fafcf commit 27cef96
Show file tree
Hide file tree
Showing 11 changed files with 468 additions and 97 deletions.
3 changes: 3 additions & 0 deletions engine/migrations/0004_logentry_owners.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Alter logentry resource_id to be integer
ALTER TABLE logs
ALTER COLUMN resource_id TYPE INTEGER USING resource_id::INTEGER;
3 changes: 3 additions & 0 deletions engine/migrations/0004_logentry_owners.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--- Alter logentry resource_id to be text
ALTER TABLE logs
ALTER COLUMN resource_id TYPE TEXT USING resource_id::TEXT;
39 changes: 29 additions & 10 deletions engine/src/models/item/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ use serde::{Deserialize, Serialize};
use sqlx::{query, query_as};
use tracing::info;

use crate::{database::Database, modules::search::Search, routes::items::{ItemUpdateMediaStatus, ItemUpdatePayload}};
use super::log::LogEntry;
use crate::{
database::Database,
modules::search::Search,
routes::items::{ItemUpdateMediaStatus, ItemUpdatePayload},
};

pub mod field;
pub mod media;
Expand Down Expand Up @@ -57,9 +62,21 @@ impl Item {
}

pub async fn insert(&self, db: &Database) -> Result<Item, sqlx::Error> {
query_as!(Item, "INSERT INTO items (item_id, name, owner_id, location_id, product_id) VALUES ($1, $2, $3, $4, $5) RETURNING *", self.item_id, self.name, self.owner_id, self.location_id, self.product_id)
let item = query_as!(Item, "INSERT INTO items (item_id, name, owner_id, location_id, product_id) VALUES ($1, $2, $3, $4, $5) RETURNING *", self.item_id, self.name, self.owner_id, self.location_id, self.product_id)
.fetch_one(&db.pool)
.await
.await?;

LogEntry::new(
db,
"item",
&item.item_id,
item.owner_id.unwrap_or(1),
"create",
serde_json::to_string(&item).unwrap().as_str(),
)
.await;

Ok(item)
}

pub async fn get_all(db: &Database) -> Result<Vec<Item>, sqlx::Error> {
Expand Down Expand Up @@ -118,10 +135,10 @@ impl Item {
}
}

pub async fn remove_search(&self, search: &Option<Search>, db: &Database) -> Result<Self, ()> {
pub async fn remove_search(&self, search: &Option<Search>, _db: &Database) -> Result<Self, ()> {
match search {
Some(search) => {
search
let _ = search
.client
.index("items")
.delete_document(&self.item_id)
Expand All @@ -146,12 +163,12 @@ impl Item {
pub async fn edit_by_id(
search: &Option<Search>,
db: &Database,
data: ItemUpdatePayload,
data: &ItemUpdatePayload,
item_id: &str,
) -> Result<Item, sqlx::Error> {
let mut tx = db.pool.begin().await?;

if let Some(name) = data.name {
if let Some(name) = &data.name {
query!(
"UPDATE items SET name = $1 WHERE item_id = $2",
name,
Expand Down Expand Up @@ -191,17 +208,19 @@ impl Item {
.await?;
}

if let Some(media) = data.media {
if let Some(media) = &data.media {
for media in media {
match media.status {
ItemUpdateMediaStatus::ExistingMedia => {
// nothing needed here
},
}
ItemUpdateMediaStatus::NewMedia => {
ItemMedia::new(db, item_id, media.media_id).await.unwrap();
}
ItemUpdateMediaStatus::RemovedMedia => {
ItemMedia::delete(db, item_id, media.media_id).await.unwrap();
ItemMedia::delete(db, item_id, media.media_id)
.await
.unwrap();
}
}
}
Expand Down
19 changes: 14 additions & 5 deletions engine/src/models/log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::database::Database;
pub struct LogEntry {
pub log_id: i32,
pub resource_type: String,
pub resource_id: i32,
pub resource_id: String,
pub user_id: i32,
pub action: String,
pub data: String,
Expand All @@ -24,11 +24,11 @@ impl LogEntry {
/// Let postgres generate the id and created_at
pub async fn new(
db: &Database,
resource_type: String,
resource_id: i32,
resource_type: &str,
resource_id: &str,
user_id: i32,
action: String,
data: String,
action: &str,
data: &str,
) -> Result<Self, sqlx::Error> {
let log_entry = query_as!(
LogEntry,
Expand All @@ -47,4 +47,13 @@ impl LogEntry {

Ok(log_entry)
}

/// Find by resource_type and resource_id
pub async fn find_by_resource(db: &Database, resource_type: &str, resource_id: &str) -> Result<Vec<Self>, sqlx::Error> {
let log_entries = query_as!(LogEntry, "SELECT * FROM logs WHERE resource_type = $1 AND resource_id = $2 ORDER BY created_at DESC", resource_type, resource_id)
.fetch_all(&db.pool)
.await?;

Ok(log_entries)
}
}
2 changes: 1 addition & 1 deletion engine/src/modules/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::env;

use aws_config::Region;
use aws_sdk_s3::{
config::Credentials, primitives::ByteStream, types::{BucketCannedAcl, CreateBucketConfiguration}, Client,
config::Credentials, primitives::ByteStream, types::CreateBucketConfiguration, Client,
};
use tracing::info;
use uuid::Uuid;
Expand Down
51 changes: 41 additions & 10 deletions engine/src/routes/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use tracing::info;

use super::ApiTags;
use crate::{
auth::middleware::AuthToken,
models::item::{media::ItemMedia, Item},
models::{
item::{media::ItemMedia, Item},
log::LogEntry,
},
state::AppState,
};
use super::ApiTags;

pub struct ItemsApi;

Expand Down Expand Up @@ -60,7 +63,7 @@ pub struct ItemUpdateMediaPayload {
#[OpenApi]
impl ItemsApi {
/// /item/owned
///
///
/// Get all items owned by the current user
#[oai(path = "/item/owned", method = "get", tag = "ApiTags::Items")]
async fn get_owned_items(
Expand All @@ -79,7 +82,7 @@ impl ItemsApi {
}

/// /item
///
///
/// Create an Item
#[oai(path = "/item", method = "post", tag = "ApiTags::Items")]
async fn create_item(
Expand All @@ -104,7 +107,7 @@ impl ItemsApi {
}

/// /item/next
///
///
/// Suggest next Item Id
#[oai(path = "/item/next", method = "get", tag = "ApiTags::Items")]
async fn next_item_id(&self, state: Data<&Arc<AppState>>) -> Json<ItemIdResponse> {
Expand All @@ -116,7 +119,7 @@ impl ItemsApi {
}

/// /item/:item_id
///
///
/// Delete an Item by `item_id`
#[oai(path = "/item/:item_id", method = "delete", tag = "ApiTags::Items")]
async fn delete_item(
Expand All @@ -136,7 +139,7 @@ impl ItemsApi {
}

/// /item/:item_id
///
///
/// Get an Item by `item_id`
#[oai(path = "/item/:item_id", method = "get", tag = "ApiTags::Items")]
async fn get_item(
Expand All @@ -154,7 +157,7 @@ impl ItemsApi {
}

/// /item/:item_id
///
///
/// Edit an Item by `item_id`
/// This updates the `name`, `owner_id`, `location_id`, `product_id`, and `media` (linking `"new-media"`, and removing `"removed-media"`)
#[oai(path = "/item/:item_id", method = "patch", tag = "ApiTags::Items")]
Expand All @@ -165,12 +168,23 @@ impl ItemsApi {
item_id: Path<String>,
data: Json<ItemUpdatePayload>,
) -> Result<()> {
Item::edit_by_id(&state.search, &state.database, data.0, &item_id.0).await;
let _ = Item::edit_by_id(&state.search, &state.database, &data.0, &item_id.0).await;

let _ = LogEntry::new(
&state.database,
"item",
&item_id.0,
auth.ok().unwrap().session.user_id,
"edit",
&serde_json::to_string(&data.0).unwrap(),
)
.await;

Ok(())
}

/// /item/:item_id/media
///
///
/// Get all media for an Item by `item_id`
#[oai(path = "/item/:item_id/media", method = "get", tag = "ApiTags::Items")]
async fn get_item_media(
Expand All @@ -185,4 +199,21 @@ impl ItemsApi {

Ok(Json(media.iter().map(|m| m.media_id).collect()))
}

/// /item/:item_id/logs
///
/// Get all logs for an Item by `item_id`
#[oai(path = "/item/:item_id/logs", method = "get", tag = "ApiTags::Items")]
async fn get_item_logs(
&self,
state: Data<&Arc<AppState>>,
auth: AuthToken,
item_id: Path<String>,
) -> Result<Json<Vec<LogEntry>>> {
Ok(Json(
LogEntry::find_by_resource(&state.database, "item", &item_id.0)
.await
.unwrap(),
))
}
}
16 changes: 16 additions & 0 deletions web/src/api/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ export const getApiItemMedia = (
}),
});

export type ApiLogResponse =
paths['/item/{item_id}/logs']['get']['responses']['200']['content']['application/json; charset=utf-8'];

export const getApiItemLogs = (
item_id: string
): UseQueryOptions<ApiLogResponse> => ({
queryKey: ['item', item_id, 'logs'],
queryFn: getHttp('/api/item/' + item_id + '/logs', {
auth: 'include',
}),
});

export const useApiItemLogs = (item_id: string) => {
return useQuery(getApiItemLogs(item_id));
};

export const useApiItemMedia = (item_id: string) => {
return useQuery(getApiItemMedia(item_id));
};
Expand Down
Loading

0 comments on commit 27cef96

Please sign in to comment.