chore: update dependencies and improve MermaidBlock security

- Updated mermaid from version 11.13.0 to 9.1.7 for compatibility.
- Upgraded next from version 14.2.21 to ^14.2.35 for the latest features and fixes.
- Added @types/dompurify and isomorphic-dompurify for improved sanitization.
- Replaced innerHTML assignment in MermaidBlock with sanitized SVG using DOMPurify.
- Updated eslint-config-next to ^16.2.4 for better linting support.
This commit is contained in:
2026-04-28 15:15:16 -04:00
parent 567fa66428
commit 2c8bfaa20e
39 changed files with 3701 additions and 2866 deletions
+44 -36
View File
@@ -28,6 +28,7 @@ use serde_json::json;
use sqlx::PgPool;
use base64::{engine::general_purpose, Engine as _};
use std::env;
use regex;
use reqwest::header::HeaderMap;
use uuid::Uuid;
@@ -605,7 +606,7 @@ pub async fn update_course(
let mut tx = pool
.begin()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// Establecer contexto de auditoría
sqlx::query(
@@ -615,7 +616,7 @@ pub async fn update_course(
.bind(org_ctx.id.to_string())
.execute(&mut *tx)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let course = sqlx::query_as::<_, Course>(
"SELECT * FROM fn_update_course($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
@@ -644,7 +645,7 @@ pub async fn update_course(
tx.commit()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(course))
}
@@ -1755,7 +1756,7 @@ pub async fn get_grading_categories(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(categories))
}
@@ -1778,7 +1779,7 @@ pub async fn create_grading_category(
.bind(payload.tipo_nota_id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(category))
}
@@ -1815,7 +1816,7 @@ pub async fn delete_grading_category(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(StatusCode::OK)
}
@@ -2789,6 +2790,13 @@ pub async fn register(
if payload.password.len() < 8 {
return Err((StatusCode::BAD_REQUEST, "La contraseña debe tener al menos 8 caracteres".into()));
}
// Validar formato de email (validación básica)
let email_regex = regex::Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Email validation error".into()))?;
if !email_regex.is_match(&payload.email) {
return Err((StatusCode::BAD_REQUEST, "Formato de email inválido".into()));
}
let password_hash = hash(payload.password, 13)
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Hashing failed".into()))?;
@@ -2809,7 +2817,7 @@ pub async fn register(
let mut tx = pool
.begin()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let user = sqlx::query_as::<_, User>("SELECT * FROM fn_register_user($1, $2, $3, $4, $5)")
.bind(&payload.email)
@@ -2829,7 +2837,7 @@ pub async fn register(
tx.commit()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let token = create_jwt(user.id, user.organization_id, &user.role).map_err(|_| {
(
@@ -3041,7 +3049,7 @@ pub async fn get_course_analytics(
let analytics = res
.json::<CourseAnalytics>()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(analytics))
}
@@ -3089,7 +3097,7 @@ pub async fn get_advanced_analytics(
let analytics = res
.json::<common::models::AdvancedAnalytics>()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(analytics))
}
@@ -3120,7 +3128,7 @@ pub async fn get_lesson_heatmap(
let heatmap = res
.json::<Vec<common::models::HeatmapPoint>>()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(heatmap))
}
@@ -3164,7 +3172,7 @@ pub async fn get_audit_logs(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(logs))
}
@@ -3239,7 +3247,7 @@ pub async fn get_sso_config(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(config))
}
@@ -3298,7 +3306,7 @@ pub async fn update_sso_config(
// We use fetch_all + next for slightly better error handling in this complex query
let config = config
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.into_iter()
.next()
.ok_or((
@@ -3319,7 +3327,7 @@ pub async fn sso_login_init(
.bind(org_id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((
StatusCode::NOT_FOUND,
"SSO no configurado o deshabilitado para esta organización".to_string(),
@@ -3351,7 +3359,7 @@ pub async fn sso_login_init(
"{}/auth/sso/callback",
env::var("CMS_API_URL").unwrap_or_else(|_| "http://localhost:3001".to_string())
))
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?,
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?,
);
let (auth_url, csrf_token, nonce) = client
@@ -3372,7 +3380,7 @@ pub async fn sso_login_init(
.bind(nonce.secret())
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(axum::response::Redirect::to(auth_url.as_str()))
}
@@ -3405,7 +3413,7 @@ pub async fn sso_callback(
.bind(org_id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// 3. Exchange code for token
let issuer_url = IssuerUrl::new(config.issuer_url.clone())
@@ -3413,7 +3421,7 @@ pub async fn sso_callback(
let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, async_http_client)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let client = CoreClient::from_provider_metadata(
provider_metadata,
@@ -3425,7 +3433,7 @@ pub async fn sso_callback(
"{}/auth/sso/callback",
env::var("CMS_API_URL").unwrap_or_else(|_| "http://localhost:3001".to_string())
))
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?,
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?,
);
let token_response = client
@@ -3464,7 +3472,7 @@ pub async fn sso_callback(
let mut tx = pool
.begin()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let user = sqlx::query_as::<_, User>(
"SELECT * FROM users WHERE organization_id = $1 AND lower(email) = lower($2)",
@@ -3473,7 +3481,7 @@ pub async fn sso_callback(
.bind(&email)
.fetch_optional(&mut *tx)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let user = match user {
Some(u) => u,
@@ -3491,13 +3499,13 @@ pub async fn sso_callback(
.bind("student") // Default role
.fetch_one(&mut *tx)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
}
};
tx.commit()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// 6. Generate JWT
let token =
@@ -3849,7 +3857,7 @@ pub async fn update_user(
.fetch_one(&pool)
.await
}
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
log_action(
&pool,
@@ -3905,7 +3913,7 @@ pub async fn delete_user(
.execute(&pool)
.await
}
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "User not found".into()));
@@ -3951,7 +3959,7 @@ pub async fn get_webhooks(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(webhooks))
}
@@ -3979,7 +3987,7 @@ pub async fn create_webhook(
.bind(payload.secret)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
log_action(
&pool,
@@ -4010,7 +4018,7 @@ pub async fn delete_webhook(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Webhook not found".into()));
@@ -4062,7 +4070,7 @@ pub async fn export_course(
.await
.map_err(|e| {
tracing::error!("Export failed: {}", e);
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
(StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())
})?;
let filename = format!("course-{}.ccb", id);
@@ -4567,7 +4575,7 @@ pub async fn check_course_access(
.bind(user_id)
.fetch_one(pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(exists)
}
@@ -4604,7 +4612,7 @@ pub async fn get_course_team(
.bind(course_id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(team))
}
@@ -4633,7 +4641,7 @@ pub async fn add_team_member(
.bind(claims.sub)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
};
if !is_authorized {
@@ -4678,7 +4686,7 @@ pub async fn remove_team_member(
.bind(claims.sub)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
};
if !is_authorized && claims.sub != user_id {
@@ -4690,7 +4698,7 @@ pub async fn remove_team_member(
.bind(user_id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(StatusCode::NO_CONTENT)
}
@@ -4707,7 +4715,7 @@ pub async fn create_course_preview_token(
}
let token = create_preview_token(claims.sub, claims.org, id)
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(json!({ "token": token })))
}
+6 -6
View File
@@ -109,7 +109,7 @@ pub async fn retry_task(
.bind(id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if let Some(l) = lesson {
let pool_clone = pool.clone();
@@ -134,7 +134,7 @@ pub async fn retry_task(
.bind(id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if let Some(task) = zip_task {
let zip_batch_id_from_metadata = task
@@ -176,7 +176,7 @@ pub async fn retry_task(
.bind(task.created_at)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if candidates.len() == 1 {
candidates[0].zip_batch_id
@@ -200,7 +200,7 @@ pub async fn retry_task(
.bind(zip_batch_id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if assets.is_empty() {
return Err((
@@ -306,7 +306,7 @@ pub async fn cancel_task(
.bind(id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if lesson_result.rows_affected() > 0 {
return Ok(StatusCode::NO_CONTENT);
@@ -327,7 +327,7 @@ pub async fn cancel_task(
.bind(id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if task_result.rows_affected() > 0 {
return Ok(StatusCode::NO_CONTENT);
+12 -12
View File
@@ -408,7 +408,7 @@ pub async fn upload_asset(
data = field
.bytes()
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.to_vec();
} else if name == "course_id" {
if let Ok(txt) = field.text().await {
@@ -447,7 +447,7 @@ pub async fn upload_asset(
// Asegurar que el directorio de subidas existe
tokio::fs::create_dir_all("uploads")
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let (storage_filename, storage_path, stored_filename, stored_mimetype) =
if is_flv_media(&filename, &mimetype) {
@@ -455,7 +455,7 @@ pub async fn upload_asset(
let temp_storage_path = format!("uploads/{}", temp_storage_filename);
tokio::fs::write(&temp_storage_path, data)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let final_storage_filename = format!("{}.mp4", asset_id);
let final_storage_path = format!("uploads/{}", final_storage_filename);
@@ -483,7 +483,7 @@ pub async fn upload_asset(
tokio::fs::write(&storage_path, data)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
(storage_filename, storage_path, filename.clone(), mimetype.clone())
};
@@ -528,7 +528,7 @@ pub async fn upload_asset(
.bind(size_bytes)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(AssetUploadResponse {
id: asset_id,
@@ -614,7 +614,7 @@ pub async fn list_assets(
.bind(offset)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(assets))
}
@@ -645,7 +645,7 @@ pub async fn list_asset_import_history(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(items))
}
@@ -664,7 +664,7 @@ pub async fn delete_asset(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Activo no encontrado".to_string()))?;
// 2. Eliminar de la base de datos
@@ -672,7 +672,7 @@ pub async fn delete_asset(
.bind(id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// 3. Eliminar archivo físico u objeto de S3
let _ = delete_storage_path(&asset.storage_path).await;
@@ -790,7 +790,7 @@ pub async fn ingest_asset_for_rag(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let source_kind = if asset.mimetype.starts_with("audio/") || asset.mimetype.starts_with("video/") {
"audio-transcription"
@@ -1435,7 +1435,7 @@ pub async fn import_assets_zip(
tokio::fs::create_dir_all("uploads")
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// ── Phase 2: process entries ───────────────────────────────────────────────
let mut imported_assets = 0usize;
@@ -1591,7 +1591,7 @@ pub async fn import_assets_zip(
let temp_storage_path = format!("uploads/{}", temp_storage_filename);
tokio::fs::write(&temp_storage_path, &content)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let final_storage_filename = format!("{}.mp4", asset_id);
let final_storage_path = format!("uploads/{}", final_storage_filename);
@@ -74,7 +74,7 @@ pub async fn generate_question_embeddings(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let _total = questions.len();
let mut processed = 0;
@@ -181,7 +181,7 @@ pub async fn regenerate_question_embedding(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Pregunta no encontrada".to_string()))?;
// Generar texto de la incrustación
@@ -226,7 +226,7 @@ pub async fn regenerate_question_embedding(
.bind(question_id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(StatusCode::OK)
}
@@ -310,7 +310,7 @@ pub async fn semantic_search(
let results = sql_query
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(results))
}
@@ -348,7 +348,7 @@ pub async fn find_similar_questions(
.bind(limit)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.into_iter()
.filter(|r| r.similarity >= threshold)
.collect();
+8 -8
View File
@@ -40,7 +40,7 @@ pub async fn create_library_block(
.bind(payload.tags.as_deref())
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(block))
}
@@ -98,7 +98,7 @@ pub async fn list_library_blocks(
let blocks = sql_query
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(blocks))
}
@@ -116,7 +116,7 @@ pub async fn get_library_block(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
match block {
Some(b) => Ok(Json(b)),
@@ -137,7 +137,7 @@ pub async fn update_library_block(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if existing.is_none() {
return Err((StatusCode::NOT_FOUND, "Bloque no encontrado".to_string()));
@@ -163,7 +163,7 @@ pub async fn update_library_block(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
} else {
sqlx::query_as(
r#"
@@ -181,7 +181,7 @@ pub async fn update_library_block(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
};
Ok(Json(updated))
@@ -198,7 +198,7 @@ pub async fn delete_library_block(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Bloque no encontrado".to_string()));
@@ -218,7 +218,7 @@ pub async fn increment_block_usage(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Bloque no encontrado".to_string()));
+6 -6
View File
@@ -63,7 +63,7 @@ pub async fn list_plugins(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let plugins = rows
.into_iter()
@@ -101,7 +101,7 @@ pub async fn list_enabled_plugins(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
let plugins = rows
.into_iter()
@@ -155,7 +155,7 @@ pub async fn create_plugin(
.bind(payload.config.unwrap_or(serde_json::json!({})))
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok((StatusCode::CREATED, Json(OrgPlugin {
id: row.get("id"),
@@ -190,7 +190,7 @@ pub async fn update_plugin(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if !exists {
return Err((StatusCode::NOT_FOUND, "Plugin no encontrado".to_string()));
@@ -229,7 +229,7 @@ pub async fn update_plugin(
.bind(payload.enabled)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(OrgPlugin {
id: row.get("id"),
@@ -262,7 +262,7 @@ pub async fn delete_plugin(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Plugin no encontrado".to_string()));
@@ -379,7 +379,7 @@ pub async fn create_question(
.bind(media_type.as_deref())
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(question))
}
@@ -501,7 +501,7 @@ pub async fn list_questions(
.fetch_all(&pool)
.await
}
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(questions))
}
@@ -531,7 +531,7 @@ pub async fn get_question(
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Pregunta no encontrada".to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()),
})?;
Ok(Json(question))
@@ -602,7 +602,7 @@ pub async fn update_question(
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Pregunta no encontrada".to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()),
})?;
Ok(Json(question))
@@ -627,7 +627,7 @@ pub async fn delete_question(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Pregunta no encontrada".to_string()));
+22 -22
View File
@@ -121,7 +121,7 @@ pub async fn create_rubric(
.bind(&payload.description)
.fetch_one(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(rubric))
}
@@ -144,7 +144,7 @@ pub async fn list_course_rubrics(
.bind(course_id)
.fetch_all(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(rubrics))
}
@@ -167,7 +167,7 @@ pub async fn get_rubric_with_details(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rúbrica no encontrada".to_string()))?;
// Get criteria
@@ -182,7 +182,7 @@ pub async fn get_rubric_with_details(
.bind(rubric_id)
.fetch_all(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// Get levels for each criterion
let mut criteria_with_levels = Vec::new();
@@ -198,7 +198,7 @@ pub async fn get_rubric_with_details(
.bind(criterion.id)
.fetch_all(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
criteria_with_levels.push(CriterionWithLevels { criterion, levels });
}
@@ -232,7 +232,7 @@ pub async fn update_rubric(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rúbrica no encontrada".to_string()))?;
Ok(Json(rubric))
@@ -249,7 +249,7 @@ pub async fn delete_rubric(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Rúbrica no encontrada".to_string()));
@@ -273,7 +273,7 @@ pub async fn create_criterion(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rúbrica no encontrada".to_string()))?;
let position = payload.position.unwrap_or(0);
@@ -292,7 +292,7 @@ pub async fn create_criterion(
.bind(position)
.fetch_one(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// Update rubric total_points
let _= sqlx::query(
@@ -306,7 +306,7 @@ pub async fn create_criterion(
.bind(rubric_id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(criterion))
}
@@ -338,7 +338,7 @@ pub async fn update_criterion(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterio no encontrado".to_string()))?;
// Update rubric total_points if max_points changed
@@ -354,7 +354,7 @@ pub async fn update_criterion(
.bind(criterion.rubric_id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
}
Ok(Json(criterion))
@@ -371,7 +371,7 @@ pub async fn delete_criterion(
.bind(criterion_id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterio no encontrado".to_string()))?;
let rubric_id: Uuid = criterion_row.get("rubric_id");
@@ -387,7 +387,7 @@ pub async fn delete_criterion(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Criterio no encontrado".to_string()));
@@ -405,7 +405,7 @@ pub async fn delete_criterion(
.bind(rubric_id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(StatusCode::NO_CONTENT)
}
@@ -425,7 +425,7 @@ pub async fn create_level(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterio no encontrado".to_string()))?;
let position = payload.position.unwrap_or(0);
@@ -444,7 +444,7 @@ pub async fn create_level(
.bind(position)
.fetch_one(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(level))
}
@@ -479,7 +479,7 @@ pub async fn update_level(
.bind(org_ctx.id)
.fetch_optional(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Nivel no encontrado".to_string()))?;
Ok(Json(level))
@@ -505,7 +505,7 @@ pub async fn delete_level(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Nivel no encontrado".to_string()));
@@ -534,7 +534,7 @@ pub async fn assign_rubric_to_lesson(
.bind(rubric_id)
.fetch_one(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(lesson_rubric))
}
@@ -550,7 +550,7 @@ pub async fn unassign_rubric_from_lesson(
.bind(rubric_id)
.execute(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Vínculo lección-rúbrica no encontrado".to_string()));
@@ -578,7 +578,7 @@ pub async fn get_lesson_rubrics(
.bind(org_ctx.id)
.fetch_all(&pool)
.await
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(rubrics))
}
+2 -2
View File
@@ -109,7 +109,7 @@ pub async fn sync_sam_students(
.await
.map_err(|e| {
errors.push(format!("Error al comprobar el usuario {}: {}", sam_student.email, e));
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
(StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())
})
.ok()
.flatten();
@@ -422,7 +422,7 @@ pub async fn sync_all_sam(
.await
.map_err(|e| {
errors.push(format!("Error al comprobar el usuario {}: {}", sam_student.email, e));
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
(StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())
})
.ok()
.flatten();
@@ -108,7 +108,7 @@ pub async fn create_test_template(
.bind(payload.tags.as_deref())
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(template))
}
@@ -198,7 +198,7 @@ pub async fn list_test_templates(
let templates = sql_query
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(templates))
}
@@ -225,7 +225,7 @@ pub async fn get_test_template(
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()),
})?;
// Obtener secciones
@@ -240,7 +240,7 @@ pub async fn get_test_template(
.bind(template_id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// Obtener preguntas
let questions: Vec<TestTemplateQuestion> = sqlx::query_as(
@@ -255,7 +255,7 @@ pub async fn get_test_template(
.bind(template_id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(TestTemplateWithQuestions {
template,
@@ -317,7 +317,7 @@ pub async fn update_test_template(
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()),
})?;
Ok(Json(template))
@@ -341,7 +341,7 @@ pub async fn delete_test_template(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()));
@@ -367,7 +367,7 @@ pub async fn create_template_question(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if !exists.0 {
return Err((StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()));
@@ -396,7 +396,7 @@ pub async fn create_template_question(
.bind(payload.metadata.as_ref())
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(question))
}
@@ -428,7 +428,7 @@ pub async fn delete_template_question(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if !exists.0 {
return Err((StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()));
@@ -444,7 +444,7 @@ pub async fn delete_template_question(
.bind(template_id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Pregunta no encontrada".to_string()));
@@ -470,7 +470,7 @@ pub async fn create_template_section(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if !exists.0 {
return Err((StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()));
@@ -494,7 +494,7 @@ pub async fn create_template_section(
.bind(payload.section_data.as_ref())
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
Ok(Json(section))
}
@@ -525,7 +525,7 @@ pub async fn delete_template_section(
.bind(template_id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Sección no encontrada".to_string()));
@@ -560,7 +560,7 @@ pub async fn apply_template_to_lesson(
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Plantilla no encontrada".to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()),
})?;
// Verificar que la lección existe y pertenece a la organización
@@ -571,7 +571,7 @@ pub async fn apply_template_to_lesson(
.bind(org_ctx.id)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if !lesson_exists.0 {
return Err((StatusCode::NOT_FOUND, "Lección no encontrada".to_string()));
@@ -590,7 +590,7 @@ pub async fn apply_template_to_lesson(
.bind(template_id)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
if template_questions.is_empty() {
return Err((StatusCode::BAD_REQUEST, "La plantilla no tiene preguntas".to_string()));
@@ -647,14 +647,14 @@ pub async fn apply_template_to_lesson(
.bind(org_ctx.id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
// Incrementar el contador de uso de la plantilla
sqlx::query("SELECT increment_template_usage($1)")
.bind(template_id)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?;
tracing::info!(
"Plantilla '{}' aplicada a la lección '{}' con {} preguntas",