From 42620cc9acd4d6f5e549e740d15a04f4fb0adf9c Mon Sep 17 00:00:00 2001 From: Nurfog Date: Tue, 28 Apr 2026 15:47:20 -0400 Subject: [PATCH] Add SECURITY_TRIAGE.md for vulnerability assessment and remediation plan - Document current state of vulnerabilities in Rust and frontend dependencies - Outline active vulnerabilities and their remediation status - Include notes on resolved issues and remaining bugs - Define a remediation plan with prioritized actions --- Cargo.lock | 245 ++-- Cargo.toml | 2 +- docs/SECURITY_TRIAGE.md | 86 ++ services/cms-service/src/handlers.rs | 84 +- services/cms-service/src/handlers/tasks.rs | 12 +- services/cms-service/src/handlers_admin.rs | 32 +- services/cms-service/src/handlers_assets.rs | 74 +- .../cms-service/src/handlers_embeddings.rs | 20 +- services/cms-service/src/handlers_library.rs | 16 +- services/cms-service/src/handlers_plugins.rs | 12 +- .../cms-service/src/handlers_question_bank.rs | 58 +- services/cms-service/src/handlers_rubrics.rs | 44 +- services/cms-service/src/handlers_sam.rs | 18 +- .../src/handlers_test_templates.rs | 46 +- services/lms-service/src/handlers.rs | 106 +- services/lms-service/src/handlers_ai_audit.rs | 8 +- .../lms-service/src/handlers_announcements.rs | 22 +- services/lms-service/src/handlers_cohorts.rs | 16 +- .../lms-service/src/handlers_discussions.rs | 22 +- services/lms-service/src/handlers_email.rs | 12 +- .../lms-service/src/handlers_embeddings.rs | 18 +- services/lms-service/src/handlers_faq.rs | 22 +- .../lms-service/src/handlers_lti_consumer.rs | 24 +- services/lms-service/src/handlers_notes.rs | 4 +- services/lms-service/src/handlers_payments.rs | 4 +- .../lms-service/src/handlers_pedagogical.rs | 10 +- .../lms-service/src/handlers_peer_review.rs | 52 +- services/lms-service/src/handlers_scorm.rs | 2 +- services/lms-service/src/handlers_search.rs | 4 +- .../lms-service/src/handlers_study_rooms.rs | 16 +- services/lms-service/src/live.rs | 6 +- services/lms-service/src/lti.rs | 22 +- services/lms-service/src/portfolio.rs | 10 +- services/lms-service/src/predictive.rs | 4 +- web/experience/package-lock.json | 1087 ++++++++++------ web/experience/package.json | 2 +- .../courses/[id]/lessons/[lessonId]/page.tsx | 1 + .../components/blocks/PeerReviewPlayer.tsx | 259 ---- web/studio/package-lock.json | 1147 +++++++++++------ web/studio/package.json | 2 +- .../app/courses/[id]/peer-reviews/page.tsx | 268 ---- web/studio/tsconfig.tsbuildinfo | 2 +- 42 files changed, 2032 insertions(+), 1869 deletions(-) create mode 100644 docs/SECURITY_TRIAGE.md diff --git a/Cargo.lock b/Cargo.lock index 9119f42..d6332d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,7 +578,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower", "tower-layer", @@ -599,7 +599,7 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -628,12 +628,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -675,12 +669,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -775,6 +763,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.42" @@ -829,7 +823,7 @@ dependencies = [ "openidconnect", "rand 0.8.5", "regex", - "reqwest 0.12.26", + "reqwest", "serde", "serde_json", "sha2", @@ -856,7 +850,7 @@ dependencies = [ "hmac", "jsonwebtoken", "openidconnect", - "reqwest 0.12.26", + "reqwest", "serde", "serde_json", "sha2", @@ -1856,6 +1850,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.4", "tower-service", + "webpki-roots 1.0.4", ] [[package]] @@ -1893,7 +1888,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.1", - "system-configuration 0.6.1", + "system-configuration", "tokio", "tower-service", "tracing", @@ -2183,7 +2178,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" dependencies = [ - "bitflags 2.10.0", + "bitflags", "libc", "redox_syscall 0.6.0", ] @@ -2230,7 +2225,7 @@ dependencies = [ "mime_guess", "rand 0.8.5", "regex", - "reqwest 0.12.26", + "reqwest", "serde", "serde_json", "sha2", @@ -2271,6 +2266,12 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchers" version = "0.2.0" @@ -2473,16 +2474,16 @@ dependencies = [ [[package]] name = "oauth2" -version = "4.4.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "chrono", "getrandom 0.2.17", - "http 0.2.12", + "http 1.4.0", "rand 0.8.5", - "reqwest 0.11.27", + "reqwest", "serde", "serde_json", "serde_path_to_error", @@ -2499,16 +2500,16 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "openidconnect" -version = "3.5.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47e80a9cfae4462dd29c41e987edd228971d6565553fbc14b8a11e666d91590" +checksum = "0d8c6709ba2ea764bbed26bce1adf3c10517113ddea6f2d4196e4851757ef2b2" dependencies = [ - "base64 0.13.1", + "base64 0.21.7", "chrono", "dyn-clone", "ed25519-dalek", "hmac", - "http 0.2.12", + "http 1.4.0", "itertools", "log", "oauth2", @@ -2518,7 +2519,6 @@ dependencies = [ "rsa", "serde", "serde-value", - "serde_derive", "serde_json", "serde_path_to_error", "serde_plain", @@ -2535,7 +2535,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -2838,6 +2838,61 @@ dependencies = [ "winapi", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.35", + "socket2 0.6.1", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls 0.23.35", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.1", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.45" @@ -2924,7 +2979,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -2933,7 +2988,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -2942,7 +2997,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -3000,47 +3055,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration 0.5.1", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - [[package]] name = "reqwest" version = "0.12.26" @@ -3067,13 +3081,16 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.35", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.4", "tower", "tower-http", "tower-service", @@ -3081,6 +3098,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 1.0.4", ] [[package]] @@ -3138,6 +3156,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustc_version" version = "0.4.1" @@ -3153,7 +3177,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -3199,21 +3223,13 @@ dependencies = [ "security-framework 3.5.1", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pki-types" version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ + "web-time", "zeroize", ] @@ -3334,7 +3350,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -3347,7 +3363,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3740,7 +3756,7 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.10.0", + "bitflags", "byteorder", "bytes", "chrono", @@ -3784,7 +3800,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.10.0", + "bitflags", "byteorder", "chrono", "crc", @@ -3881,12 +3897,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3907,36 +3917,15 @@ dependencies = [ "syn", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "system-configuration-sys 0.5.0", -] - [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.9.4", - "system-configuration-sys 0.6.0", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", + "system-configuration-sys", ] [[package]] @@ -4158,7 +4147,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -4171,7 +4160,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-core", "futures-util", @@ -4527,12 +4516,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.11" @@ -4875,16 +4858,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-bindgen" version = "0.57.1" diff --git a/Cargo.toml b/Cargo.toml index bf6e3cd..59ad04f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ reqwest = { version = "0.12", features = ["json", "multipart"] } hmac = "0.12" sha2 = "0.10" hex = "0.4" -openidconnect = { version = "3.5", features = ["reqwest"] } +openidconnect = { version = "4", features = ["reqwest"] } anyhow = "1.0" utoipa = { version = "5", features = ["axum_extras", "chrono", "uuid"] } thiserror = "2.0" diff --git a/docs/SECURITY_TRIAGE.md b/docs/SECURITY_TRIAGE.md new file mode 100644 index 0000000..f299239 --- /dev/null +++ b/docs/SECURITY_TRIAGE.md @@ -0,0 +1,86 @@ +# Security Triage + +Fecha de última actualización: 2026-04-28 + +--- + +## Estado actual (post-remediación) + +### Rust (cargo audit) +- Vulnerabilidades: 4 (todas en dependencias transitivas de terceros sin fix directo) +- Warnings: 4 + +#### Vulnerabilidades activas + +1. RUSTSEC-2023-0071 (rsa 0.9.9) + - Severidad: media (Marvin Attack) + - Cadena: sqlx-mysql → rsa + - Fix upstream: no disponible + - Estado: aceptación de riesgo temporal + +2. RUSTSEC-2026-0098 (rustls-webpki 0.101.7) + - Nombre: URI name constraints incorrectly accepted + - Cadena: aws-sdk-s3/aws-config → aws-smithy-http-client → rustls 0.21 → rustls-webpki 0.101.7 + - Fix: requiere AWS SDK 1.x actualice su stack TLS a rustls >=0.22 + - Estado: bloqueado por tercero (AWS SDK) + +3. RUSTSEC-2026-0099 (rustls-webpki 0.101.7) + - Nombre: wildcard name constraints incorrectly accepted + - Misma cadena que 0098 + +4. RUSTSEC-2026-0104 (rustls-webpki 0.101.7) + - Nombre: panic alcanzable en CRL parsing + - Misma cadena que 0098 + +#### Nota: openidconnect ya NO es un vector +- Se actualizó openidconnect de 3.5 → 4.x +- openidconnect 4.x usa reqwest 0.12 + rustls-webpki 0.103.13 (parcheado) ✓ +- Código de handlers SSO actualizado para nueva API (reqwest::Client en lugar de async_http_client) + +--- + +### Frontend (npm audit --omit=dev) + +#### Studio +- Pre-remediación: 1 critical, 12 high, 1 moderate (total 14) +- Post-remediación: 0 critical, 2 high, 3 moderate (total 5) +- Resuelto: dompurify critical + toda la cadena d3/mermaid/dagre-d3 (via upgrade mermaid 9 → 11.14.0) +- Restante high: xlsx (2 advisories, sin fix disponible) +- Restante moderate: next + postcss (requieren Next major upgrade) + +#### Experience +- Pre-remediación: 1 critical, 11 high, 1 moderate (total 13) +- Post-remediación: 0 critical, 1 high, 3 moderate (total 4) +- Resuelto: dompurify critical + toda la cadena d3/mermaid/dagre-d3 ✓ +- Restante high: next (requiere Next major upgrade) +- Restante moderate: next postcss + uuid (moderate, via mermaid 11; revertir a mermaid 9 empeoraría) + +--- + +## Bugs corregidos (colaterales al triage) + +- Studio: función PeerReviewDashboard duplicada en peer-reviews/page.tsx (compilación OK) +- Experience: PeerReviewPlayer duplicada en blocks/PeerReviewPlayer.tsx (compilación OK) +- Experience: try sin catch en handleBlockComplete de lessons/[lessonId]/page.tsx +- Backend: variable err_body no usada en handlers LMS (warning eliminado) + +--- + +## Plan de remediación restante + +### P1 (pendiente - bloqueado por terceros) +- rustls-webpki via AWS SDK: monitorear release del AWS SDK que actualice a rustls 0.22+ + - Validar con: cargo update && cargo audit + - ETA: depende de AWS SDK Rust team + +### P2 (decisión de producto) +- xlsx en studio: sin fix disponible en npm + - Opción A: encapsular parseo de Excel en backend y eliminar xlsx del frontend + - Opción B: documentar excepción + limitar tamaño y tipo de archivos subidos + +### P3 (pendiente) +- Next.js major upgrade (14.x → 15.x o superior con fix) + - Requiere checklist de breaking changes de Next + - Validar: rutas, middleware, auth flows, SSR + - Recomendado ejecutar en rama separada con suite E2E completa + diff --git a/services/cms-service/src/handlers.rs b/services/cms-service/src/handlers.rs index 1760c1b..20277ed 100644 --- a/services/cms-service/src/handlers.rs +++ b/services/cms-service/src/handlers.rs @@ -33,7 +33,6 @@ use reqwest::header::HeaderMap; use uuid::Uuid; use openidconnect::core::{CoreClient, CoreProviderMetadata, CoreResponseType}; -use openidconnect::reqwest::async_http_client; use openidconnect::{ AuthenticationFlow, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, RedirectUrl, Scope, TokenResponse, @@ -606,7 +605,7 @@ pub async fn update_course( let mut tx = pool .begin() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Establecer contexto de auditoría sqlx::query( @@ -616,7 +615,7 @@ pub async fn update_course( .bind(org_ctx.id.to_string()) .execute(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (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)", @@ -645,7 +644,7 @@ pub async fn update_course( tx.commit() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(course)) } @@ -1756,7 +1755,7 @@ pub async fn get_grading_categories( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(categories)) } @@ -1779,7 +1778,7 @@ pub async fn create_grading_category( .bind(payload.tipo_nota_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(category)) } @@ -1816,7 +1815,7 @@ pub async fn delete_grading_category( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -2793,7 +2792,7 @@ pub async fn register( // 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()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !email_regex.is_match(&payload.email) { return Err((StatusCode::BAD_REQUEST, "Formato de email inválido".into())); } @@ -2817,7 +2816,7 @@ pub async fn register( let mut tx = pool .begin() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (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) @@ -2837,7 +2836,7 @@ pub async fn register( tx.commit() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let token = create_jwt(user.id, user.organization_id, &user.role).map_err(|_| { ( @@ -3049,7 +3048,7 @@ pub async fn get_course_analytics( let analytics = res .json::() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(analytics)) } @@ -3097,7 +3096,7 @@ pub async fn get_advanced_analytics( let analytics = res .json::() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(analytics)) } @@ -3128,7 +3127,7 @@ pub async fn get_lesson_heatmap( let heatmap = res .json::>() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(heatmap)) } @@ -3172,7 +3171,7 @@ pub async fn get_audit_logs( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(logs)) } @@ -3247,7 +3246,7 @@ pub async fn get_sso_config( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(config)) } @@ -3306,7 +3305,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, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .into_iter() .next() .ok_or(( @@ -3327,7 +3326,7 @@ pub async fn sso_login_init( .bind(org_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (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(), @@ -3340,7 +3339,8 @@ pub async fn sso_login_init( ) })?; - let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, async_http_client) + let http_client = reqwest::Client::new(); + let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, &http_client) .await .map_err(|e| { ( @@ -3359,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, "Error interno del servidor".to_string()))?, + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?, ); let (auth_url, csrf_token, nonce) = client @@ -3380,7 +3380,7 @@ pub async fn sso_login_init( .bind(nonce.secret()) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(axum::response::Redirect::to(auth_url.as_str())) } @@ -3413,15 +3413,16 @@ pub async fn sso_callback( .bind(org_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Exchange code for token let issuer_url = IssuerUrl::new(config.issuer_url.clone()) .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?; - let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, async_http_client) + let http_client = reqwest::Client::new(); + let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, &http_client) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let client = CoreClient::from_provider_metadata( provider_metadata, @@ -3433,12 +3434,13 @@ 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, "Error interno del servidor".to_string()))?, + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?, ); let token_response = client .exchange_code(AuthorizationCode::new(params.code)) - .request_async(async_http_client) + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .request_async(&http_client) .await .map_err(|e| { ( @@ -3464,7 +3466,7 @@ pub async fn sso_callback( .to_string(); let name = claims .name() - .and_then(|n| n.get(None)) + .and_then(|n| n.get(None::<&openidconnect::LanguageTag>)) .map(|n| n.to_string()) .unwrap_or_else(|| email.split('@').next().unwrap_or("User").to_string()); @@ -3472,7 +3474,7 @@ pub async fn sso_callback( let mut tx = pool .begin() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (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)", @@ -3481,7 +3483,7 @@ pub async fn sso_callback( .bind(&email) .fetch_optional(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let user = match user { Some(u) => u, @@ -3499,13 +3501,13 @@ pub async fn sso_callback( .bind("student") // Default role .fetch_one(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? } }; tx.commit() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 6. Generate JWT let token = @@ -3857,7 +3859,7 @@ pub async fn update_user( .fetch_one(&pool) .await } - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; log_action( &pool, @@ -3913,7 +3915,7 @@ pub async fn delete_user( .execute(&pool) .await } - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if result.rows_affected() == 0 { return Err((StatusCode::NOT_FOUND, "User not found".into())); @@ -3959,7 +3961,7 @@ pub async fn get_webhooks( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(webhooks)) } @@ -3987,7 +3989,7 @@ pub async fn create_webhook( .bind(payload.secret) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; log_action( &pool, @@ -4018,7 +4020,7 @@ pub async fn delete_webhook( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if result.rows_affected() == 0 { return Err((StatusCode::NOT_FOUND, "Webhook not found".into())); @@ -4575,7 +4577,7 @@ pub async fn check_course_access( .bind(user_id) .fetch_one(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(exists) } @@ -4612,7 +4614,7 @@ pub async fn get_course_team( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(team)) } @@ -4641,7 +4643,7 @@ pub async fn add_team_member( .bind(claims.sub) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? }; if !is_authorized { @@ -4686,7 +4688,7 @@ pub async fn remove_team_member( .bind(claims.sub) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? }; if !is_authorized && claims.sub != user_id { @@ -4698,7 +4700,7 @@ pub async fn remove_team_member( .bind(user_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } @@ -4715,7 +4717,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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(json!({ "token": token }))) } diff --git a/services/cms-service/src/handlers/tasks.rs b/services/cms-service/src/handlers/tasks.rs index 88a6179..d9efc97 100644 --- a/services/cms-service/src/handlers/tasks.rs +++ b/services/cms-service/src/handlers/tasks.rs @@ -109,7 +109,7 @@ pub async fn retry_task( .bind(id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if task_result.rows_affected() > 0 { return Ok(StatusCode::NO_CONTENT); diff --git a/services/cms-service/src/handlers_admin.rs b/services/cms-service/src/handlers_admin.rs index 49b2673..45c4be5 100644 --- a/services/cms-service/src/handlers_admin.rs +++ b/services/cms-service/src/handlers_admin.rs @@ -40,7 +40,7 @@ pub async fn get_token_usage( ) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Calcular estadísticas let total_tokens: i64 = usage.iter().map(|u| u.total_tokens).sum(); @@ -123,7 +123,7 @@ pub async fn get_ai_usage_dashboard( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso diario: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener uso por punto de conexión/función let by_endpoint: Vec = sqlx::query_as( @@ -149,7 +149,7 @@ pub async fn get_ai_usage_dashboard( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso del punto de conexión: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener usuarios principales let top_users: Vec = sqlx::query_as( @@ -179,7 +179,7 @@ pub async fn get_ai_usage_dashboard( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los usuarios principales: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Calcular estadísticas de resumen let total_tokens: i64 = daily_usage.iter().map(|d| d.total_tokens).sum(); @@ -256,7 +256,7 @@ pub async fn get_ai_usage_logs( .bind(offset as i64) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los logs: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener el conteo total para la paginación let count: (i64,) = sqlx::query_as( @@ -274,7 +274,7 @@ pub async fn get_ai_usage_logs( .bind(filters.user_id.clone()) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al contar los logs: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(UsageLogsResponse { logs, @@ -459,7 +459,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso diario: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener uso por punto de conexión/función let by_endpoint: Vec = sqlx::query_as( @@ -483,7 +483,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso del punto de conexión: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener uso por organización let by_organization: Vec = sqlx::query_as( @@ -509,7 +509,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso de la organización: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener usuarios principales en todas las organizaciones let top_users: Vec = sqlx::query_as( @@ -539,7 +539,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los usuarios principales: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener uso por tipo de solicitud (para gráfico circular) let by_request_type: Vec = sqlx::query_as( @@ -560,7 +560,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso del tipo de solicitud: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Calcular estadísticas de resumen let total_tokens: i64 = daily_usage.iter().map(|d| d.total_tokens).sum(); @@ -593,7 +593,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al contar los usuarios: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Calcular uso específico por estudiante (interacciones de chat) let student_chat_usage: Vec = sqlx::query_as( @@ -623,7 +623,7 @@ pub async fn get_ai_usage_global( .bind(filters.end_date.clone()) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso de chat de estudiantes: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Calcular totales de chat de estudiantes let total_student_chat_tokens: i64 = student_chat_usage.iter().map(|s| s.total_tokens).sum(); @@ -757,7 +757,7 @@ pub async fn set_user_token_limit( .bind(user_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al establecer el límite: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -792,7 +792,7 @@ pub async fn get_user_token_usage( .bind(user_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el uso: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(usage)) } @@ -810,7 +810,7 @@ pub async fn check_user_token_limit( .bind(user_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to check limit: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(result)) } diff --git a/services/cms-service/src/handlers_assets.rs b/services/cms-service/src/handlers_assets.rs index 903741d..b2dd5d5 100644 --- a/services/cms-service/src/handlers_assets.rs +++ b/services/cms-service/src/handlers_assets.rs @@ -234,7 +234,7 @@ async fn maybe_push_local_file_to_s3( let bytes = tokio::fs::read(local_path) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al leer el archivo local: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let client = build_s3_client(&settings).await?; let key = build_s3_object_key(org_id, course_id, storage_filename); @@ -339,13 +339,13 @@ pub async fn public_s3_proxy( header::CONTENT_TYPE, "application/octet-stream" .parse() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Cabecera inválida: {}", e)))?, + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?, ); headers.insert( header::CACHE_CONTROL, "public, max-age=3600" .parse() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Cabecera inválida: {}", e)))?, + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?, ); Ok((headers, bytes)) @@ -375,7 +375,7 @@ async fn read_storage_bytes(storage_path: &str) -> Result, (StatusCode, tokio::fs::read(storage_path) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error de lectura: {}", e))) + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())) } /// POST /api/assets/upload - Subir un archivo a la biblioteca global @@ -408,7 +408,7 @@ pub async fn upload_asset( data = field .bytes() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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" @@ -1214,17 +1214,17 @@ pub async fn import_assets_zip( let temp_name = format!("uploads/tmp/import-{}.zip", Uuid::new_v4()); tokio::fs::create_dir_all("uploads/tmp") .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to create temp dir: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut temp_file = tokio::fs::File::create(&temp_name) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to create temp zip file: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut received_bytes: u64 = 0; while let Some(chunk) = field .chunk() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to read upload chunk: {}", e)))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? { received_bytes = received_bytes.saturating_add(chunk.len() as u64); if received_bytes > max_upload_bytes { @@ -1241,13 +1241,13 @@ pub async fn import_assets_zip( temp_file .write_all(&chunk) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to write temp zip file: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } temp_file .flush() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to flush temp zip file: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; zip_temp_path = Some(temp_name); } else if name == "course_id" { @@ -1315,7 +1315,7 @@ pub async fn import_assets_zip( let source_zip_name = zip_original_name.unwrap_or_else(|| "import.zip".to_string()); let zip_file = std::fs::File::open(&zip_path) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to open temp zip file: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut archive = zip::ZipArchive::new(zip_file) .map_err(|_| (StatusCode::BAD_REQUEST, "Invalid ZIP file".to_string()))?; @@ -1334,7 +1334,7 @@ pub async fn import_assets_zip( for i in 0..len { let mut file = archive .by_index(i) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("ZIP read error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !file.is_file() { continue; @@ -1377,7 +1377,7 @@ pub async fn import_assets_zip( let mut content = Vec::new(); std::io::Read::read_to_end(&mut file, &mut content) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("ZIP entry read failed: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let guessed_mimetype = mime_guess::from_path(&safe_filename) .first_or_octet_stream() @@ -1435,7 +1435,7 @@ pub async fn import_assets_zip( tokio::fs::create_dir_all("uploads") .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // ── Phase 2: process entries ─────────────────────────────────────────────── let mut imported_assets = 0usize; @@ -1564,7 +1564,7 @@ pub async fn import_assets_zip( let temp_storage_path = format!("uploads/tmp/{}", temp_storage_filename); tokio::fs::create_dir_all("uploads/tmp") .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error creating temp dir: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Err(e) = tokio::fs::write(&temp_storage_path, &content).await { failed_entries.push(format!("{}: local write failed ({})", entry_name, e)); continue; @@ -1573,7 +1573,7 @@ pub async fn import_assets_zip( let storage_path = build_ready_for_rag_path(org_ctx.id, asset_id, &format!("{}.mp4", asset_id)); tokio::fs::create_dir_all(StdPath::new(&storage_path).parent().unwrap_or(StdPath::new("."))) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error creating ready-for-rag dir: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Err((_, msg)) = transcode_flv_to_mp4(&temp_storage_path, &storage_path).await { let _ = tokio::fs::remove_file(&temp_storage_path).await; @@ -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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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); @@ -1609,7 +1609,7 @@ pub async fn import_assets_zip( let storage_path = build_ready_for_rag_path(org_ctx.id, asset_id, &safe_filename); tokio::fs::create_dir_all(StdPath::new(&storage_path).parent().unwrap_or(StdPath::new("."))) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error creating ready-for-rag dir: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Err(e) = tokio::fs::write(&storage_path, &content).await { failed_entries.push(format!("{}: local write failed ({})", entry_name, e)); continue; @@ -2124,7 +2124,7 @@ async fn normalize_flv_asset_for_rag( tokio::fs::create_dir_all("uploads/tmp") .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error creating temp dir: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let input_path = format!("uploads/tmp/flv-normalize-in-{}.flv", asset.id); let output_path = format!("uploads/tmp/flv-normalize-out-{}.mp4", asset.id); @@ -2132,7 +2132,7 @@ async fn normalize_flv_asset_for_rag( let source_bytes = read_storage_bytes(&asset.storage_path).await?; tokio::fs::write(&input_path, source_bytes) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error writing temp FLV: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Err(e) = transcode_flv_to_mp4(&input_path, &output_path).await { let _ = tokio::fs::remove_file(&input_path).await; @@ -2144,7 +2144,7 @@ async fn normalize_flv_asset_for_rag( let output_bytes = tokio::fs::read(&output_path) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error reading temp MP4: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let _ = tokio::fs::remove_file(&output_path).await; let next_storage_path = replace_last_path_extension(&asset.storage_path, "mp4"); @@ -2172,7 +2172,7 @@ async fn normalize_flv_asset_for_rag( } else { tokio::fs::write(&next_storage_path, &output_bytes) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error writing normalized MP4: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if asset.storage_path != next_storage_path { let _ = tokio::fs::remove_file(&asset.storage_path).await; @@ -2199,7 +2199,7 @@ async fn normalize_flv_asset_for_rag( .bind(asset.id) .execute(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error updating normalized asset: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; asset.filename = next_filename; asset.storage_path = next_storage_path; @@ -2307,7 +2307,7 @@ async fn ingest_chunks_to_question_bank( .bind(unit_number) .fetch_one(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Insert failed: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Ok(embedding_res) = generate_embedding(client, ollama_url, model, chunk).await { let pgvector = ai::embedding_to_pgvector(&embedding_res.embedding); @@ -2371,10 +2371,10 @@ async fn extract_pdf_text_from_bytes(bytes: Vec) -> Result= threshold) .collect(); diff --git a/services/cms-service/src/handlers_library.rs b/services/cms-service/src/handlers_library.rs index 2e89b3f..9f97f17 100644 --- a/services/cms-service/src/handlers_library.rs +++ b/services/cms-service/src/handlers_library.rs @@ -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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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())); diff --git a/services/cms-service/src/handlers_plugins.rs b/services/cms-service/src/handlers_plugins.rs index e8c306d..52fa649 100644 --- a/services/cms-service/src/handlers_plugins.rs +++ b/services/cms-service/src/handlers_plugins.rs @@ -63,7 +63,7 @@ pub async fn list_plugins( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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())); diff --git a/services/cms-service/src/handlers_question_bank.rs b/services/cms-service/src/handlers_question_bank.rs index 6beb3a7..b57501d 100644 --- a/services/cms-service/src/handlers_question_bank.rs +++ b/services/cms-service/src/handlers_question_bank.rs @@ -92,7 +92,7 @@ async fn connect_mysql_pool(env_var: &str) -> Result = if payload.import_all.unwrap_or(false) { @@ -718,7 +718,7 @@ pub async fn import_from_mysql( ) .fetch_all(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener las preguntas: {}", e)))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? } else if let Some(course_id) = payload.mysql_course_id { // Importar todas las preguntas para un curso específico (sin límite) sqlx::query_as( @@ -737,7 +737,7 @@ pub async fn import_from_mysql( .bind(course_id) .fetch_all(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener las preguntas: {}", e)))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? } else if let Some(question_ids) = payload.question_ids { // Obtener IDs de preguntas específicas - usar enfoque simple let mut imported_questions: Vec = vec![]; @@ -758,7 +758,7 @@ pub async fn import_from_mysql( .bind(q_id) .fetch_optional(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener la pregunta {}: {}", q_id, e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Some(question) = mq { // Mapear el tipo de pregunta de MySQL al tipo de pregunta de la plataforma @@ -806,7 +806,7 @@ pub async fn import_from_mysql( .bind(&source_metadata) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al importar la pregunta {}: {}", question.id_pregunta, e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; imported_questions.push(qb); } @@ -837,7 +837,7 @@ pub async fn import_from_mysql( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al comprobar existencia: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if exists.0 { skipped_count += 1; @@ -893,7 +893,7 @@ pub async fn import_from_mysql( .bind(mq.id_cursos) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al importar la pregunta {}: {}", mq.id_pregunta, e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; imported_questions.push(question); } @@ -1041,7 +1041,7 @@ pub async fn list_mysql_courses( ) .fetch_all(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; mysql_pool.close().await; @@ -1067,7 +1067,7 @@ pub async fn get_mysql_plans( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los planes: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Respaldo compatible con versiones anteriores: si el reflejo SAM está vacío, usar el reflejo de metadatos heredado. if plans.is_empty() { @@ -1084,7 +1084,7 @@ pub async fn get_mysql_plans( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los planes heredados: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } // Auto-sincronización de último recurso: si sigue vacío, obtener metadatos de MySQL y persistirlos. @@ -1208,7 +1208,7 @@ pub async fn get_mysql_courses_by_plan( .bind(filters.plan_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Intentar refrescar desde MySQL (fuente SAM) para evitar listas incompletas por espejo desactualizado. if let Ok(mysql_pool) = connect_mysql_pool("MYSQL_DATABASE_URL").await { @@ -1315,7 +1315,7 @@ pub async fn get_mysql_courses_by_plan( .bind(filters.plan_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos heredados: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } Ok(Json(courses)) @@ -1408,7 +1408,7 @@ pub async fn import_all_from_mysql( ) .fetch_all(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!("Se obtuvieron {} cursos de MySQL", mysql_courses.len()); @@ -1416,7 +1416,7 @@ pub async fn import_all_from_mysql( tracing::info!("Guardando planes y cursos en PostgreSQL..."); save_mysql_courses_and_plans(&pool, org_ctx.id, mysql_plans.clone(), mysql_courses.clone()) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al guardar cursos/planes: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Si solo se solicita la importación de metadatos, salir antes if import_metadata_only { @@ -1477,7 +1477,7 @@ pub async fn import_all_from_mysql( ) .fetch_all(&mysql_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener las preguntas: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; mysql_pool.close().await; @@ -1505,7 +1505,7 @@ pub async fn import_all_from_mysql( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Fallo en la comprobación: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; match existing { Some((id, is_active)) => { @@ -1724,14 +1724,14 @@ pub async fn ai_generate_question( })) .send() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("La solicitud de IA falló: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !response.status().is_success() { - return Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Error de la API de IA: {}", response.status()))); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())); } let result: serde_json::Value = response.json().await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al analizar la respuesta de la IA: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Extraer contenido de la respuesta de Ollama let content = result @@ -1742,7 +1742,7 @@ pub async fn ai_generate_question( // Analizar la respuesta de la IA como JSON let ai_question: AIQuestionResponse = serde_json::from_str(content) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al analizar el JSON de la pregunta: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(ai_question)) } @@ -1801,7 +1801,7 @@ pub async fn import_course_from_mysql( if let sqlx::Error::RowNotFound = e { (StatusCode::NOT_FOUND, format!("Curso con ID {} no encontrado en MySQL", payload.mysql_course_id)) } else { - (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener el curso de MySQL: {}", e)) + (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()) } })?; @@ -1809,7 +1809,7 @@ pub async fn import_course_from_mysql( // Iniciar transacción let mut tx = pool.begin().await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al iniciar la transacción: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Determinar el tipo y nivel del curso para la generación de la estructura let course_type = calculate_course_type_from_duration(mysql_course.duracion); @@ -1845,7 +1845,7 @@ pub async fn import_course_from_mysql( .bind(mysql_course.id_cursos) .fetch_one(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al crear el curso: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!("Curso creado en PostgreSQL: {}", new_course.id); @@ -1863,7 +1863,7 @@ pub async fn import_course_from_mysql( // Confirmar transacción tx.commit().await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al confirmar la transacción: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!( "Curso {} importado con éxito con {} módulos y {} lecciones", diff --git a/services/cms-service/src/handlers_rubrics.rs b/services/cms-service/src/handlers_rubrics.rs index b7040d8..b7c3131 100644 --- a/services/cms-service/src/handlers_rubrics.rs +++ b/services/cms-service/src/handlers_rubrics.rs @@ -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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))? + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rubrics)) } diff --git a/services/cms-service/src/handlers_sam.rs b/services/cms-service/src/handlers_sam.rs index 212d6d0..e002ad8 100644 --- a/services/cms-service/src/handlers_sam.rs +++ b/services/cms-service/src/handlers_sam.rs @@ -65,7 +65,7 @@ pub async fn sync_sam_students( let sam_pool = sqlx::PgPool::connect(&sam_url) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al conectar con la base de datos SAM: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut errors = Vec::new(); let mut students_synced = 0; @@ -85,7 +85,7 @@ pub async fn sync_sam_students( ) .fetch_all(&sam_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener estudiantes de SAM: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Convertir a SamStudentInfo let sam_students: Vec = rows.iter().map(|row| { @@ -196,7 +196,7 @@ pub async fn sync_sam_assignments( let sam_pool = sqlx::PgPool::connect(&sam_url) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al conectar con la base de datos SAM: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut errors = Vec::new(); let mut assignments_synced = 0; @@ -215,7 +215,7 @@ pub async fn sync_sam_assignments( ) .fetch_all(&sam_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener asignaciones: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Convertir a SamAssignmentInfo let sam_assignments: Vec = rows.iter().map(|row| { @@ -317,7 +317,7 @@ pub async fn list_sam_students( let rows = sqlx::query(&query) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los estudiantes: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let students: Vec = rows.iter().map(|row| { serde_json::json!({ @@ -354,7 +354,7 @@ pub async fn get_sam_student_courses( .bind(&sam_student_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let courses: Vec = rows.iter().map(|row| { serde_json::json!({ @@ -386,7 +386,7 @@ pub async fn sync_all_sam( let sam_pool = sqlx::PgPool::connect(&sam_url) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al conectar con la base de datos SAM: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Sincronizar estudiantes primero { @@ -400,7 +400,7 @@ pub async fn sync_all_sam( ) .fetch_all(&sam_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener estudiantes de SAM: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let sam_students: Vec = rows.iter().map(|row| { SamStudentInfo { @@ -470,7 +470,7 @@ pub async fn sync_all_sam( ) .fetch_all(&sam_pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener asignaciones: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let sam_assignments: Vec = rows.iter().map(|row| { SamAssignmentInfo { diff --git a/services/cms-service/src/handlers_test_templates.rs b/services/cms-service/src/handlers_test_templates.rs index cadd21c..fd92e4c 100644 --- a/services/cms-service/src/handlers_test_templates.rs +++ b/services/cms-service/src/handlers_test_templates.rs @@ -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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(templates)) } @@ -240,7 +240,7 @@ pub async fn get_test_template( .bind(template_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener preguntas let questions: Vec = 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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(TestTemplateWithQuestions { 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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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())); @@ -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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (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, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!( "Plantilla '{}' aplicada a la lección '{}' con {} preguntas", @@ -1019,7 +1019,7 @@ pub async fn generate_questions_with_rag( .danger_accept_invalid_certs(true) .danger_accept_invalid_hostnames(true) .build() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error del cliente HTTP: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ollama_url = ai::get_ollama_url(); let model = ai::get_embedding_model(); @@ -1070,7 +1070,7 @@ pub async fn generate_questions_with_rag( .bind(requested_num_questions * 3) // Get more for diversity .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("La búsqueda semántica falló: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!("La búsqueda semántica encontró {} preguntas similares", mysql_questions.len()); @@ -1123,7 +1123,7 @@ pub async fn generate_questions_with_rag( .bind(requested_num_questions * 3) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("El recurso a palabras clave falló: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if mysql_questions.is_empty() { tracing::info!( @@ -1220,7 +1220,7 @@ pub async fn generate_questions_with_rag( .bind(requested_num_questions * 3) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("La búsqueda por palabras clave falló: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if mysql_questions.is_empty() { tracing::info!( @@ -1309,7 +1309,7 @@ pub async fn generate_questions_with_rag( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener las preguntas: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } else { // Fetch all imported MySQL questions for this organization // NO LIMIT - fetch all questions for better RAG context @@ -1339,7 +1339,7 @@ pub async fn generate_questions_with_rag( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener las preguntas: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } if mysql_questions.is_empty() { @@ -1487,7 +1487,7 @@ pub async fn generate_questions_with_rag( let response = request.send().await.map_err(|e| { tracing::error!("AI request failed after timeout: {}", e); - (StatusCode::INTERNAL_SERVER_ERROR, format!("Ollama timeout - el equipo t-800 está tardando en responder. Intenta nuevamente: {}", e)) + (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()) })?; tracing::info!("Estado de la respuesta de Ollama: {}", response.status()); diff --git a/services/lms-service/src/handlers.rs b/services/lms-service/src/handlers.rs index 4e31606..c6b3136 100644 --- a/services/lms-service/src/handlers.rs +++ b/services/lms-service/src/handlers.rs @@ -154,7 +154,7 @@ pub async fn get_me( .bind(claims.sub) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Some(user) = user { return Ok(Json(UserResponse { @@ -513,7 +513,7 @@ pub async fn export_course_grades( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 2. Obtener datos generales de los estudiantes #[derive(sqlx::FromRow)] @@ -546,7 +546,7 @@ pub async fn export_course_grades( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Obtener calificaciones detalladas por usuario/categoría #[derive(sqlx::FromRow)] @@ -571,7 +571,7 @@ pub async fn export_course_grades( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 4. Construir CSV let mut csv = "Name,Email,Cohort,Progress,Overall Score".to_string(); @@ -830,7 +830,7 @@ pub async fn register( // 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()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !email_regex.is_match(&payload.email) { return Err((StatusCode::BAD_REQUEST, "Formato de email inválido".into())); } @@ -855,7 +855,7 @@ pub async fn register( let mut tx = pool .begin() .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let organization = if let Some(org_name) = payload.organization_name { sqlx::query_as::<_, Organization>( @@ -864,7 +864,7 @@ pub async fn register( .bind(&org_name) .fetch_one(&mut *tx) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al buscar o crear la organización: {}", e)))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? } else { sqlx::query_as::<_, Organization>( "SELECT * FROM organizations WHERE id = '00000000-0000-0000-0000-000000000001'", @@ -892,7 +892,7 @@ pub async fn register( tx.commit() .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let token = create_jwt(user.id, user.organization_id, "student").map_err(|_| { ( @@ -1872,7 +1872,7 @@ pub async fn submit_lesson_score( let mut tx = pool .begin() .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ip = headers .get("x-forwarded-for") @@ -1894,7 +1894,7 @@ pub async fn submit_lesson_score( Some("EVENTO_DEL_SISTEMA".to_string()), ) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 1. Obtener reglas de intentos de la lección let max_attempts: Option> = @@ -1902,7 +1902,7 @@ pub async fn submit_lesson_score( .bind(payload.lesson_id) .fetch_optional(&mut *tx) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if max_attempts.is_none() { return Err((StatusCode::NOT_FOUND, "Lección no encontrada".into())); @@ -1916,7 +1916,7 @@ pub async fn submit_lesson_score( .bind(org_ctx.id) .fetch_optional(&mut *tx) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Some(count) = existing_attempts { if let Some(max) = max_attempts { @@ -1941,7 +1941,7 @@ pub async fn submit_lesson_score( .bind(payload.metadata) .fetch_one(&mut *tx) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3.1 Sincronizar con MySQL externo si está disponible if let Some(mysql_pool) = mysql_pool { @@ -2006,7 +2006,7 @@ pub async fn submit_lesson_score( tx.commit() .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 4. Enviar Webhooks let webhook_service = common::webhooks::WebhookService::new(pool.clone()); @@ -2217,7 +2217,7 @@ pub async fn get_course_analytics( .bind(filter.cohort_id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 2. Puntaje promedio del curso (General) let average_score: Option = sqlx::query_scalar( @@ -2236,7 +2236,7 @@ pub async fn get_course_analytics( .bind(filter.cohort_id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Analítica por lección // Nota: Convertimos AVG a float4 para compatibilidad con PostgreSQL @@ -2262,7 +2262,7 @@ pub async fn get_course_analytics( .bind(filter.cohort_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let lessons = rows .into_iter() @@ -2305,7 +2305,7 @@ pub async fn notify_student( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; match role.as_deref() { Some("instructor") | Some("admin") => {} @@ -2320,7 +2320,7 @@ pub async fn notify_student( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !enrolled { return Err((StatusCode::NOT_FOUND, "El alumno no está inscrito en este curso".to_string())); @@ -2337,7 +2337,7 @@ pub async fn notify_student( .bind(&payload.link_url) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } @@ -2368,7 +2368,7 @@ pub async fn get_course_progress( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .flatten(); let progress_percentage = enrollment_progress @@ -2737,7 +2737,7 @@ pub async fn toggle_bookmark( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Some(id) = existing_id { // Eliminar marcador @@ -2745,7 +2745,7 @@ pub async fn toggle_bookmark( .bind(id) .execute(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } else { // Añadir marcador @@ -2758,7 +2758,7 @@ pub async fn toggle_bookmark( .bind(lesson_id) .execute(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::CREATED) } } @@ -2780,7 +2780,7 @@ pub async fn get_user_bookmarks( // Wait, let's create a better filter for this. .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(bookmarks)) } @@ -2812,7 +2812,7 @@ pub async fn update_user( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(UserResponse { id: user.id, @@ -2846,7 +2846,7 @@ pub async fn get_recommendations( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 2. Obtener metadatos de la lección (títulos y etiquetas) para contexto #[derive(sqlx::FromRow)] @@ -2878,7 +2878,7 @@ pub async fn get_recommendations( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Preparar contexto de IA con Análisis de Habilidades use std::collections::HashMap; @@ -3080,7 +3080,7 @@ pub async fn evaluate_audio_response( })) .send() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ai_data: serde_json::Value = response.json().await.map_err(|e| { ( @@ -3101,7 +3101,7 @@ pub async fn evaluate_audio_response( "feedback": "Lo siento, tuve un problema analizando tu respuesta. ¡Sigue practicando!" }) }) - ).map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Mapping failed: {}", e)))?; + ).map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(grading)) } @@ -3152,7 +3152,7 @@ pub async fn evaluate_audio_file( audio_data = field .bytes() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .to_vec(); tracing::info!("Received audio file: {} bytes", audio_data.len()); } @@ -3322,7 +3322,7 @@ pub async fn evaluate_audio_file( "feedback": "Lo siento, tuve un problema analizando tu respuesta con Whisper. ¡Sigue practicando!" }) }) - ).map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Mapping failed: {}", e)))?; + ).map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; grading.transcript = Some(transcript.clone()); // 3. Guardar respuesta de audio en la base de datos @@ -4242,7 +4242,7 @@ pub async fn chat_with_tutor( .build() .map_err(|e| { tracing::warn!("Failed to create HTTP client for embeddings: {}", e); - (StatusCode::INTERNAL_SERVER_ERROR, format!("HTTP client error: {}", e)) + (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()) })?; let ollama_url = ai::get_ollama_url(); @@ -4666,11 +4666,11 @@ pub async fn chat_role_play( "temperature": 0.8 })) .send().await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error en la solicitud de IA: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !response.status().is_success() { - let err_body = response.text().await.unwrap_or_default(); - return Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Error de la API de IA: {}", err_body))); + let _err_body = response.text().await.unwrap_or_default(); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string())); } let ai_data: serde_json::Value = response.json().await.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error al analizar la respuesta de la IA".into()))?; @@ -4714,7 +4714,7 @@ pub async fn get_lesson_feedback( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or(( StatusCode::BAD_REQUEST, "No se encontró calificación para esta lección".into(), @@ -5197,7 +5197,7 @@ pub async fn update_lesson_collaborative_doc( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !lesson_exists { return Err((StatusCode::NOT_FOUND, "Lección no encontrada".into())); @@ -5220,7 +5220,7 @@ pub async fn update_lesson_collaborative_doc( .bind(payload.base_revision) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .rows_affected(); if rows_updated == 1 { @@ -5241,7 +5241,7 @@ pub async fn update_lesson_collaborative_doc( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if existing.is_none() && payload.base_revision == 0 { // Primer guardado @@ -5258,7 +5258,7 @@ pub async fn update_lesson_collaborative_doc( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; sqlx::query( r#" @@ -5273,7 +5273,7 @@ pub async fn update_lesson_collaborative_doc( .bind(user_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; return Ok(Json(UpdateCollaborativeDocResponse { lesson_id: id, @@ -5294,7 +5294,7 @@ pub async fn update_lesson_collaborative_doc( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let (sc, sr) = server.map(|r| (r.content, r.revision)).unwrap_or_default(); @@ -5428,7 +5428,7 @@ pub async fn list_lesson_annotations( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rows)) } @@ -5464,7 +5464,7 @@ pub async fn create_lesson_annotation( .bind(payload.position_data) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok((StatusCode::CREATED, Json(row))) } @@ -5511,7 +5511,7 @@ pub async fn delete_lesson_annotation( .bind(lesson_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .rows_affected(); if affected == 0 { Err((StatusCode::NOT_FOUND, "Anotación no encontrada".to_string())) @@ -5535,7 +5535,7 @@ pub async fn get_my_annotations( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rows)) } @@ -5595,7 +5595,7 @@ pub async fn assign_mentor( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; match role.as_deref() { Some("instructor") | Some("admin") => {} @@ -5620,7 +5620,7 @@ pub async fn assign_mentor( .bind(&payload.notes) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(row)) } @@ -5654,7 +5654,7 @@ pub async fn list_course_mentorships( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rows)) } @@ -5673,7 +5673,7 @@ pub async fn delete_mentorship( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .rows_affected(); if affected == 0 { @@ -5714,7 +5714,7 @@ pub async fn get_my_mentor( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(row)) } @@ -5750,7 +5750,7 @@ pub async fn get_my_mentees( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rows)) } diff --git a/services/lms-service/src/handlers_ai_audit.rs b/services/lms-service/src/handlers_ai_audit.rs index 8c088fb..1a7aaa9 100644 --- a/services/lms-service/src/handlers_ai_audit.rs +++ b/services/lms-service/src/handlers_ai_audit.rs @@ -283,7 +283,7 @@ pub async fn list_ai_audit_logs( .bind(offset) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al listar auditoría de IA: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut items = Vec::new(); @@ -371,7 +371,7 @@ pub async fn review_ai_audit_log( .bind(note_or_null) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al actualizar auditoría IA: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if updated.rows_affected() == 0 { return Err((StatusCode::NOT_FOUND, "Registro de auditoría no encontrado".to_string())); @@ -437,7 +437,7 @@ pub async fn get_ai_audit_metrics( .bind(days) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error métricas de auditoría: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let total_chat_logs: i64 = totals.get("total_chat"); let total_reviewed: i64 = totals.get("reviewed"); @@ -456,7 +456,7 @@ pub async fn get_ai_audit_metrics( .bind(days) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error escaneando logs: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut signal_counts: std::collections::HashMap = std::collections::HashMap::new(); let mut total_flagged: i64 = 0; diff --git a/services/lms-service/src/handlers_announcements.rs b/services/lms-service/src/handlers_announcements.rs index 37d6ef0..3de9245 100644 --- a/services/lms-service/src/handlers_announcements.rs +++ b/services/lms-service/src/handlers_announcements.rs @@ -49,7 +49,7 @@ async fn ensure_announcement_author_exists( .bind(user_id) .fetch_one(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if exists { return Ok(()); @@ -71,7 +71,7 @@ async fn ensure_announcement_author_exists( .bind(normalized_role) .execute(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("No se pudo provisionar usuario LMS: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(()) } @@ -97,7 +97,7 @@ pub async fn list_announcements( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Adjuntar cohort_ids a cada anuncio for a in &mut announcements { @@ -107,7 +107,7 @@ pub async fn list_announcements( .bind(a.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !cohorts.is_empty() { a.cohort_ids = Some(cohorts.into_iter().map(|c| c.0).collect()); @@ -136,7 +136,7 @@ pub async fn create_announcement( let mut tx = pool .begin() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 1. Crear anuncio let mut announcement = sqlx::query_as::<_, CourseAnnouncement>( @@ -152,7 +152,7 @@ pub async fn create_announcement( .bind(payload.is_pinned.unwrap_or(false)) .fetch_one(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 2. Vincular cohortes si se proporcionan if let Some(ref cohort_ids) = payload.cohort_ids { @@ -164,14 +164,14 @@ pub async fn create_announcement( .bind(cohort_id) .execute(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } announcement.cohort_ids = Some(cohort_ids.clone()); } tx.commit() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Obtener estudiantes objetivo para notificaciones let enrolled_students = if let Some(ref cohort_ids) = payload.cohort_ids { @@ -207,7 +207,7 @@ pub async fn create_announcement( .fetch_all(&pool) .await } - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Crear notificación para cada estudiante inscrito for (student_id,) in enrolled_students { @@ -276,7 +276,7 @@ pub async fn update_announcement( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(announcement)) } @@ -302,7 +302,7 @@ pub async fn delete_announcement( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } diff --git a/services/lms-service/src/handlers_cohorts.rs b/services/lms-service/src/handlers_cohorts.rs index 35723df..c660d9a 100644 --- a/services/lms-service/src/handlers_cohorts.rs +++ b/services/lms-service/src/handlers_cohorts.rs @@ -20,7 +20,7 @@ pub async fn list_cohorts( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(cohorts)) } @@ -43,7 +43,7 @@ pub async fn create_cohort( .bind(payload.description) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(cohort)) } @@ -63,7 +63,7 @@ pub async fn add_cohort_member( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !exists { return Err((StatusCode::NOT_FOUND, "Cohorte no encontrada".to_string())); @@ -81,7 +81,7 @@ pub async fn add_cohort_member( .bind(payload.user_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(member)) } @@ -100,7 +100,7 @@ pub async fn remove_cohort_member( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !exists { return Err((StatusCode::NOT_FOUND, "Cohorte no encontrada".to_string())); @@ -111,7 +111,7 @@ pub async fn remove_cohort_member( .bind(user_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } @@ -130,7 +130,7 @@ pub async fn get_cohort_members( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !exists { return Err((StatusCode::NOT_FOUND, "Cohorte no encontrada".to_string())); @@ -140,7 +140,7 @@ pub async fn get_cohort_members( .bind(cohort_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(members)) } diff --git a/services/lms-service/src/handlers_discussions.rs b/services/lms-service/src/handlers_discussions.rs index a1a6e0c..2ff2d87 100644 --- a/services/lms-service/src/handlers_discussions.rs +++ b/services/lms-service/src/handlers_discussions.rs @@ -454,7 +454,7 @@ pub async fn list_threads( let threads = sql_query .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(threads)) } @@ -497,7 +497,7 @@ pub async fn create_thread( .bind(&payload.content) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Suscribir automáticamente al autor al hilo let _ = sqlx::query( @@ -654,7 +654,7 @@ fn get_thread_posts_recursive<'a>( let mut posts = sql_query .fetch_all(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Obtener respuestas recursivamente para cada mensaje for post in &mut posts { @@ -691,7 +691,7 @@ pub async fn pin_thread( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -721,7 +721,7 @@ pub async fn lock_thread( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -779,7 +779,7 @@ pub async fn create_post( .bind(payload.content) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Notificar a los suscritos al hilo (excepto autor de la respuesta) let mut recipients = sqlx::query_as::<_, (Uuid, String, Option)>( @@ -883,7 +883,7 @@ pub async fn endorse_post( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -912,7 +912,7 @@ pub async fn vote_post( .bind(&payload.vote_type) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Recalcular votos positivos let upvote_count: i64 = sqlx::query_scalar( @@ -928,7 +928,7 @@ pub async fn vote_post( .bind(post_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -951,7 +951,7 @@ pub async fn subscribe_thread( .bind(claims.sub) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -971,7 +971,7 @@ pub async fn unsubscribe_thread( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } diff --git a/services/lms-service/src/handlers_email.rs b/services/lms-service/src/handlers_email.rs index 7ce6dd1..db4fedf 100644 --- a/services/lms-service/src/handlers_email.rs +++ b/services/lms-service/src/handlers_email.rs @@ -188,7 +188,7 @@ pub async fn forgot_password( .bind(&email) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let Some(user) = user else { // Respuesta genérica — no revelar si el email existe @@ -210,7 +210,7 @@ pub async fn forgot_password( .bind(user.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Insertar nuevo token (expira en 1 hora) sqlx::query( @@ -220,7 +220,7 @@ pub async fn forgot_password( .bind(&token) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Intentar enviar email (fire-and-forget en caso de error SMTP) let base_url = env::var("EXPERIENCE_URL").unwrap_or_else(|_| "https://openccb.local".to_string()); @@ -283,7 +283,7 @@ pub async fn reset_password( .bind(&token) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let Some((user_id,)) = row else { return Err(( @@ -303,14 +303,14 @@ pub async fn reset_password( .bind(user_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Marcar token como usado sqlx::query("UPDATE password_reset_tokens SET used_at = NOW() WHERE token = $1") .bind(&token) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(MessageResponse { message: "Contraseña actualizada correctamente. Ya puedes iniciar sesión.".to_string(), diff --git a/services/lms-service/src/handlers_embeddings.rs b/services/lms-service/src/handlers_embeddings.rs index 0121148..b2f2400 100644 --- a/services/lms-service/src/handlers_embeddings.rs +++ b/services/lms-service/src/handlers_embeddings.rs @@ -55,7 +55,7 @@ pub async fn generate_knowledge_embeddings( .danger_accept_invalid_certs(true) .danger_accept_invalid_hostnames(true) .build() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("HTTP client error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ollama_url = ai::get_ollama_url(); let model = ai::get_embedding_model(); @@ -73,7 +73,7 @@ pub async fn generate_knowledge_embeddings( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let _total = entries.len(); let mut processed = 0; @@ -144,7 +144,7 @@ pub async fn regenerate_knowledge_embedding( .danger_accept_invalid_certs(true) .danger_accept_invalid_hostnames(true) .build() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("HTTP client error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ollama_url = ai::get_ollama_url(); let model = ai::get_embedding_model(); @@ -157,13 +157,13 @@ pub async fn regenerate_knowledge_embedding( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Entrada de la base de conocimientos no encontrada".to_string()))?; // Generar embedding let response = generate_embedding(&client, &ollama_url, &model, &entry.content_chunk) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("AI error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let pgvector = ai::embedding_to_pgvector(&response.embedding); @@ -180,7 +180,7 @@ pub async fn regenerate_knowledge_embedding( .bind(entry_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -198,7 +198,7 @@ pub async fn semantic_search_knowledge( .danger_accept_invalid_certs(true) .danger_accept_invalid_hostnames(true) .build() - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("HTTP client error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let ollama_url = ai::get_ollama_url(); let model = ai::get_embedding_model(); @@ -206,7 +206,7 @@ pub async fn semantic_search_knowledge( // Generar embedding para la consulta let embedding_response = generate_embedding(&client, &ollama_url, &model, &filters.query) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("AI error: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let pgvector = ai::embedding_to_pgvector(&embedding_response.embedding); @@ -264,7 +264,7 @@ pub async fn semantic_search_knowledge( let results = sql_query .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(results)) } diff --git a/services/lms-service/src/handlers_faq.rs b/services/lms-service/src/handlers_faq.rs index 9f4ba9a..6b50308 100644 --- a/services/lms-service/src/handlers_faq.rs +++ b/services/lms-service/src/handlers_faq.rs @@ -194,7 +194,7 @@ pub async fn import_faq_candidates( .bind(limit) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al importar candidatos FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let imported: i64 = row.get("imported"); let skipped: i64 = row.get("skipped"); @@ -250,7 +250,7 @@ pub async fn list_faq_review_queue( .bind(offset) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al listar la cola FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let total: i64 = sqlx::query_scalar( r#" @@ -264,7 +264,7 @@ pub async fn list_faq_review_queue( .bind(filters.status.clone()) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al contar cola FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(FaqReviewQueueResponse { items, @@ -292,7 +292,7 @@ pub async fn answer_faq_review_item( let mut tx = pool .begin() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("No se pudo iniciar transacción FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let queue_item: (String, String) = sqlx::query_as( "SELECT status, question_text FROM faq_review_queue WHERE id = $1 AND organization_id = $2" @@ -301,7 +301,7 @@ pub async fn answer_faq_review_item( .bind(org_ctx.id) .fetch_optional(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al buscar item FAQ: {}", e)))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Item de revisión no encontrado".to_string()))?; if queue_item.0 == "dismissed" { @@ -335,7 +335,7 @@ pub async fn answer_faq_review_item( .bind(claims.sub) .fetch_one(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al crear FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; sqlx::query( r#" @@ -358,7 +358,7 @@ pub async fn answer_faq_review_item( .bind(org_ctx.id) .execute(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al actualizar cola FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } else { sqlx::query( r#" @@ -379,12 +379,12 @@ pub async fn answer_faq_review_item( .bind(org_ctx.id) .execute(&mut *tx) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al responder cola FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } tx.commit() .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("No se pudo confirmar transacción FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::OK) } @@ -416,7 +416,7 @@ pub async fn dismiss_faq_review_item( .bind(org_ctx.id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al descartar item FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if result.rows_affected() == 0 { return Err((StatusCode::NOT_FOUND, "Item de revisión no encontrado".to_string())); @@ -475,7 +475,7 @@ pub async fn list_faq_entries( .bind(offset) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al listar FAQ: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(rows)) } diff --git a/services/lms-service/src/handlers_lti_consumer.rs b/services/lms-service/src/handlers_lti_consumer.rs index 32497d3..dc6d8c3 100644 --- a/services/lms-service/src/handlers_lti_consumer.rs +++ b/services/lms-service/src/handlers_lti_consumer.rs @@ -82,7 +82,7 @@ pub async fn list_course_lti_tools( .bind(course_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let tools = rows .into_iter() @@ -139,7 +139,7 @@ pub async fn create_course_lti_tool( .bind(payload.config.unwrap_or(serde_json::json!({}))) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(( StatusCode::CREATED, @@ -206,7 +206,7 @@ pub async fn update_course_lti_tool( .bind(payload.config) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Herramienta LTI no encontrada".to_string()))?; Ok(Json(LtiExternalTool { @@ -236,7 +236,7 @@ pub async fn delete_course_lti_tool( .bind(course_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if res.rows_affected() == 0 { return Err((StatusCode::NOT_FOUND, "Herramienta LTI no encontrada".to_string())); @@ -276,7 +276,7 @@ pub async fn lti_grade_passback( .bind(tool_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Herramienta LTI no encontrada".to_string()))?; let organization_id: Uuid = tool_row.get("organization_id"); @@ -323,7 +323,7 @@ pub async fn lti_grade_passback( .bind(organization_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !user_exists { return Err((StatusCode::UNPROCESSABLE_ENTITY, "user_id inválido para esta organización".to_string())); @@ -348,7 +348,7 @@ pub async fn lti_grade_passback( .bind(organization_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !lesson_ok { return Err((StatusCode::UNPROCESSABLE_ENTITY, "lesson_id no pertenece al curso".to_string())); @@ -384,7 +384,7 @@ pub async fn lti_grade_passback( .bind(payload.metadata.clone().unwrap_or(serde_json::json!({}))) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Sincronizar con gradebook solo cuando hay lesson_id if let Some(lesson_id) = payload.lesson_id { @@ -419,7 +419,7 @@ pub async fn lti_grade_passback( .bind(metadata) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; } Ok(Json(LtiGradePassbackResponse { @@ -458,7 +458,7 @@ pub async fn rotate_lti_tool_secret( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if !tool_exists { return Err((StatusCode::NOT_FOUND, "Herramienta LTI no encontrada".to_string())); @@ -481,7 +481,7 @@ pub async fn rotate_lti_tool_secret( .bind(tool_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; tracing::info!( "rotate_lti_tool_secret: rotated secret for tool {} in course {} org {}", @@ -634,7 +634,7 @@ pub async fn lti_ags_score_passback( .bind(tool_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Herramienta LTI no encontrada".to_string()))?; let client_id = config.ags_client_id.as_deref().unwrap_or(""); diff --git a/services/lms-service/src/handlers_notes.rs b/services/lms-service/src/handlers_notes.rs index a015c3c..633c4b4 100644 --- a/services/lms-service/src/handlers_notes.rs +++ b/services/lms-service/src/handlers_notes.rs @@ -20,7 +20,7 @@ pub async fn get_note( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(note)) } @@ -47,7 +47,7 @@ pub async fn save_note( .bind(payload.content) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(note)) } diff --git a/services/lms-service/src/handlers_payments.rs b/services/lms-service/src/handlers_payments.rs index 03080c0..3db0905 100644 --- a/services/lms-service/src/handlers_payments.rs +++ b/services/lms-service/src/handlers_payments.rs @@ -51,7 +51,7 @@ pub async fn create_payment_preference( .bind(&course.currency) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 3. Llamar a la API de Mercado Pago let mp_access_token = std::env::var("MP_ACCESS_TOKEN").unwrap_or_default(); @@ -125,7 +125,7 @@ pub async fn create_payment_preference( .bind(transaction_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(PaymentPreferenceResponse { preference_id, diff --git a/services/lms-service/src/handlers_pedagogical.rs b/services/lms-service/src/handlers_pedagogical.rs index e89782f..625b481 100644 --- a/services/lms-service/src/handlers_pedagogical.rs +++ b/services/lms-service/src/handlers_pedagogical.rs @@ -88,7 +88,7 @@ pub async fn get_lesson_quality_metrics( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if enrolled == 0 { return Ok(Json(CourseQualityMetrics { @@ -146,7 +146,7 @@ pub async fn get_lesson_quality_metrics( .bind(enrolled) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let lessons = rows .into_iter() @@ -211,7 +211,7 @@ pub async fn get_quiz_discrimination_index( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if rows.is_empty() { return Ok(Json(CourseDiscriminationReport { @@ -300,7 +300,7 @@ pub async fn get_curricular_suggestions( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if enrolled < 5 { return Ok(Json(CurricularSuggestionsReport { @@ -335,7 +335,7 @@ pub async fn get_curricular_suggestions( .bind(enrolled) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut suggestions: Vec = vec![]; diff --git a/services/lms-service/src/handlers_peer_review.rs b/services/lms-service/src/handlers_peer_review.rs index 17e9b27..31e52cd 100644 --- a/services/lms-service/src/handlers_peer_review.rs +++ b/services/lms-service/src/handlers_peer_review.rs @@ -81,7 +81,7 @@ pub async fn submit_assignment( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if let Some(_) = existing { // Actualizar entrega existente @@ -98,7 +98,7 @@ pub async fn submit_assignment( .bind(lesson_id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; return Ok(Json(updated)); } @@ -118,7 +118,7 @@ pub async fn submit_assignment( .bind(&payload.content) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(submission)) } @@ -158,7 +158,7 @@ pub async fn get_peer_review_assignment( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(submission)) } @@ -177,7 +177,7 @@ pub async fn submit_peer_review( .bind(payload.submission_id) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let submission_user_id = match submission_row { Some(row) => row.get::("user_id"), @@ -199,7 +199,7 @@ pub async fn submit_peer_review( .bind(claims.sub) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if existing.is_some() { return Err(( @@ -223,7 +223,7 @@ pub async fn submit_peer_review( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Recalcular nota final ponderada tras nueva revisión de par let lesson_id_for_calc: Uuid = sqlx::query_scalar( @@ -232,7 +232,7 @@ pub async fn submit_peer_review( .bind(payload.submission_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let _ = recalculate_final_score(&pool, payload.submission_id, lesson_id_for_calc).await; @@ -258,7 +258,7 @@ pub async fn get_my_submission_feedback( .bind(lesson_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(reviews)) } @@ -287,7 +287,7 @@ pub async fn list_lesson_submissions( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(submissions)) } @@ -304,7 +304,7 @@ pub async fn get_submission_reviews( .bind(submission_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(reviews)) } @@ -325,7 +325,7 @@ pub async fn get_peer_review_settings( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(settings)) } @@ -376,7 +376,7 @@ pub async fn upsert_peer_review_settings( .bind(auto_assign) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(settings)) } @@ -400,7 +400,7 @@ pub async fn auto_assign_peer_reviews( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .unwrap_or(2); // Entregar todas las submissions de esta lección @@ -411,7 +411,7 @@ pub async fn auto_assign_peer_reviews( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let mut assignments_created: i64 = 0; @@ -423,7 +423,7 @@ pub async fn auto_assign_peer_reviews( .bind(sub_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let needed = (required as i64) - existing_count; if needed <= 0 { @@ -437,7 +437,7 @@ pub async fn auto_assign_peer_reviews( .bind(sub_id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Candidatos: otros alumnos que no sean el autor y no hayan revisado ya let candidates: Vec = submissions @@ -486,7 +486,7 @@ pub async fn auto_assign_peer_reviews( .bind(lesson_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(serde_json::json!({ "lesson_id": lesson_id, @@ -517,7 +517,7 @@ pub async fn instructor_grade_submission( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if sub_exists.is_none() { return Err((StatusCode::NOT_FOUND, "Entrega no encontrada".to_string())); @@ -542,7 +542,7 @@ pub async fn instructor_grade_submission( .bind(org_ctx.id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // Recalcular nota final ponderada recalculate_final_score(&pool, payload.submission_id, lesson_id).await?; @@ -570,7 +570,7 @@ pub async fn get_my_submission( .bind(lesson_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(sub)) } @@ -594,7 +594,7 @@ async fn recalculate_final_score( .bind(submission_id) .fetch_optional(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .unwrap_or((70i32, 30i32, 2i32)); // Promedio de revisiones de pares (no instructor) @@ -604,7 +604,7 @@ async fn recalculate_final_score( .bind(submission_id) .fetch_optional(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .flatten(); // Calificación del instructor @@ -614,7 +614,7 @@ async fn recalculate_final_score( .bind(submission_id) .fetch_optional(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .flatten(); // Solo calcular nota final si hay suficientes revisiones de pares O hay nota del instructor @@ -624,7 +624,7 @@ async fn recalculate_final_score( .bind(submission_id) .fetch_one(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let has_enough_peers = peer_count >= required as i64; let final_score = match (peer_avg, instructor_score, has_enough_peers) { @@ -653,7 +653,7 @@ async fn recalculate_final_score( .bind(submission_id) .execute(pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // También actualizar review_count en todas las submissions del mismo lesson let _ = sqlx::query( diff --git a/services/lms-service/src/handlers_scorm.rs b/services/lms-service/src/handlers_scorm.rs index 19b5780..230d886 100644 --- a/services/lms-service/src/handlers_scorm.rs +++ b/services/lms-service/src/handlers_scorm.rs @@ -74,7 +74,7 @@ pub async fn track_xapi_statement( .bind(payload.raw_statement) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(XapiStatementResponse { id: statement_id, diff --git a/services/lms-service/src/handlers_search.rs b/services/lms-service/src/handlers_search.rs index 99cbdd5..bc9eeb1 100644 --- a/services/lms-service/src/handlers_search.rs +++ b/services/lms-service/src/handlers_search.rs @@ -66,7 +66,7 @@ pub async fn global_search( .bind(limit) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; for (id, title, description) in courses { let snippet = description.map(|d| truncate(&d, 150)); @@ -99,7 +99,7 @@ pub async fn global_search( .bind(limit) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; for (id, title, summary, course_id, course_title) in lessons { let snippet = summary.map(|s| truncate(&s, 150)); diff --git a/services/lms-service/src/handlers_study_rooms.rs b/services/lms-service/src/handlers_study_rooms.rs index a0585ba..6074b12 100644 --- a/services/lms-service/src/handlers_study_rooms.rs +++ b/services/lms-service/src/handlers_study_rooms.rs @@ -102,7 +102,7 @@ pub async fn list_course_study_rooms( .bind(org_ctx.id) .fetch_all(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let rooms = rows .into_iter() @@ -212,7 +212,7 @@ pub async fn create_study_room( .bind(now) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(( StatusCode::CREATED, @@ -259,7 +259,7 @@ pub async fn join_study_room( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Sala no encontrada".to_string()))?; if room.status == "ended" { @@ -322,7 +322,7 @@ pub async fn end_study_room( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Sala no encontrada".to_string()))?; // Solo el creador puede terminar la sala @@ -351,7 +351,7 @@ pub async fn end_study_room( .bind(room_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(EndStudyRoomResponse { room_id, @@ -373,7 +373,7 @@ pub async fn delete_study_room( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Sala no encontrada".to_string()))?; if claims.sub != created_by { @@ -384,7 +384,7 @@ pub async fn delete_study_room( .bind(room_id) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } @@ -417,7 +417,7 @@ pub async fn get_study_room_recordings( .bind(org_ctx.id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .flatten() .ok_or((StatusCode::NOT_FOUND, "Sala no encontrada o sin ID BBB".to_string()))?; diff --git a/services/lms-service/src/live.rs b/services/lms-service/src/live.rs index 89bc981..bcda999 100644 --- a/services/lms-service/src/live.rs +++ b/services/lms-service/src/live.rs @@ -30,7 +30,7 @@ pub async fn get_course_meetings( .bind(claims.org) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(meetings)) } @@ -65,7 +65,7 @@ pub async fn create_meeting( .bind(join_url) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(meeting)) } @@ -84,7 +84,7 @@ pub async fn delete_meeting( .bind(claims.org) .execute(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::NO_CONTENT) } diff --git a/services/lms-service/src/lti.rs b/services/lms-service/src/lti.rs index d08e5e6..c61286a 100644 --- a/services/lms-service/src/lti.rs +++ b/services/lms-service/src/lti.rs @@ -33,7 +33,7 @@ pub async fn lti_login_initiation( .bind(¶ms.client_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::BAD_REQUEST, "Registro LTI no encontrado".to_string()))?; // 2. Generar estado y nonce @@ -45,7 +45,7 @@ pub async fn lti_login_initiation( .bind(&nonce) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; // 4. Construir URL de redirección let mut url = format!( @@ -130,7 +130,7 @@ pub async fn lti_launch( .bind(aud) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Registro LTI no encontrado para emisor/audiencia".to_string()))?; // 3. Validar JWT @@ -143,7 +143,7 @@ pub async fn lti_launch( .bind(<i_claims.nonce) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .rows_affected() > 0; if !nonce_exists { @@ -161,7 +161,7 @@ pub async fn lti_launch( .bind(registration.organization_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; if user.is_none() { let new_user_id = Uuid::new_v4(); @@ -182,7 +182,7 @@ pub async fn lti_launch( .bind(role) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; user = Some(User { id: new_user_id, @@ -211,7 +211,7 @@ pub async fn lti_launch( let studio_url = std::env::var("NEXT_PUBLIC_STUDIO_URL").unwrap_or_else(|_| "http://localhost:3001".to_string()); let token = common::auth::create_jwt(user.id, user.organization_id, &user.role) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al crear el token: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let redirect_target = lti_claims.resource_link.as_ref().map(|rl| rl.id.clone()).unwrap_or_default(); if lti_claims.message_type == "LtiDeepLinkingRequest" { @@ -228,7 +228,7 @@ pub async fn lti_launch( .bind(&settings.data) .execute(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Redirect::to(&format!("{}/lti/deep-linking?token={}&dl_token={}", studio_url, token, dl_request_id))) } else { @@ -258,7 +258,7 @@ pub async fn lti_deep_linking_response( .bind(dl_id) .fetch_optional(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::UNAUTHORIZED, "Solicitud de DL inválida o expirada".to_string()))?; // Mapeo manual ya que no podemos usar query!/query_as! fácilmente para RETURNING sin una estructura @@ -274,7 +274,7 @@ pub async fn lti_deep_linking_response( .bind(registration_id) .fetch_one(&pool) .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let now = chrono::Utc::now().timestamp(); let response_claims = common::models::LtiDeepLinkingResponseClaims { @@ -301,7 +301,7 @@ pub async fn lti_deep_linking_response( &response_claims, &private_key, ) - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(json!({ "jwt": response_jwt, diff --git a/services/lms-service/src/portfolio.rs b/services/lms-service/src/portfolio.rs index 9cc3e31..130444c 100644 --- a/services/lms-service/src/portfolio.rs +++ b/services/lms-service/src/portfolio.rs @@ -18,7 +18,7 @@ pub async fn get_public_profile( .bind(user_id) .fetch_optional(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .ok_or((StatusCode::NOT_FOUND, "Usuario no encontrado".to_string()))?; let is_public: bool = user.get("is_public_profile"); @@ -44,13 +44,13 @@ pub async fn get_public_profile( .bind(user_id) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let completed_courses: i64 = sqlx::query("SELECT COUNT(*) FROM enrollments WHERE user_id = $1 AND progress >= 100") .bind(user_id) .fetch_one(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))? .get(0); Ok(Json(PublicProfile { @@ -87,7 +87,7 @@ pub async fn get_my_badges( .bind(claims.sub) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(Json(badges)) } @@ -106,7 +106,7 @@ pub async fn award_badge( .bind(payload.badge_id) .execute(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; Ok(StatusCode::CREATED) } diff --git a/services/lms-service/src/predictive.rs b/services/lms-service/src/predictive.rs index 68ca9ec..1e2dff9 100644 --- a/services/lms-service/src/predictive.rs +++ b/services/lms-service/src/predictive.rs @@ -20,7 +20,7 @@ pub async fn get_course_dropout_risks( } calculate_risks_for_course(&pool, course_id, claims.org).await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let rows = sqlx::query( r#" @@ -34,7 +34,7 @@ pub async fn get_course_dropout_risks( .bind(claims.org) .fetch_all(&pool) .await - .map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los riesgos: {}", e)))?; + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Error interno del servidor".to_string()))?; let risks: Vec = rows.into_iter().map(|row| { DropoutRisk { diff --git a/web/experience/package-lock.json b/web/experience/package-lock.json index 3dc3e96..b823912 100644 --- a/web/experience/package-lock.json +++ b/web/experience/package-lock.json @@ -15,7 +15,7 @@ "isomorphic-dompurify": "^3.10.0", "lodash": "^4.17.21", "lucide-react": "^0.395.0", - "mermaid": "^9.1.7", + "mermaid": "^11.14.0", "next": "^14.2.35", "react": "^18", "react-dom": "^18", @@ -50,6 +50,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@asamuzakjp/css-color": { "version": "5.1.11", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", @@ -371,9 +384,9 @@ } }, "node_modules/@braintree/sanitize-url": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", - "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", "license": "MIT" }, "node_modules/@bramus/specificity": { @@ -388,6 +401,43 @@ "specificity": "bin/cli.js" } }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz", + "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "12.0.0", + "@chevrotain/types": "12.0.0" + } + }, + "node_modules/@chevrotain/gast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz", + "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "12.0.0" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz", + "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz", + "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz", + "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==", + "license": "Apache-2.0" + }, "node_modules/@csstools/color-helpers": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", @@ -472,7 +522,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -519,7 +568,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -667,6 +715,23 @@ "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.1.tgz", + "integrity": "sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.2" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -713,6 +778,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz", + "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", + "license": "MIT", + "dependencies": { + "langium": "^4.0.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -1037,24 +1111,159 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", "license": "MIT" }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", @@ -1070,6 +1279,24 @@ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, "node_modules/@types/d3-scale": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", @@ -1079,6 +1306,18 @@ "@types/d3-time": "*" } }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, "node_modules/@types/d3-shape": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", @@ -1094,12 +1333,37 @@ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -1133,6 +1397,12 @@ "@types/estree": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -1182,13 +1452,14 @@ "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==" + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true }, "node_modules/@types/react": { "version": "18.3.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "peer": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -1266,7 +1537,6 @@ "integrity": "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", @@ -1759,13 +2029,21 @@ "win32" ] }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2187,7 +2465,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2363,6 +2640,34 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chevrotain": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz", + "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "12.0.0", + "@chevrotain/gast": "12.0.0", + "@chevrotain/regexp-to-ast": "12.0.0", + "@chevrotain/types": "12.0.0", + "@chevrotain/utils": "12.0.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.1.tgz", + "integrity": "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^12.0.0" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -2455,6 +2760,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2462,6 +2773,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2504,7 +2824,56 @@ "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true + }, + "node_modules/cytoscape": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.2.tgz", + "integrity": "sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" }, "node_modules/d3": { "version": "7.9.0", @@ -2596,12 +2965,6 @@ "node": ">=12" } }, - "node_modules/d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", - "license": "BSD-3-Clause" - }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", @@ -2804,6 +3167,46 @@ "node": ">=12" } }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", @@ -2838,7 +3241,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -2907,12 +3309,6 @@ "d3-selection": "2 - 3" } }, - "node_modules/d3-voronoi": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==", - "license": "BSD-3-Clause" - }, "node_modules/d3-zoom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", @@ -2929,339 +3325,14 @@ "node": ">=12" } }, - "node_modules/dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "license": "MIT", "dependencies": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/dagre-d3": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/dagre-d3/-/dagre-d3-0.6.4.tgz", - "integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==", - "license": "MIT", - "dependencies": { - "d3": "^5.14", - "dagre": "^0.8.5", - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/dagre-d3/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/dagre-d3/node_modules/d3": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", - "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "1", - "d3-axis": "1", - "d3-brush": "1", - "d3-chord": "1", - "d3-collection": "1", - "d3-color": "1", - "d3-contour": "1", - "d3-dispatch": "1", - "d3-drag": "1", - "d3-dsv": "1", - "d3-ease": "1", - "d3-fetch": "1", - "d3-force": "1", - "d3-format": "1", - "d3-geo": "1", - "d3-hierarchy": "1", - "d3-interpolate": "1", - "d3-path": "1", - "d3-polygon": "1", - "d3-quadtree": "1", - "d3-random": "1", - "d3-scale": "2", - "d3-scale-chromatic": "1", - "d3-selection": "1", - "d3-shape": "1", - "d3-time": "1", - "d3-time-format": "2", - "d3-timer": "1", - "d3-transition": "1", - "d3-voronoi": "1", - "d3-zoom": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-axis": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", - "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-brush": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", - "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "1", - "d3-path": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-contour": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", - "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^1.1.1" - } - }, - "node_modules/dagre-d3/node_modules/d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-drag": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", - "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-dsv": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", - "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", - "license": "BSD-3-Clause", - "dependencies": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json", - "csv2tsv": "bin/dsv2dsv", - "dsv2dsv": "bin/dsv2dsv", - "dsv2json": "bin/dsv2json", - "json2csv": "bin/json2dsv", - "json2dsv": "bin/json2dsv", - "json2tsv": "bin/json2dsv", - "tsv2csv": "bin/dsv2dsv", - "tsv2json": "bin/dsv2json" - } - }, - "node_modules/dagre-d3/node_modules/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-fetch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", - "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dsv": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-force": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", - "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-format": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-polygon": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", - "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-quadtree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", - "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-random": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", - "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-scale": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", - "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "node_modules/dagre-d3/node_modules/d3-scale-chromatic": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", - "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1", - "d3-interpolate": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", - "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-time-format": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", - "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-time": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", - "license": "BSD-3-Clause" - }, - "node_modules/dagre-d3/node_modules/d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-zoom": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "node_modules/dagre-d3/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "d3": "^7.9.0", + "lodash-es": "^4.17.21" } }, "node_modules/damerau-levenshtein": { @@ -3344,6 +3415,12 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -3733,7 +3810,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -4574,14 +4650,11 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.15" - } + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" }, "node_modules/has-bigints": { "version": "1.1.0", @@ -5357,7 +5430,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5486,6 +5558,31 @@ "node": ">=4.0" } }, + "node_modules/katex": { + "version": "0.16.45", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz", + "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5500,6 +5597,24 @@ "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" }, + "node_modules/langium": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.2.tgz", + "integrity": "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==", + "license": "MIT", + "dependencies": { + "@chevrotain/regexp-to-ast": "~12.0.0", + "chevrotain": "~12.0.0", + "chevrotain-allstar": "~0.4.1", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -5518,6 +5633,12 @@ "node": ">=0.10" } }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5570,6 +5691,12 @@ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5615,6 +5742,18 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5793,28 +5932,34 @@ } }, "node_modules/mermaid": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.7.tgz", - "integrity": "sha512-MRVHXy5FLjnUQUG7YS3UN9jEN6FXCJbFCXVGJQjVIbiR6Vhw0j/6pLIjqsiah9xoHmQU6DEaKOvB3S1g/1nBPA==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", + "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", "license": "MIT", "dependencies": { - "@braintree/sanitize-url": "^6.0.0", - "d3": "^7.0.0", - "dagre": "^0.8.5", - "dagre-d3": "^0.6.4", - "dompurify": "2.4.0", - "graphlib": "^2.1.8", - "khroma": "^2.0.0", - "moment-mini": "2.24.0", - "stylis": "^4.0.10" + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.0", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" } }, - "node_modules/mermaid/node_modules/dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==", - "license": "(MPL-2.0 OR Apache-2.0)" - }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -6292,11 +6437,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/moment-mini": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.24.0.tgz", - "integrity": "sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ==", - "license": "MIT" + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } }, "node_modules/motion-dom": { "version": "11.18.1", @@ -6654,6 +6805,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6703,6 +6860,12 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6736,6 +6899,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6772,6 +6941,33 @@ "node": ">= 6" } }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -6801,7 +6997,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6954,7 +7149,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -7093,7 +7287,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -7105,7 +7298,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7118,7 +7310,7 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "peer": true + "dev": true }, "node_modules/react-markdown": { "version": "10.1.0", @@ -7152,7 +7344,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -7226,8 +7417,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -7419,6 +7609,18 @@ "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8053,6 +8255,15 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -8092,7 +8303,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8187,6 +8397,15 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -8313,7 +8532,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8346,6 +8564,12 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -8554,6 +8778,19 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -8604,6 +8841,55 @@ "d3-timer": "^3.0.1" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -8803,7 +9089,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/experience/package.json b/web/experience/package.json index ac7aa5f..029b6df 100644 --- a/web/experience/package.json +++ b/web/experience/package.json @@ -20,7 +20,7 @@ "isomorphic-dompurify": "^3.10.0", "lodash": "^4.17.21", "lucide-react": "^0.395.0", - "mermaid": "^9.1.7", + "mermaid": "^11.14.0", "next": "^14.2.35", "react": "^18", "react-dom": "^18", diff --git a/web/experience/src/app/courses/[id]/lessons/[lessonId]/page.tsx b/web/experience/src/app/courses/[id]/lessons/[lessonId]/page.tsx index 3809c5a..05b6e5c 100644 --- a/web/experience/src/app/courses/[id]/lessons/[lessonId]/page.tsx +++ b/web/experience/src/app/courses/[id]/lessons/[lessonId]/page.tsx @@ -145,6 +145,7 @@ export default function LessonPlayerPage({ params }: { params: { id: string, les } return [...prev, res]; }); + } catch (err) { console.error(`Failed to submit score for block ${blockId}`, err); } } diff --git a/web/experience/src/components/blocks/PeerReviewPlayer.tsx b/web/experience/src/components/blocks/PeerReviewPlayer.tsx index 4e52e80..efc8b3f 100644 --- a/web/experience/src/components/blocks/PeerReviewPlayer.tsx +++ b/web/experience/src/components/blocks/PeerReviewPlayer.tsx @@ -323,262 +323,3 @@ export default function PeerReviewPlayer({ courseId, lessonId, block }: PeerRevi ); } - - -interface PeerReviewPlayerProps { - courseId: string; - lessonId: string; - block: Block; -} - -export default function PeerReviewPlayer({ courseId, lessonId, block }: PeerReviewPlayerProps) { - const [view, setView] = useState<'submit' | 'dashboard' | 'reviewing'>('submit'); - const [submissionContent, setSubmissionContent] = useState(""); - const [mySubmission, setMySubmission] = useState(null); - const [peerAssignment, setPeerAssignment] = useState(null); - const [feedbackReceived, setFeedbackReceived] = useState([]); - - // Review form state - const [reviewScore, setReviewScore] = useState(80); - const [reviewFeedback, setReviewFeedback] = useState(""); - const [loading, setLoading] = useState(false); - const [message, setMessage] = useState(""); - - // Initial check - do we have a submission? - // We don't have an endpoint for "get my submission" directly in the list I made, - // but I can infer it or try to fetch feedback. - // Actually, I missed adding "get my submission" endpoint. - // Additionaly `getPeerReviewAssignment` excludes my own. - // For now, let's assume if I can fetch feedback, I have submitted. - // Or I can add a check endpoint. - // Let's try to fetch feedback first. - - useEffect(() => { - const checkStatus = async () => { - // For simplify, we just check feedback. If error or empty, maybe no submission? - // Actually, `getMySubmissionFeedback` returns array. - try { - const reviews = await lmsApi.getMySubmissionFeedback(courseId, lessonId); - setFeedbackReceived(reviews); - // If we get reviews (or even empty array), it implies we might have submitted? - // Not necessarily. - // I should have added `getMySubmission`. - // But for now, let's rely on local storage or just show "Submit" if no local state. - // Ideally backend check. - } catch (err) { - // Error might mean not authorized or something. - } - }; - checkStatus(); - }, [courseId, lessonId]); - - // Workaround: We will use a "saved" state in localStorage for "submitted" to avoid needing another endpoint right now, - // or better: just try to submit. If it says "already submitted", handle it? - // The backend `submit_assignment` UPDATES if exists. So it's safe to show form with previous content if we had it. - // But we don't have "get my content". - - // Let's add a "View my submission" button if I assume I submitted? - // Maybe just show the dashboard if I have feedback. - - const handleSubmit = async () => { - setLoading(true); - try { - const sub = await lmsApi.submitAssignment(courseId, lessonId, submissionContent); - setMySubmission(sub); - setView('dashboard'); - setMessage("Submission saved successfully!"); - } catch (err: any) { - setMessage("Failed to submit: " + err.message); - } finally { - setLoading(false); - } - }; - - const handleStartReview = async () => { - setLoading(true); - try { - const assignment = await lmsApi.getPeerReviewAssignment(courseId, lessonId); - if (!assignment) { - setMessage("No assignments available for review at the moment. Please try again later."); - } else { - setPeerAssignment(assignment); - setView('reviewing'); - setMessage(""); - } - } catch (err: any) { - setMessage("Error fetching assignment: " + err.message); - } finally { - setLoading(false); - } - }; - - const handleSubmitReview = async () => { - if (!peerAssignment) return; - setLoading(true); - try { - await lmsApi.submitPeerReview(courseId, lessonId, peerAssignment.id, reviewScore, reviewFeedback); - setMessage("Review submitted successfully! Thank you."); - setPeerAssignment(null); - setReviewFeedback(""); - setView('dashboard'); - } catch (err: any) { - setMessage("Failed to submit review: " + err.message); - } finally { - setLoading(false); - } - }; - - if (view === 'reviewing' && peerAssignment) { - return ( -
- -
-

Reviewing Peer Submission

-
- {peerAssignment.content} -
-
- -
-

Your Feedback

- - {block.reviewCriteria && ( -
- Criteria: {block.reviewCriteria} -
- )} - -
- - setReviewScore(parseInt(e.target.value))} - className="bg-black/20 border border-white/10 rounded-lg px-4 py-2 text-white w-24" - /> -
- -
- -