Remove build_errors.txt and validate_auth.sh scripts; clean up unused imports and fix type inference issues in lms-service.
This commit is contained in:
@@ -1,372 +0,0 @@
|
||||
# OpenCCB - Resumen de Configuración y Despliegue
|
||||
## Fecha: 26 de Marzo de 2026
|
||||
|
||||
---
|
||||
|
||||
## 📋 Resumen del Proyecto
|
||||
|
||||
**OpenCCB** es una plataforma LMS/CMS de código abierto desplegada en **AWS EC2** con nginx-proxy para SSL automático.
|
||||
|
||||
**Servidor AWS:**
|
||||
- **Host**: `ec2-18-224-137-67.us-east-2.compute.amazonaws.com`
|
||||
- **Usuario**: `ubuntu`
|
||||
- **SSH Key**: `ubuntu.pem`
|
||||
- **Región**: us-east-2 (Ohio)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuración Actual
|
||||
|
||||
### Dominios
|
||||
- `studio.norteamericano.com` - CMS/Admin
|
||||
- `learning.norteamericano.com` - LMS/Estudiantes
|
||||
|
||||
### Arquitectura
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ AWS EC2 │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ nginx │───▶│ Studio + CMS │ │
|
||||
│ │ proxy │ │ (Next.js + Rust) │ │
|
||||
│ │ :80, :443 │ │ :3000, :3001 │ │
|
||||
│ └──────┬──────┘ └──────────┬───────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ acme │ │ Experience + LMS │ │
|
||||
│ │ companion │ │ (Next.js + Rust) │ │
|
||||
│ │ (Let's │ │ :3003, :3002 │ │
|
||||
│ │ Encrypt) │ └──────────┬───────────────┘ │
|
||||
│ └─────────────┘ │ │
|
||||
│ │ │
|
||||
│ ┌──────────▼───────────────┐ │
|
||||
│ │ PostgreSQL + PGVector │ │
|
||||
│ │ :5432 │ │
|
||||
│ └──────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Comandos de Despliegue
|
||||
|
||||
### Desde tu máquina local:
|
||||
|
||||
```bash
|
||||
# Ejecutar deploy
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
El script preguntará:
|
||||
1. Nombre del administrador
|
||||
2. Email del administrador
|
||||
3. Contraseña (oculta)
|
||||
4. Nombre de la organización
|
||||
5. ¿Usar SSL? [y/N]
|
||||
- **y**: Usará HTTPS (con o sin staging)
|
||||
- **N**: Usará HTTP (recomendado para staging)
|
||||
6. ¿Usar STAGING? [y/N] (solo si elegiste SSL)
|
||||
- **y**: Certificados de prueba (sin rate limits)
|
||||
- **N**: Certificados reales (con rate limits)
|
||||
|
||||
### Conexión al servidor:
|
||||
|
||||
```bash
|
||||
ssh -i "ubuntu.pem" ubuntu@ec2-18-224-137-67.us-east-2.compute.amazonaws.com
|
||||
cd /var/www/openccb
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Problemas Conocidos y Soluciones
|
||||
|
||||
### 1. Login Pegado / Error de Conexión API
|
||||
|
||||
**Problema**: El botón de login se queda procesando infinitamente.
|
||||
|
||||
**Causa**: Las URLs de la API incluyen el puerto `:3001` incorrectamente.
|
||||
|
||||
**Solución Aplicada**:
|
||||
- Actualizado `web/studio/src/lib/api.ts` para hardcodear las URLs de producción
|
||||
- El código ahora detecta el hostname y usa la URL sin puerto
|
||||
|
||||
**Comandos para Solucionar**:
|
||||
```bash
|
||||
# Conectarse al servidor
|
||||
ssh -i "ubuntu.pem" ubuntu@ec2-18-224-137-67.us-east-2.compute.amazonaws.com
|
||||
cd /var/www/openccb
|
||||
|
||||
# Detener todo
|
||||
sudo docker compose down
|
||||
|
||||
# Eliminar imágenes cacheadas
|
||||
sudo docker rmi openccb-studio 2>/dev/null || true
|
||||
sudo docker images | grep openccb | awk '{print $3}' | xargs sudo docker rmi -f 2>/dev/null || true
|
||||
|
||||
# Limpiar caché de Docker
|
||||
sudo docker builder prune -af
|
||||
sudo docker system prune -af
|
||||
|
||||
# Reconstruir DESDE CERO (CRÍTICO usar --no-cache)
|
||||
sudo docker compose build --no-cache studio
|
||||
|
||||
# Iniciar todo
|
||||
sudo docker compose up -d
|
||||
|
||||
# Esperar 1 minuto
|
||||
sleep 60
|
||||
|
||||
# Verificar
|
||||
sudo docker compose ps
|
||||
docker logs openccb-studio --tail 20
|
||||
```
|
||||
|
||||
**Verificación en el Navegador**:
|
||||
1. Abrir ventana de incógnito (Ctrl+Shift+N)
|
||||
2. Ir a `http://studio.norteamericano.com`
|
||||
3. Abrir consola (F12) → Pestaña Network
|
||||
4. Intentar loguearse
|
||||
5. Verificar que la URL sea: `http://studio.norteamericano.com/auth/login` (SIN puerto)
|
||||
|
||||
### 2. Rate Limit de Let's Encrypt
|
||||
|
||||
**Problema**: Se alcanzó el límite de 5 certificados por semana.
|
||||
|
||||
**Solución Temporal**:
|
||||
- Usar HTTP en lugar de HTTPS
|
||||
- O usar Let's Encrypt Staging (certificados de prueba)
|
||||
|
||||
**Fecha de Reinicio**: 2026-03-27 04:21:42 UTC
|
||||
|
||||
---
|
||||
|
||||
## 📁 Archivos Modificados
|
||||
|
||||
### 1. `deploy.sh`
|
||||
- ✅ Pregunta datos del administrador
|
||||
- ✅ Pregunta sobre SSL y Staging
|
||||
- ✅ Actualiza docker-compose.yml según elección (HTTP/HTTPS)
|
||||
- ✅ Reconstruye contenedores con `--no-cache`
|
||||
- ✅ Verifica variables de entorno en los contenedores
|
||||
- ✅ Muestra URLs correctas según protocolo elegido
|
||||
|
||||
### 2. `docker-compose.yml`
|
||||
- ✅ URLs en HTTP por defecto
|
||||
- ✅ Ambos argumentos de build para studio:
|
||||
- `NEXT_PUBLIC_CMS_API_URL: http://studio.norteamericano.com`
|
||||
- `NEXT_PUBLIC_LMS_API_URL: http://learning.norteamericano.com`
|
||||
- ✅ Variables de entorno correctas
|
||||
|
||||
### 3. `web/studio/Dockerfile`
|
||||
- ✅ Agrega `ARG NEXT_PUBLIC_LMS_API_URL`
|
||||
- ✅ Agrega `ENV NEXT_PUBLIC_LMS_API_URL`
|
||||
|
||||
### 4. `web/studio/src/lib/api.ts`
|
||||
- ✅ Corrige función `getApiBaseUrl` para producción
|
||||
- ✅ Hardcodea URLs para `studio.norteamericano.com` y `learning.norteamericano.com`
|
||||
- ✅ Elimina el puerto de las URLs en producción
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Credenciales (Ejemplo)
|
||||
|
||||
**Usuario Administrador**:
|
||||
- Email: `admin@norteamericano.com`
|
||||
- Contraseña: `Admin123!` (o la que se haya configurado)
|
||||
|
||||
**Base de Datos** (en `/var/www/openccb/.env`):
|
||||
```
|
||||
DB_PASSWORD=<generada_aleatoriamente>
|
||||
JWT_SECRET=<generada_aleatoriamente>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Comandos Útiles
|
||||
|
||||
### Ver estado de servicios
|
||||
```bash
|
||||
sudo docker compose ps
|
||||
```
|
||||
|
||||
### Ver logs
|
||||
```bash
|
||||
# Todos los servicios
|
||||
sudo docker compose logs -f
|
||||
|
||||
# Servicio específico
|
||||
docker logs openccb-studio --tail 50
|
||||
docker logs openccb-experience --tail 50
|
||||
docker logs acme-companion --tail 50
|
||||
```
|
||||
|
||||
### Verificar variables de entorno
|
||||
```bash
|
||||
# Studio
|
||||
sudo docker exec openccb-studio env | grep NEXT_PUBLIC
|
||||
|
||||
# Experience
|
||||
sudo docker exec openccb-experience env | grep NEXT_PUBLIC
|
||||
|
||||
# Debería mostrar:
|
||||
# NEXT_PUBLIC_CMS_API_URL=http://studio.norteamericano.com
|
||||
# NEXT_PUBLIC_LMS_API_URL=http://learning.norteamericano.com
|
||||
```
|
||||
|
||||
### Reconstruir contenedores
|
||||
```bash
|
||||
# Todo
|
||||
sudo docker compose build --no-cache
|
||||
sudo docker compose up -d
|
||||
|
||||
# Solo studio
|
||||
sudo docker compose build --no-cache studio
|
||||
sudo docker compose up -d studio
|
||||
```
|
||||
|
||||
### Limpiar caché de Docker
|
||||
```bash
|
||||
# Limpiar builder
|
||||
sudo docker builder prune -af
|
||||
|
||||
# Limpiar sistema
|
||||
sudo docker system prune -af
|
||||
```
|
||||
|
||||
### Verificar certificados SSL
|
||||
```bash
|
||||
docker logs acme-companion --tail 50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Próximos Pasos
|
||||
|
||||
### 1. Reconstruir Studio con --no-cache
|
||||
```bash
|
||||
ssh -i "ubuntu.pem" ubuntu@ec2-18-224-137-67.us-east-2.compute.amazonaws.com
|
||||
cd /var/www/openccb
|
||||
|
||||
sudo docker compose down
|
||||
sudo docker rmi openccb-studio 2>/dev/null || true
|
||||
sudo docker builder prune -af
|
||||
sudo docker compose build --no-cache studio
|
||||
sudo docker compose up -d
|
||||
sleep 60
|
||||
sudo docker compose ps
|
||||
```
|
||||
|
||||
### 2. Probar Login
|
||||
- Abrir ventana de incógnito
|
||||
- Ir a `http://studio.norteamericano.com`
|
||||
- Ver consola (F12) → Network
|
||||
- Verificar URL: `http://studio.norteamericano.com/auth/login`
|
||||
- Intentar loguearse
|
||||
|
||||
### 3. Verificar Funcionalidades
|
||||
- [ ] Login de administrador
|
||||
- [ ] Creación de cursos
|
||||
- [ ] Subida de archivos
|
||||
- [ ] Integración con LMS
|
||||
- [ ] Certificados SSL generados
|
||||
|
||||
### 4. Cambiar a HTTPS (Después del Rate Limit)
|
||||
```bash
|
||||
# Después del 2026-03-27
|
||||
./deploy.sh
|
||||
# Responder "y" a "¿Usar SSL?"
|
||||
# Responder "n" a "¿Usar STAGING?"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Solución de Problemas Comunes
|
||||
|
||||
### Login se queda procesando
|
||||
```bash
|
||||
# Verificar URL en consola del navegador
|
||||
# Debe ser: http://studio.norteamericano.com/auth/login
|
||||
# NO debe tener :3001
|
||||
|
||||
# Si tiene puerto, reconstruir con --no-cache
|
||||
sudo docker compose build --no-cache studio
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
### Error 502 Bad Gateway
|
||||
```bash
|
||||
# Verificar que los servicios están corriendo
|
||||
sudo docker compose ps
|
||||
|
||||
# Ver logs
|
||||
docker logs openccb-studio --tail 50
|
||||
docker logs nginx-proxy --tail 50
|
||||
|
||||
# Reiniciar
|
||||
sudo docker compose restart
|
||||
```
|
||||
|
||||
### Variables NEXT_PUBLIC faltantes
|
||||
```bash
|
||||
# Ver docker-compose.yml
|
||||
cat docker-compose.yml | grep -A 10 "studio:"
|
||||
|
||||
# Verificar en contenedor
|
||||
sudo docker exec openccb-studio env | grep NEXT_PUBLIC
|
||||
|
||||
# Reconstruir
|
||||
sudo docker compose build --no-cache studio
|
||||
```
|
||||
|
||||
### Certificados SSL no se generan
|
||||
```bash
|
||||
# Ver logs
|
||||
docker logs acme-companion --tail 100
|
||||
|
||||
# Verificar DNS
|
||||
dig studio.norteamericano.com
|
||||
dig learning.norteamericano.com
|
||||
|
||||
# Verificar puertos
|
||||
sudo netstat -tlnp | grep :80
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notas Importantes
|
||||
|
||||
1. **HTTP vs HTTPS**: Actualmente se usa HTTP porque:
|
||||
- Los certificados de staging no son válidos para producción
|
||||
- Las llamadas API entre dominios requieren HTTP o certificados válidos
|
||||
|
||||
2. **Rate Limit**: Let's Encrypt permite 5 certificados por semana por dominio. El límite se reinicia el 2026-03-27.
|
||||
|
||||
3. **--no-cache es CRÍTICO**: Siempre usar `--no-cache` al reconstruir Studio para que los cambios en el código se apliquen. Docker usa caché por defecto.
|
||||
|
||||
4. **Ventana de Incógnito**: Después de reconstruir, siempre probar en ventana de incógnito para evitar caché del navegador.
|
||||
|
||||
5. **URLs Hardcodeadas**: El código ahora tiene las URLs de producción hardcodeadas para `studio.norteamericano.com` y `learning.norteamericano.com`. Esto evita problemas con variables de entorno.
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contacto y Soporte
|
||||
|
||||
**Documentación**:
|
||||
- `DESPLIEGUE.md` - Instrucciones de despliegue
|
||||
- `README.md` - Documentación general
|
||||
- `docker-compose.yml` - Configuración de servicios
|
||||
|
||||
**Archivos de Configuración**:
|
||||
- `/var/www/openccb/.env` - Variables de entorno
|
||||
- `/var/www/openccb/docker-compose.yml` - Servicios Docker
|
||||
- `web/studio/Dockerfile` - Build de Studio
|
||||
- `web/studio/src/lib/api.ts` - Configuración de APIs
|
||||
- `deploy.sh` - Script de despliegue
|
||||
|
||||
---
|
||||
|
||||
**Última Actualización**: 26 de Marzo de 2026
|
||||
**Estado**: ✅ Solución aplicada - Pendiente reconstruir con --no-cache y probar login
|
||||
@@ -1,468 +0,0 @@
|
||||
# OpenCCB - Project Context
|
||||
|
||||
## Project Overview
|
||||
|
||||
**OpenCCB (Open Comprehensive Course Backbone)** is an open-source Learning Management System (LMS) and Content Management System (CMS) platform built for performance, security, and scalability. It provides a complete infrastructure for course creation, student management, and AI-powered learning features.
|
||||
|
||||
### Architecture
|
||||
|
||||
The project uses a **unified container architecture** with the following structure:
|
||||
|
||||
| Service | Ports | Description |
|
||||
|---------|-------|-------------|
|
||||
| **Studio + CMS** | 3000/3001 | Next.js admin frontend + Rust CMS API |
|
||||
| **Experience + LMS** | 3003/3002 | Next.js student frontend + Rust LMS API |
|
||||
| **Database** | 5433 | PostgreSQL 16 (shared, separate DBs: `openccb_cms`, `openccb_lms`) |
|
||||
|
||||
### Technology Stack
|
||||
|
||||
**Backend:**
|
||||
- Rust Edition 2024 (workspace with 3 crates)
|
||||
- Web Framework: Axum 0.8
|
||||
- Database: SQLx 0.8 with PostgreSQL 16
|
||||
- Authentication: JWT (jsonwebtoken 9.3), bcrypt
|
||||
- Security: HMAC, SHA2, OpenID Connect (SSO)
|
||||
- Rate Limiting: tower-governor 0.7
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 14 (App Router)
|
||||
- React 18 + TypeScript 5
|
||||
- Styling: Tailwind CSS 3.4
|
||||
- UI: Lucide React, Framer Motion, React Markdown
|
||||
- Mermaid diagrams for dynamic visualization
|
||||
|
||||
**Infrastructure:**
|
||||
- Docker & Docker Compose
|
||||
- Single-tenant design (premium module)
|
||||
- Local AI: Ollama (Llama 3.2) + Faster-Whisper
|
||||
|
||||
**Key Features:**
|
||||
- AI-powered course generation and quiz creation
|
||||
- Discussion forums with nested replies
|
||||
- LTI 1.3 Tool Provider (Canvas, Moodle integration)
|
||||
- Monetization via Mercado Pago
|
||||
- Live learning with Jitsi integration
|
||||
- Student portfolios with Open Badges
|
||||
- Predictive analytics (dropout risk detection)
|
||||
- Multi-language support (EN, ES, PT)
|
||||
- Gamification (XP, levels, badges, leaderboards)
|
||||
- **Semantic search with PGVector** (question bank, knowledge base)
|
||||
- **RAG-enhanced AI tutor** with contextual retrieval
|
||||
- **MySQL integration** (study plans, courses import)
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
openccb/
|
||||
├── services/
|
||||
│ ├── cms-service/ # Rust CMS API (course management, content creation)
|
||||
│ │ ├── migrations/ # SQLx database migrations
|
||||
│ │ └── src/
|
||||
│ └── lms-service/ # Rust LMS API (student experience, grades)
|
||||
│ └── src/
|
||||
├── shared/
|
||||
│ └── common/ # Shared Rust library (auth, models, utils)
|
||||
├── web/
|
||||
│ ├── studio/ # Next.js CMS frontend (admin/instructor)
|
||||
│ └── experience/ # Next.js LMS frontend (student)
|
||||
├── e2e/ # Playwright end-to-end tests
|
||||
├── scripts/ # Utility scripts (auth, database)
|
||||
└── [config files]
|
||||
```
|
||||
|
||||
### Rust Workspace Members
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = [
|
||||
"services/cms-service",
|
||||
"services/lms-service",
|
||||
"shared/common",
|
||||
]
|
||||
```
|
||||
|
||||
## Building and Running
|
||||
|
||||
### Docker (Recommended)
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up --build
|
||||
|
||||
# Start in detached mode
|
||||
docker-compose up -d
|
||||
|
||||
# Rebuild and start
|
||||
docker-compose up -d --build
|
||||
|
||||
# Clean install (removes volumes)
|
||||
docker-compose down -v && docker-compose up --build
|
||||
|
||||
# Run E2E tests
|
||||
docker-compose --profile test up e2e
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
**Prerequisites:**
|
||||
- Rust (Edition 2024)
|
||||
- Node.js 18+
|
||||
- PostgreSQL 16
|
||||
- sqlx-cli: `cargo install sqlx-cli --no-default-features --features postgres`
|
||||
|
||||
**Backend (Rust):**
|
||||
|
||||
```bash
|
||||
# CMS Service (port 3001)
|
||||
cd services/cms-service
|
||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms cargo run
|
||||
|
||||
# LMS Service (port 3002)
|
||||
cd services/lms-service
|
||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_lms cargo run
|
||||
|
||||
# With debug logging
|
||||
RUST_LOG=debug cargo run -p cms-service
|
||||
```
|
||||
|
||||
**Frontend (Next.js):**
|
||||
|
||||
```bash
|
||||
# Studio (CMS Frontend - port 3000)
|
||||
cd web/studio
|
||||
npm install
|
||||
npm run dev
|
||||
|
||||
# Experience (LMS Frontend - port 3003)
|
||||
cd web/experience
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Installation Script
|
||||
|
||||
```bash
|
||||
# Full installation with database setup
|
||||
./install.sh
|
||||
|
||||
# Fast mode (skip dependency checks)
|
||||
./install.sh --fast
|
||||
```
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Code Quality
|
||||
|
||||
```bash
|
||||
# Frontend linting and formatting
|
||||
cd web/studio && npm run lint:fix
|
||||
cd web/studio && npm run format
|
||||
cd web/studio && npm run type-check
|
||||
|
||||
# Same commands available in web/experience
|
||||
```
|
||||
|
||||
### Database Management
|
||||
|
||||
```bash
|
||||
# Reset database (delete and recreate)
|
||||
./reset_db.sh
|
||||
|
||||
# Run migrations manually
|
||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms \
|
||||
sqlx migrate run --source services/cms-service/migrations
|
||||
|
||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_lms \
|
||||
sqlx migrate run --source services/lms-service/migrations
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
```bash
|
||||
# CMS Service
|
||||
curl http://localhost:3001/health
|
||||
curl http://localhost:3001/health/live
|
||||
curl http://localhost:3001/health/ready
|
||||
|
||||
# LMS Service
|
||||
curl http://localhost:3002/health
|
||||
curl http://localhost:3002/health/live
|
||||
curl http://localhost:3002/health/ready
|
||||
```
|
||||
|
||||
### Utilities
|
||||
|
||||
```bash
|
||||
# Generate secure JWT secret
|
||||
./generate_jwt_secret.sh
|
||||
|
||||
# Clear session
|
||||
./clear_session.sh
|
||||
|
||||
# Validate authentication
|
||||
./validate_auth.sh
|
||||
|
||||
# Diagnose auth issues
|
||||
./diagnose_auth.sh
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Authentication (CMS - port 3001)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/auth/register` | Create new user |
|
||||
| POST | `/auth/login` | Login and get JWT token |
|
||||
| GET | `/auth/profile` | Get current user profile |
|
||||
|
||||
### Course Management (CMS)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/courses` | Create course |
|
||||
| POST | `/courses/generate` | AI-generate course structure |
|
||||
| GET | `/courses/{id}/export` | Export course to JSON |
|
||||
| POST | `/courses/import` | Import course from JSON |
|
||||
| DELETE | `/courses/{id}` | Delete course |
|
||||
| POST | `/lessons` | Add lesson to module |
|
||||
| POST | `/assets/upload` | Upload media/document |
|
||||
|
||||
### Learning Experience (LMS - port 3002)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/enroll` | Enroll in course |
|
||||
| POST | `/grades` | Submit lesson score |
|
||||
| GET | `/notifications` | Get user notifications |
|
||||
| POST | `/notifications/{id}/read` | Mark notification as read |
|
||||
|
||||
### Discussion Forums (LMS)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| GET | `/courses/{id}/discussions` | List threads |
|
||||
| POST | `/courses/{id}/discussions` | Create thread |
|
||||
| GET | `/discussions/{id}` | Get thread with replies |
|
||||
| POST | `/discussions/{id}/posts` | Reply to thread |
|
||||
| POST | `/posts/{id}/vote` | Vote on post |
|
||||
| POST | `/posts/{id}/endorse` | Mark post as correct (instructor) |
|
||||
|
||||
### AI Features
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/lessons/{id}/transcribe` | Start transcription |
|
||||
| POST | `/lessons/{id}/generate-quiz` | Generate quiz with AI |
|
||||
| POST | `/lessons/{id}/chat` | Chat with lesson tutor |
|
||||
| GET | `/lessons/{id}/feedback` | Get AI feedback |
|
||||
| GET | `/courses/{id}/dropout-risks` | Get dropout risk analysis |
|
||||
| POST | `/question-bank/embeddings/generate` | Generate embeddings for questions |
|
||||
| POST | `/question-bank/{id}/embedding/regenerate` | Regenerate question embedding |
|
||||
| GET | `/question-bank/semantic-search` | Search questions semantically |
|
||||
| GET | `/question-bank/similar/{id}` | Find similar questions (duplicates) |
|
||||
| POST | `/question-bank/generate-with-rag` | Generate question with RAG + 4 skills |
|
||||
| POST | `/knowledge-base/embeddings/generate` | Generate knowledge base embeddings |
|
||||
| GET | `/knowledge-base/semantic-search` | Search knowledge base semantically |
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
Copy `.env.example` to `.env` and configure:
|
||||
|
||||
```bash
|
||||
# Database
|
||||
CMS_DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms
|
||||
LMS_DATABASE_URL=postgresql://user:password@localhost:5433/openccb_lms
|
||||
|
||||
# JWT Secret (generate with ./generate_jwt_secret.sh)
|
||||
JWT_SECRET=your_secure_secret
|
||||
|
||||
# AI Configuration
|
||||
AI_PROVIDER=local
|
||||
LOCAL_WHISPER_URL=http://localhost:9000
|
||||
LOCAL_OLLAMA_URL=http://localhost:11434
|
||||
LOCAL_LLM_MODEL=llama3.2:3b
|
||||
EMBEDDING_MODEL=nomic-embed-text
|
||||
|
||||
# Frontend URLs
|
||||
NEXT_PUBLIC_CMS_API_URL=http://localhost:3001
|
||||
NEXT_PUBLIC_LMS_API_URL=http://localhost:3002
|
||||
|
||||
# Backend-to-backend (LMS -> CMS)
|
||||
CMS_API_URL=http://studio:3001
|
||||
```
|
||||
|
||||
### Default Credentials
|
||||
|
||||
After running `./install.sh`, the default admin user is:
|
||||
- **Email**: `admin@norteamericano.cl`
|
||||
- **Password**: `Admin123!`
|
||||
|
||||
You can customize these during installation.
|
||||
|
||||
## Testing
|
||||
|
||||
### E2E Tests (Playwright)
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
cd e2e && npx playwright test
|
||||
|
||||
# Run with UI
|
||||
cd e2e && npx playwright test --ui
|
||||
|
||||
# Run specific test file
|
||||
cd e2e && npx playwright test tests/auth.spec.ts
|
||||
|
||||
# Generate report
|
||||
cd e2e && npx playwright show-report
|
||||
```
|
||||
|
||||
### Backend Tests
|
||||
|
||||
```bash
|
||||
# Run Rust tests
|
||||
cargo test -p cms-service
|
||||
cargo test -p lms-service
|
||||
cargo test -p common
|
||||
```
|
||||
|
||||
## Key Conventions
|
||||
|
||||
### Rust Code Style
|
||||
|
||||
- Use workspace dependencies from root `Cargo.toml`
|
||||
- Shared code goes in `shared/common`
|
||||
- Use `sqlx::query!` macros for compile-time SQL verification
|
||||
- Error handling with `thiserror` and `anyhow`
|
||||
- Tracing for logging (`tracing::info!`, `tracing::debug!`)
|
||||
|
||||
### Frontend Code Style
|
||||
|
||||
- TypeScript strict mode enabled
|
||||
- Tailwind CSS for styling
|
||||
- Lucide React for icons
|
||||
- Framer Motion for animations
|
||||
- Components in `src/components/`
|
||||
- Pages in `src/app/` (Next.js App Router)
|
||||
|
||||
### Database
|
||||
|
||||
- Separate databases for CMS and LMS
|
||||
- Migrations managed by SQLx
|
||||
- UUIDs for primary keys
|
||||
- Timestamps with timezone (timestamptz)
|
||||
|
||||
### Authentication
|
||||
|
||||
- JWT-based authentication
|
||||
- Bcrypt password hashing
|
||||
- Role-based access control (admin, instructor, student)
|
||||
- OpenID Connect support for SSO
|
||||
|
||||
## Common Issues
|
||||
|
||||
### CORS Errors (Login/Registro)
|
||||
|
||||
Si ves errores de CORS al intentar loguearte:
|
||||
|
||||
```
|
||||
Access to fetch at 'http://localhost:3001/auth/login' from origin 'http://localhost:3000'
|
||||
has been blocked by CORS policy
|
||||
```
|
||||
|
||||
**Solución**: Asegúrate de que el rate limiter NO esté aplicado a las rutas de autenticación.
|
||||
En `services/cms-service/src/main.rs`, el `GovernorLayer` debe estar solo en `protected_routes`,
|
||||
no en `public_routes`.
|
||||
|
||||
### Rate Limiter Bloqueando Peticiones
|
||||
|
||||
**Estado actual**: El rate limiter (`tower_governor`) está **deshabilitado** debido a problemas de compatibilidad con el middleware de autenticación.
|
||||
|
||||
Si quieres habilitarlo en producción:
|
||||
|
||||
1. Agrega `GovernorLayer` solo a rutas protegidas usando `.route_layer()`
|
||||
2. Configúralo después del middleware de autenticación
|
||||
3. Ajusta los límites (por defecto: 10 req/s, burst 50)
|
||||
|
||||
```rust
|
||||
.protected_routes
|
||||
.route_layer(middleware::from_fn(org_extractor_middleware))
|
||||
.route_layer(GovernorLayer { config: governor_conf })
|
||||
```
|
||||
|
||||
**Advertencia**: Si el rate limiter está mal configurado, las peticiones a `/courses`, `/auth/login`, etc. pueden fallar con error 500 sin logs.
|
||||
|
||||
### Port Conflicts
|
||||
|
||||
If port 5432 is occupied, the setup uses 5433:
|
||||
```bash
|
||||
# Check if port is in use
|
||||
lsof -i :5432
|
||||
lsof -i :5433
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
```bash
|
||||
# Check if PostgreSQL is running
|
||||
docker ps | grep postgres
|
||||
|
||||
# Check database connectivity
|
||||
docker exec openccb-db-1 pg_isready -U user
|
||||
```
|
||||
|
||||
### PGVector Issues
|
||||
|
||||
```bash
|
||||
# Check if pgvector extension is enabled
|
||||
docker exec -it openccb-db-1 psql -U user -d openccb_cms -c "SELECT * FROM pg_extension WHERE extname = 'vector';"
|
||||
|
||||
# If not enabled, run migration
|
||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms \
|
||||
sqlx migrate run --source services/cms-service/migrations
|
||||
```
|
||||
|
||||
### Embedding Generation Issues
|
||||
|
||||
```bash
|
||||
# Check if Ollama is running
|
||||
curl http://localhost:11434/api/tags
|
||||
|
||||
# Pull embedding model
|
||||
docker exec -it ollama ollama pull nomic-embed-text
|
||||
|
||||
# Test embedding generation
|
||||
curl -X POST http://localhost:11434/api/embeddings \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model": "nomic-embed-text", "prompt": "Hello world"}'
|
||||
```
|
||||
|
||||
### Frontend Build Issues
|
||||
|
||||
```bash
|
||||
# Clear Next.js cache
|
||||
rm -rf web/studio/.next
|
||||
rm -rf web/experience/.next
|
||||
|
||||
# Reinstall dependencies
|
||||
cd web/studio && rm -rf node_modules && npm install
|
||||
```
|
||||
|
||||
### Rust Compilation Issues
|
||||
|
||||
```bash
|
||||
# Clean and rebuild
|
||||
cargo clean
|
||||
cargo build
|
||||
|
||||
# Update dependencies
|
||||
cargo update
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- `README.md` - Comprehensive user documentation with API manual
|
||||
- `OPTIMIZATIONS.md` - Performance optimizations implemented
|
||||
- `roadmap.md` - Project roadmap and feature status
|
||||
- `diagnose_auth.sh` - Authentication debugging script
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
const { Client } = require('pg');
|
||||
|
||||
async function checkEnrollments() {
|
||||
const client = new Client({
|
||||
connectionString: "postgresql://user:password@localhost:5432/openccb_lms"
|
||||
});
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
console.log("Connected to LMS DB");
|
||||
|
||||
console.log("\n--- Users ---");
|
||||
const users = await client.query("SELECT id, email, organization_id, full_name FROM users");
|
||||
console.table(users.rows);
|
||||
|
||||
console.log("\n--- Enrollments ---");
|
||||
const enrollments = await client.query("SELECT id, user_id, course_id, organization_id FROM enrollments");
|
||||
console.table(enrollments.rows);
|
||||
|
||||
console.log("\n--- Courses ---");
|
||||
const courses = await client.query("SELECT id, title, organization_id FROM courses");
|
||||
console.table(courses.rows);
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error:", err);
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
}
|
||||
|
||||
checkEnrollments();
|
||||
@@ -1,74 +0,0 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function checkMySQL() {
|
||||
try {
|
||||
const conn = await mysql.createConnection('mysql://root:Smith3976!@ec2-18-222-25-254.us-east-2.compute.amazonaws.com:3306/sige_sam_v3');
|
||||
console.log('Conectado a MySQL\n');
|
||||
|
||||
// Mostrar tablas
|
||||
const [tables] = await conn.query('SHOW TABLES');
|
||||
console.log('=== TABLAS ===');
|
||||
console.table(tables);
|
||||
|
||||
// Estructura de curso
|
||||
console.log('\n=== ESTRUCTURA DE curso ===');
|
||||
const [cursoCols] = await conn.query('DESCRIBE curso');
|
||||
console.table(cursoCols);
|
||||
|
||||
// Estructura de plandeestudios
|
||||
console.log('\n=== ESTRUCTURA DE plandeestudios ===');
|
||||
const [planCols] = await conn.query('DESCRIBE plandeestudios');
|
||||
console.table(planCols);
|
||||
|
||||
// Ver algunos cursos de ejemplo
|
||||
console.log('\n=== CURSOS (ejemplo) ===');
|
||||
const [cursos] = await conn.query('SELECT * FROM curso LIMIT 5');
|
||||
console.table(cursos);
|
||||
|
||||
// Ver planes de estudio
|
||||
console.log('\n=== PLANES DE ESTUDIO (ejemplo) ===');
|
||||
const [planes] = await conn.query('SELECT * FROM plandeestudios LIMIT 5');
|
||||
console.table(planes);
|
||||
|
||||
// Buscar tabla con idDetalleContrato
|
||||
console.log('\n=== Buscando tablas con idDetalleContrato ===');
|
||||
const [detalleTables] = await conn.query(`
|
||||
SELECT TABLE_NAME, COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'sige_sam_v3'
|
||||
AND COLUMN_NAME LIKE '%idDetalle%'
|
||||
`);
|
||||
console.table(detalleTables);
|
||||
|
||||
// Estructura de detallecontrato
|
||||
console.log('\n=== ESTRUCTURA DE detallecontrato ===');
|
||||
const [detalleCols] = await conn.query('DESCRIBE detallecontrato');
|
||||
console.table(detalleCols);
|
||||
|
||||
// Estructura de prueba (banco de preguntas)
|
||||
console.log('\n=== ESTRUCTURA DE prueba ===');
|
||||
const [pruebaCols] = await conn.query('DESCRIBE prueba');
|
||||
console.table(pruebaCols);
|
||||
|
||||
// Ver algunos detallecontrato
|
||||
console.log('\n=== DETALLE CONTRATO (ejemplo) ===');
|
||||
const [detalles] = await conn.query('SELECT * FROM detallecontrato LIMIT 5');
|
||||
console.table(detalles);
|
||||
|
||||
// Ver banco de preguntas
|
||||
console.log('\n=== BANCO DE PREGUNTAS (ejemplo) ===');
|
||||
const [preguntas] = await conn.query('SELECT * FROM bancopreguntas LIMIT 5');
|
||||
console.table(preguntas);
|
||||
|
||||
// Ver tipo_nota
|
||||
console.log('\n=== TIPO NOTA ===');
|
||||
const [tiposNota] = await conn.query('SELECT * FROM tiponota');
|
||||
console.table(tiposNota);
|
||||
|
||||
await conn.end();
|
||||
} catch (err) {
|
||||
console.error('Error:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
checkMySQL();
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Script para limpiar tokens antiguos y forzar re-login
|
||||
|
||||
echo "=== Limpiando tokens antiguos de localStorage ==="
|
||||
echo ""
|
||||
echo "Por favor, ejecuta esto en la consola del navegador (F12 → Console):"
|
||||
echo ""
|
||||
echo "localStorage.removeItem('studio_token');"
|
||||
echo "localStorage.removeItem('studio_user');"
|
||||
echo "location.reload();"
|
||||
echo ""
|
||||
echo "Luego vuelve a hacer login con:"
|
||||
echo " Email: juan.allende@gmail.com"
|
||||
echo " Password: apoca11"
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
echo "=== DIAGNÓSTICO DE AUTENTICACIÓN ==="
|
||||
echo ""
|
||||
|
||||
# 1. Verificar que el backend acepta login
|
||||
echo "1. Probando LOGIN directo al backend..."
|
||||
RESPONSE=$(curl -s -X POST http://localhost:3001/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"juan.allende@gmail.com","password":"password123"}')
|
||||
|
||||
TOKEN=$(echo $RESPONSE | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "❌ ERROR: No se pudo obtener token del backend"
|
||||
echo "Respuesta: $RESPONSE"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Token obtenido exitosamente"
|
||||
echo "Token: ${TOKEN:0:50}..."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "2. Probando acceso a /courses CON el token..."
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
http://localhost:3001/courses)
|
||||
|
||||
if [ "$HTTP_CODE" -eq 200 ]; then
|
||||
echo "✅ Acceso a /courses exitoso (200)"
|
||||
else
|
||||
echo "❌ Acceso a /courses falló con código: $HTTP_CODE"
|
||||
# Mostrar respuesta completa
|
||||
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3001/courses
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "3. Verificando JWT_SECRET en el contenedor..."
|
||||
JWT_SECRET=$(docker exec openccb-studio-1 env | grep JWT_SECRET | cut -d'=' -f2)
|
||||
echo "JWT_SECRET actual: $JWT_SECRET"
|
||||
|
||||
echo ""
|
||||
echo "=== INSTRUCCIONES ==="
|
||||
echo "Si el test 2 fue exitoso, el problema está en el navegador."
|
||||
echo "Ejecuta en la consola del navegador (F12):"
|
||||
echo ""
|
||||
echo " localStorage.clear();"
|
||||
echo " location.reload();"
|
||||
echo ""
|
||||
echo "Luego vuelve a hacer login."
|
||||
@@ -1 +0,0 @@
|
||||
Invalid credentials
|
||||
Generated
-301
@@ -1,301 +0,0 @@
|
||||
{
|
||||
"name": "openccb",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"mysql2": "^3.20.0",
|
||||
"pg": "^8.17.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
|
||||
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-ssl-profiles": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-function": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
|
||||
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-property": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru.min": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz",
|
||||
"integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=1.30.0",
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wellwelwel"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.20.0.tgz",
|
||||
"integrity": "sha512-eCLUs7BNbgA6nf/MZXsaBO1SfGs0LtLVrJD3WeWq+jPLDWkSufTD+aGMwykfUVPdZnblaUK1a8G/P63cl9FkKg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-ssl-profiles": "^1.1.2",
|
||||
"denque": "^2.1.0",
|
||||
"generate-function": "^2.3.1",
|
||||
"iconv-lite": "^0.7.2",
|
||||
"long": "^5.3.2",
|
||||
"lru.min": "^1.1.4",
|
||||
"named-placeholders": "^1.1.6",
|
||||
"sql-escaper": "^1.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/named-placeholders": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz",
|
||||
"integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lru.min": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.17.2",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.17.2.tgz",
|
||||
"integrity": "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.10.1",
|
||||
"pg-pool": "^3.11.0",
|
||||
"pg-protocol": "^1.11.0",
|
||||
"pg-types": "2.2.0",
|
||||
"pgpass": "1.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"pg-cloudflare": "^1.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg-native": ">=3.0.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pg-cloudflare": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz",
|
||||
"integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.10.1.tgz",
|
||||
"integrity": "sha512-iNzslsoeSH2/gmDDKiyMqF64DATUCWj3YJ0wP14kqcsf2TUklwimd+66yYojKwZCA7h2yRNLGug71hCBA2a4sw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-pool": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.11.0.tgz",
|
||||
"integrity": "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"pg": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.11.0.tgz",
|
||||
"integrity": "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pgpass": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"split2": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-bytea": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
|
||||
"integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/sql-escaper": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.3.3.tgz",
|
||||
"integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=2.0.0",
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"mysql2": "^3.20.0",
|
||||
"pg": "^8.17.2"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,620 +0,0 @@
|
||||
Checking lms-service v0.1.0 (/home/juan/dev/openccb/services/lms-service)
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers.rs:154:22
|
||||
|
|
||||
154 | let categories = sqlx::query!(
|
||||
| ______________________^
|
||||
155 | | "SELECT id, name FROM grading_categories WHERE course_id = $1 ORDER BY name",
|
||||
156 | | course_id
|
||||
157 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers.rs:163:20
|
||||
|
|
||||
163 | let students = sqlx::query!(
|
||||
| ____________________^
|
||||
164 | | r#"
|
||||
165 | | SELECT
|
||||
166 | | u.id,
|
||||
... |
|
||||
180 | | org_ctx.id
|
||||
181 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers.rs:193:27
|
||||
|
|
||||
193 | let detailed_grades = sqlx::query_as!(
|
||||
| ___________________________^
|
||||
194 | | UserCategoryGrade,
|
||||
195 | | r#"
|
||||
196 | | SELECT
|
||||
... |
|
||||
205 | | course_id
|
||||
206 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers.rs:896:24
|
||||
|
|
||||
896 | let dependencies = sqlx::query_as!(
|
||||
| ________________________^
|
||||
897 | | LessonDependency,
|
||||
898 | | r#"
|
||||
899 | | SELECT ld.*
|
||||
... |
|
||||
905 | | id
|
||||
906 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers.rs:1004:30
|
||||
|
|
||||
1004 | let unmet_dependencies = sqlx::query!(
|
||||
| ______________________________^
|
||||
1005 | | r#"
|
||||
1006 | | SELECT ld.prerequisite_lesson_id, p.title as prereq_title, ld.min_score_percentage
|
||||
1007 | | FROM lesson_dependencies ld
|
||||
... |
|
||||
1020 | | claims.sub
|
||||
1021 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_announcements.rs:55:23
|
||||
|
|
||||
55 | let cohorts = sqlx::query!(
|
||||
| _______________________^
|
||||
56 | | "SELECT cohort_id FROM announcement_cohorts WHERE announcement_id = $1",
|
||||
57 | | a.id
|
||||
58 | | )
|
||||
| |_________^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:21:46
|
||||
|
|
||||
21 | let existing: Option<CourseSubmission> = sqlx::query_as!(
|
||||
| ______________________________________________^
|
||||
22 | | CourseSubmission,
|
||||
23 | | "SELECT * FROM course_submissions WHERE user_id = $1 AND lesson_id = $2",
|
||||
24 | | claims.sub,
|
||||
25 | | lesson_id
|
||||
26 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:33:23
|
||||
|
|
||||
33 | let updated = sqlx::query_as!(
|
||||
| _______________________^
|
||||
34 | | CourseSubmission,
|
||||
35 | | r#"
|
||||
36 | | UPDATE course_submissions
|
||||
... |
|
||||
43 | | lesson_id
|
||||
44 | | )
|
||||
| |_________^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:53:22
|
||||
|
|
||||
53 | let submission = sqlx::query_as!(
|
||||
| ______________________^
|
||||
54 | | CourseSubmission,
|
||||
55 | | r#"
|
||||
56 | | INSERT INTO course_submissions (user_id, course_id, lesson_id, organization_id, content)
|
||||
... |
|
||||
64 | | payload.content
|
||||
65 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:83:22
|
||||
|
|
||||
83 | let submission = sqlx::query_as!(
|
||||
| ______________________^
|
||||
84 | | CourseSubmission,
|
||||
85 | | r#"
|
||||
86 | | SELECT s.*
|
||||
... |
|
||||
105 | | org_ctx.id
|
||||
106 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:122:22
|
||||
|
|
||||
122 | let submission = sqlx::query!(
|
||||
| ______________________^
|
||||
123 | | "SELECT user_id FROM course_submissions WHERE id = $1",
|
||||
124 | | payload.submission_id
|
||||
125 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:143:20
|
||||
|
|
||||
143 | let existing = sqlx::query!(
|
||||
| ____________________^
|
||||
144 | | "SELECT id FROM peer_reviews WHERE submission_id = $1 AND reviewer_id = $2",
|
||||
145 | | payload.submission_id,
|
||||
146 | | claims.sub
|
||||
147 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:160:18
|
||||
|
|
||||
160 | let review = sqlx::query_as!(
|
||||
| __________________^
|
||||
161 | | PeerReview,
|
||||
162 | | r#"
|
||||
163 | | INSERT INTO peer_reviews (submission_id, reviewer_id, score, feedback, organization_id)
|
||||
... |
|
||||
171 | | org_ctx.id
|
||||
172 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: error communicating with database: Connection refused (os error 111)
|
||||
--> services/lms-service/src/handlers_peer_review.rs:187:19
|
||||
|
|
||||
187 | let reviews = sqlx::query_as!(
|
||||
| ___________________^
|
||||
188 | | PeerReview,
|
||||
189 | | r#"
|
||||
190 | | SELECT pr.*
|
||||
... |
|
||||
196 | | lesson_id
|
||||
197 | | )
|
||||
| |_____^
|
||||
|
|
||||
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0412]: cannot find type `AnalyticsFilter` in module `common::models`
|
||||
--> services/lms-service/src/handlers.rs:1736:42
|
||||
|
|
||||
1736 | Query(filter): Query<common::models::AnalyticsFilter>,
|
||||
| ^^^^^^^^^^^^^^^ not found in `common::models`
|
||||
|
||||
error[E0412]: cannot find type `RecommendationResponse` in this scope
|
||||
--> services/lms-service/src/handlers.rs:1802:18
|
||||
|
|
||||
1802 | ) -> Result<Json<RecommendationResponse>, (StatusCode, String)> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this struct
|
||||
|
|
||||
1 + use common::models::RecommendationResponse;
|
||||
|
|
||||
|
||||
error[E0412]: cannot find type `RecommendationResponse` in this scope
|
||||
--> services/lms-service/src/handlers.rs:1945:22
|
||||
|
|
||||
1945 | let ai_response: RecommendationResponse = response
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this struct
|
||||
|
|
||||
1 + use common::models::RecommendationResponse;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find function `dangerous_insecure_decode` in crate `jsonwebtoken`
|
||||
--> services/lms-service/src/lti.rs:107:51
|
||||
|
|
||||
107 | let claims: serde_json::Value = jsonwebtoken::dangerous_insecure_decode(&payload.id_token)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `jsonwebtoken`
|
||||
|
||||
warning: unused imports: `SubmitAssignmentPayload` and `SubmitPeerReviewPayload`
|
||||
--> services/lms-service/src/handlers.rs:12:44
|
||||
|
|
||||
12 | Module, Notification, Organization, SubmitAssignmentPayload, SubmitPeerReviewPayload, User, UserResponse,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: unused import: `crate::lti`
|
||||
--> services/lms-service/src/handlers.rs:14:5
|
||||
|
|
||||
14 | use crate::lti;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:154:22
|
||||
|
|
||||
154 | let categories = sqlx::query!(
|
||||
| ______________________^
|
||||
155 | | "SELECT id, name FROM grading_categories WHERE course_id = $1 ORDER BY name",
|
||||
156 | | course_id
|
||||
... |
|
||||
159 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:160:15
|
||||
|
|
||||
160 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
160 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:163:20
|
||||
|
|
||||
163 | let students = sqlx::query!(
|
||||
| ____________________^
|
||||
164 | | r#"
|
||||
165 | | SELECT
|
||||
166 | | u.id,
|
||||
... |
|
||||
182 | | .fetch_all(&pool)
|
||||
183 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:184:15
|
||||
|
|
||||
184 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
184 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:193:27
|
||||
|
|
||||
193 | let detailed_grades = sqlx::query_as!(
|
||||
| ___________________________^
|
||||
194 | | UserCategoryGrade,
|
||||
195 | | r#"
|
||||
196 | | SELECT
|
||||
... |
|
||||
207 | | .fetch_all(&pool)
|
||||
208 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:209:15
|
||||
|
|
||||
209 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
209 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:896:24
|
||||
|
|
||||
896 | let dependencies = sqlx::query_as!(
|
||||
| ________________________^
|
||||
897 | | LessonDependency,
|
||||
898 | | r#"
|
||||
899 | | SELECT ld.*
|
||||
... |
|
||||
907 | | .fetch_all(&pool)
|
||||
908 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:1004:30
|
||||
|
|
||||
1004 | let unmet_dependencies = sqlx::query!(
|
||||
| ______________________________^
|
||||
1005 | | r#"
|
||||
1006 | | SELECT ld.prerequisite_lesson_id, p.title as prereq_title, ld.min_score_percentage
|
||||
1007 | | FROM lesson_dependencies ld
|
||||
... |
|
||||
1022 | | .fetch_all(&pool)
|
||||
1023 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0277]: the trait bound `for<'r> DailyProgress: FromRow<'r, _>` is not satisfied
|
||||
--> services/lms-service/src/handlers.rs:1461:49
|
||||
|
|
||||
1461 | let daily_completions = sqlx::query_as::<_, common::models::DailyProgress>(
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> FromRow<'r, _>` is not implemented for `DailyProgress`
|
||||
|
|
||||
= help: the following other types implement trait `FromRow<'r, R>`:
|
||||
`()` implements `FromRow<'r, R>`
|
||||
`(T1, T2)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3, T4)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3, T4, T5)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3, T4, T5, T6)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3, T4, T5, T6, T7)` implements `FromRow<'r, R>`
|
||||
`(T1, T2, T3, T4, T5, T6, T7, T8)` implements `FromRow<'r, R>`
|
||||
and 58 others
|
||||
note: required by a bound in `sqlx::query_as`
|
||||
--> /home/juan/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/sqlx-core-0.8.6/src/query_as.rs:345:8
|
||||
|
|
||||
342 | pub fn query_as<'q, DB, O>(sql: &'q str) -> QueryAs<'q, DB, O, <DB as Database>::Arguments<'q>>
|
||||
| -------- required by a bound in this function
|
||||
...
|
||||
345 | O: for<'r> FromRow<'r, DB::Row>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `query_as`
|
||||
|
||||
error[E0599]: the method `fetch_all` exists for struct `QueryAs<'_, Postgres, DailyProgress, PgArguments>`, but its trait bounds were not satisfied
|
||||
--> services/lms-service/src/handlers.rs:1476:6
|
||||
|
|
||||
1461 | let daily_completions = sqlx::query_as::<_, common::models::DailyProgress>(
|
||||
| _____________________________-
|
||||
1462 | | r#"
|
||||
1463 | | SELECT
|
||||
1464 | | TO_CHAR(created_at, 'YYYY-MM-DD') as date,
|
||||
... |
|
||||
1475 | | .bind(org_ctx.id)
|
||||
1476 | | .fetch_all(&pool)
|
||||
| | -^^^^^^^^^ method cannot be called on `QueryAs<'_, Postgres, DailyProgress, PgArguments>` due to unsatisfied trait bounds
|
||||
| |_____|
|
||||
|
|
||||
|
|
||||
::: /home/juan/dev/openccb/shared/common/src/models.rs:349:1
|
||||
|
|
||||
349 | pub struct DailyProgress {
|
||||
| ------------------------ doesn't satisfy `DailyProgress: FromRow<'r, PgRow>`
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`DailyProgress: FromRow<'r, PgRow>`
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers.rs:1461:29
|
||||
|
|
||||
1461 | let daily_completions = sqlx::query_as::<_, common::models::DailyProgress>(
|
||||
| _____________________________^
|
||||
1462 | | r#"
|
||||
1463 | | SELECT
|
||||
1464 | | TO_CHAR(created_at, 'YYYY-MM-DD') as date,
|
||||
... |
|
||||
1476 | | .fetch_all(&pool)
|
||||
1477 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_announcements.rs:55:23
|
||||
|
|
||||
55 | let cohorts = sqlx::query!(
|
||||
| _______________________^
|
||||
56 | | "SELECT cohort_id FROM announcement_cohorts WHERE announcement_id = $1",
|
||||
57 | | a.id
|
||||
... |
|
||||
60 | | .await
|
||||
| |______________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_announcements.rs:61:19
|
||||
|
|
||||
61 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
61 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:21:46
|
||||
|
|
||||
21 | let existing: Option<CourseSubmission> = sqlx::query_as!(
|
||||
| ______________________________________________^
|
||||
22 | | CourseSubmission,
|
||||
23 | | "SELECT * FROM course_submissions WHERE user_id = $1 AND lesson_id = $2",
|
||||
24 | | claims.sub,
|
||||
... |
|
||||
27 | | .fetch_optional(&pool)
|
||||
28 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:29:15
|
||||
|
|
||||
29 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
29 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:33:23
|
||||
|
|
||||
33 | let updated = sqlx::query_as!(
|
||||
| _______________________^
|
||||
34 | | CourseSubmission,
|
||||
35 | | r#"
|
||||
36 | | UPDATE course_submissions
|
||||
... |
|
||||
45 | | .fetch_one(&pool)
|
||||
46 | | .await
|
||||
| |______________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:47:19
|
||||
|
|
||||
47 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
47 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:53:22
|
||||
|
|
||||
53 | let submission = sqlx::query_as!(
|
||||
| ______________________^
|
||||
54 | | CourseSubmission,
|
||||
55 | | r#"
|
||||
56 | | INSERT INTO course_submissions (user_id, course_id, lesson_id, organization_id, content)
|
||||
... |
|
||||
66 | | .fetch_one(&pool)
|
||||
67 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:68:15
|
||||
|
|
||||
68 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
68 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:83:22
|
||||
|
|
||||
83 | let submission = sqlx::query_as!(
|
||||
| ______________________^
|
||||
84 | | CourseSubmission,
|
||||
85 | | r#"
|
||||
86 | | SELECT s.*
|
||||
... |
|
||||
107 | | .fetch_optional(&pool)
|
||||
108 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:109:15
|
||||
|
|
||||
109 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
109 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:122:22
|
||||
|
|
||||
122 | let submission = sqlx::query!(
|
||||
| ______________________^
|
||||
123 | | "SELECT user_id FROM course_submissions WHERE id = $1",
|
||||
124 | | payload.submission_id
|
||||
... |
|
||||
127 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:128:15
|
||||
|
|
||||
128 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
128 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:143:20
|
||||
|
|
||||
143 | let existing = sqlx::query!(
|
||||
| ____________________^
|
||||
144 | | "SELECT id FROM peer_reviews WHERE submission_id = $1 AND reviewer_id = $2",
|
||||
145 | | payload.submission_id,
|
||||
146 | | claims.sub
|
||||
147 | | )
|
||||
148 | | .fetch_optional(&pool)
|
||||
149 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:150:15
|
||||
|
|
||||
150 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
150 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:160:18
|
||||
|
|
||||
160 | let review = sqlx::query_as!(
|
||||
| __________________^
|
||||
161 | | PeerReview,
|
||||
162 | | r#"
|
||||
163 | | INSERT INTO peer_reviews (submission_id, reviewer_id, score, feedback, organization_id)
|
||||
... |
|
||||
173 | | .fetch_one(&pool)
|
||||
174 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:175:15
|
||||
|
|
||||
175 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
175 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:187:19
|
||||
|
|
||||
187 | let reviews = sqlx::query_as!(
|
||||
| ___________________^
|
||||
188 | | PeerReview,
|
||||
189 | | r#"
|
||||
190 | | SELECT pr.*
|
||||
... |
|
||||
198 | | .fetch_all(&pool)
|
||||
199 | | .await
|
||||
| |__________^ cannot infer type
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> services/lms-service/src/handlers_peer_review.rs:200:15
|
||||
|
|
||||
200 | .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
200 | .map_err(|e: /* Type */| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
| ++++++++++++
|
||||
|
||||
Some errors have detailed explanations: E0277, E0282, E0412, E0425, E0599.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
warning: `lms-service` (bin "lms-service") generated 2 warnings
|
||||
error: could not compile `lms-service` (bin "lms-service") due to 47 previous errors; 2 warnings emitted
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 1. Verificar Login de Juan
|
||||
echo "Probando Login para juan.allende@gmail.com..."
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST http://localhost:3001/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"juan.allende@gmail.com","password":"password123"}')
|
||||
|
||||
if [ "$HTTP_CODE" -eq 200 ]; then
|
||||
echo "ÉXITO: El login funcionó para juan.allende@gmail.com con password123"
|
||||
else
|
||||
echo "FALLO: El login falló con estado $HTTP_CODE"
|
||||
# Imprimir cuerpo para depuración
|
||||
curl -s -X POST http://localhost:3001/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"juan.allende@gmail.com","password":"password123"}'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 3. Verificar Contexto de Organización (Scoping de Cursos)
|
||||
echo "Probando Scoping de Cursos por Organización..."
|
||||
# Login para obtener token
|
||||
USER_DATA=$(curl -s -X POST http://localhost:3001/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"juan.allende@gmail.com","password":"password123"}')
|
||||
TOKEN=$(echo "$USER_DATA" | jq -r '.token')
|
||||
ORG_ID=$(echo "$USER_DATA" | jq -r '.user.organization_id')
|
||||
|
||||
if [ "$TOKEN" != "null" ]; then
|
||||
echo "ÉXITO: Se obtuvo el token para juan.allende@gmail.com"
|
||||
# Intentar listar cursos
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X GET http://localhost:3001/courses \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
if [ "$HTTP_CODE" -eq 200 ]; then
|
||||
echo "ÉXITO: Cursos recuperados correctamente con scope de organización"
|
||||
else
|
||||
echo "FALLO: Error al recuperar cursos (Estado: $HTTP_CODE)"
|
||||
fi
|
||||
|
||||
# 4. Verificar Cambio de Contexto de Admin (X-Organization-Id)
|
||||
# Crear una organización ficticia para probar el cambio
|
||||
echo "Probando Cambio de Contexto de Admin (X-Organization-Id)..."
|
||||
NEW_ORG_ID=$(curl -s -X POST http://localhost:3001/organizations \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name": "Prueba de Cambio de Contexto"}' | jq -r '.id')
|
||||
|
||||
if [ "$NEW_ORG_ID" != "null" ]; then
|
||||
echo "ÉXITO: Nueva organización creada ($NEW_ORG_ID)"
|
||||
# Intentar listar cursos usando el nuevo contexto de org
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X GET http://localhost:3001/courses \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "X-Organization-Id: $NEW_ORG_ID")
|
||||
|
||||
if [ "$HTTP_CODE" -eq 200 ]; then
|
||||
echo "ÉXITO: El cambio de contexto funcionó vía X-Organization-Id"
|
||||
else
|
||||
echo "FALLO: El cambio de contexto falló (Estado: $HTTP_CODE)"
|
||||
fi
|
||||
else
|
||||
echo "FALLO: No se pudo crear la organización de prueba"
|
||||
fi
|
||||
else
|
||||
echo "FALLO: No se pudo obtener el token para probar el contexto de organización"
|
||||
fi
|
||||
Reference in New Issue
Block a user