feat: Implement video play count tracking, refactor user update API, add missing CMS delete functions, and update database transaction handling.

This commit is contained in:
2026-01-16 13:43:58 -03:00
parent 2dffbd8b71
commit 42976236b3
11 changed files with 138 additions and 39 deletions
@@ -0,0 +1,32 @@
-- Migration: Add missing delete functions
-- Adds fn_delete_module and fn_delete_lesson which were missing from the CRUD migration
CREATE OR REPLACE FUNCTION fn_delete_module(
p_id UUID,
p_organization_id UUID
) RETURNS BOOLEAN AS $$
DECLARE
v_deleted_count INTEGER;
BEGIN
DELETE FROM modules
WHERE id = p_id AND organization_id = p_organization_id;
GET DIAGNOSTICS v_deleted_count = ROW_COUNT;
RETURN v_deleted_count > 0;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION fn_delete_lesson(
p_id UUID,
p_organization_id UUID
) RETURNS BOOLEAN AS $$
DECLARE
v_deleted_count INTEGER;
BEGIN
DELETE FROM lessons
WHERE id = p_id AND organization_id = p_organization_id;
GET DIAGNOSTICS v_deleted_count = ROW_COUNT;
RETURN v_deleted_count > 0;
END;
$$ LANGUAGE plpgsql;
+7 -7
View File
@@ -1,8 +1,8 @@
use sqlx::{Postgres, Transaction};
use sqlx::{Postgres, PgConnection};
use uuid::Uuid;
pub async fn set_session_context(
tx: &mut Transaction<'_, Postgres>,
conn: &mut PgConnection,
user_id: Option<Uuid>,
org_id: Option<Uuid>,
ip_address: Option<String>,
@@ -12,31 +12,31 @@ pub async fn set_session_context(
if let Some(uid) = user_id {
let _ = sqlx::query("SELECT set_config('app.current_user_id', $1, true)")
.bind(uid.to_string())
.execute(&mut **tx)
.execute(&mut *conn)
.await?;
}
if let Some(oid) = org_id {
let _ = sqlx::query("SELECT set_config('app.current_org_id', $1, true)")
.bind(oid.to_string())
.execute(&mut **tx)
.execute(&mut *conn)
.await?;
}
if let Some(ip) = ip_address {
let _ = sqlx::query("SELECT set_config('app.client_ip', $1, true)")
.bind(ip)
.execute(&mut **tx)
.execute(&mut *conn)
.await?;
}
if let Some(ua) = user_agent {
let _ = sqlx::query("SELECT set_config('app.user_agent', $1, true)")
.bind(ua)
.execute(&mut **tx)
.execute(&mut *conn)
.await?;
}
if let Some(et) = event_type {
let _ = sqlx::query("SELECT set_config('app.event_type', $1, true)")
.bind(et)
.execute(&mut **tx)
.execute(&mut *conn)
.await?;
}
Ok(())
+15 -23
View File
@@ -199,7 +199,7 @@ pub async fn create_course(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(instructor_id),
Some(org_ctx.id),
ip,
@@ -400,7 +400,7 @@ pub async fn create_module(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -498,7 +498,7 @@ pub async fn create_lesson(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1008,7 +1008,7 @@ pub async fn update_lesson(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1231,7 +1231,7 @@ pub async fn reorder_modules(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1282,7 +1282,7 @@ pub async fn reorder_lessons(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1759,7 +1759,7 @@ pub async fn update_module(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut *tx,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1801,8 +1801,8 @@ pub async fn delete_module(
headers: axum::http::HeaderMap,
Path(id): Path<Uuid>,
) -> Result<StatusCode, StatusCode> {
let mut tx = pool
.begin()
let mut conn = pool
.acquire()
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
@@ -1818,7 +1818,7 @@ pub async fn delete_module(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut conn,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1831,7 +1831,7 @@ pub async fn delete_module(
let success = sqlx::query_scalar::<_, bool>("SELECT fn_delete_module($1, $2)")
.bind(id)
.bind(org_ctx.id)
.fetch_one(&mut *tx)
.fetch_one(&mut *conn)
.await
.map_err(|e| {
tracing::error!("Delete module failed: {}", e);
@@ -1842,10 +1842,6 @@ pub async fn delete_module(
return Err(StatusCode::NOT_FOUND);
}
tx.commit()
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(StatusCode::OK)
}
@@ -1860,8 +1856,8 @@ pub async fn delete_lesson(
return Err(StatusCode::FORBIDDEN);
}
let mut tx = pool
.begin()
let mut conn = pool
.acquire()
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
@@ -1877,7 +1873,7 @@ pub async fn delete_lesson(
.map(|s| s.to_string());
crate::db_util::set_session_context(
&mut tx,
&mut conn,
Some(claims.sub),
Some(org_ctx.id),
ip,
@@ -1890,7 +1886,7 @@ pub async fn delete_lesson(
let success = sqlx::query_scalar::<_, bool>("SELECT fn_delete_lesson($1, $2)")
.bind(id)
.bind(org_ctx.id)
.fetch_one(&mut *tx)
.fetch_one(&mut *conn)
.await
.map_err(|e| {
tracing::error!("Delete lesson failed: {}", e);
@@ -1901,10 +1897,6 @@ pub async fn delete_lesson(
return Err(StatusCode::NOT_FOUND);
}
tx.commit()
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(StatusCode::OK)
}