feat: implement core domain models, authentication service, and UI components for the attendance system
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Asistencia.Models;
|
||||
|
||||
namespace Asistencia.Data;
|
||||
|
||||
public class AppDbContext : DbContext
|
||||
{
|
||||
public DbSet<Profesor> Profesores => Set<Profesor>();
|
||||
public DbSet<Curso> Cursos => Set<Curso>();
|
||||
public DbSet<CursoAbierto> CursosAbiertos => Set<CursoAbierto>();
|
||||
public DbSet<DetalleContrato> DetallesContrato => Set<DetalleContrato>();
|
||||
public DbSet<AsistenciaProfesor> AsistenciasProfesor => Set<AsistenciaProfesor>();
|
||||
public DbSet<AsistenciaAlumno> AsistenciasAlumno => Set<AsistenciaAlumno>();
|
||||
|
||||
public string DbPath { get; }
|
||||
|
||||
public AppDbContext()
|
||||
{
|
||||
var folder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var appFolder = Path.Combine(folder, "Asistencia");
|
||||
Directory.CreateDirectory(appFolder);
|
||||
DbPath = Path.Combine(appFolder, "asistencia.db");
|
||||
}
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||
=> options.UseSqlite($"Data Source={DbPath}");
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<CursoAbierto>()
|
||||
.HasOne(c => c.Curso)
|
||||
.WithMany()
|
||||
.HasForeignKey(c => c.IdCursos);
|
||||
|
||||
modelBuilder.Entity<DetalleContrato>()
|
||||
.HasOne(d => d.CursoAbierto)
|
||||
.WithMany()
|
||||
.HasForeignKey(d => d.IdCursoAbierto);
|
||||
|
||||
modelBuilder.Entity<AsistenciaProfesor>()
|
||||
.HasOne(a => a.CursoAbierto)
|
||||
.WithMany()
|
||||
.HasForeignKey(a => a.IdCursoAbierto);
|
||||
|
||||
modelBuilder.Entity<AsistenciaAlumno>()
|
||||
.HasKey(a => new { a.IdDetalleContrato, a.FechaAsistencia });
|
||||
|
||||
modelBuilder.Entity<AsistenciaAlumno>()
|
||||
.HasOne(a => a.DetalleContrato)
|
||||
.WithMany()
|
||||
.HasForeignKey(a => a.IdDetalleContrato);
|
||||
|
||||
SeedData(modelBuilder);
|
||||
}
|
||||
|
||||
private static void SeedData(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Profesor>().HasData(
|
||||
new Profesor
|
||||
{
|
||||
RutPasaporte = "12345678-9",
|
||||
Nombre = "Juan",
|
||||
Paterno = "Perez",
|
||||
Materno = "Gonzalez",
|
||||
Email = "juan.perez@norteamericano.cl",
|
||||
Fono = "+56912345678",
|
||||
Direccion = "Av. Providencia 1234, Santiago",
|
||||
Clave = "",
|
||||
CrearClave = true
|
||||
}
|
||||
);
|
||||
|
||||
modelBuilder.Entity<Curso>().HasData(
|
||||
new Curso { IdCursos = 1, NombreCurso = "English Basic A1" },
|
||||
new Curso { IdCursos = 2, NombreCurso = "English Intermediate B1" },
|
||||
new Curso { IdCursos = 3, NombreCurso = "English Advanced C1" }
|
||||
);
|
||||
|
||||
modelBuilder.Entity<CursoAbierto>().HasData(
|
||||
new CursoAbierto
|
||||
{
|
||||
IdCursoAbierto = 1,
|
||||
IdCursos = 1,
|
||||
Sala = "Sala 101",
|
||||
Sede = "Providencia",
|
||||
HoraInicio = "09:00",
|
||||
HoraFin = "10:30",
|
||||
FechaInicio = new DateTime(2026, 3, 1),
|
||||
FechaTermino = new DateTime(2026, 7, 31),
|
||||
ProfesorRun = "12345678-9"
|
||||
},
|
||||
new CursoAbierto
|
||||
{
|
||||
IdCursoAbierto = 2,
|
||||
IdCursos = 2,
|
||||
Sala = "Sala 202",
|
||||
Sede = "Las Condes",
|
||||
HoraInicio = "14:00",
|
||||
HoraFin = "15:30",
|
||||
FechaInicio = new DateTime(2026, 3, 1),
|
||||
FechaTermino = new DateTime(2026, 7, 31),
|
||||
ProfesorRun = "12345678-9"
|
||||
}
|
||||
);
|
||||
|
||||
modelBuilder.Entity<DetalleContrato>().HasData(
|
||||
new DetalleContrato
|
||||
{
|
||||
IdDetalleContrato = 1,
|
||||
IdCursoAbierto = 1,
|
||||
AP_Paterno = "Garcia",
|
||||
AP_Materno = "Lopez",
|
||||
Nombres = "Maria",
|
||||
Email = "maria.garcia@email.com",
|
||||
Telefono = "+56998765432"
|
||||
},
|
||||
new DetalleContrato
|
||||
{
|
||||
IdDetalleContrato = 2,
|
||||
IdCursoAbierto = 1,
|
||||
AP_Paterno = "Rodriguez",
|
||||
AP_Materno = "Soto",
|
||||
Nombres = "Carlos",
|
||||
Email = "carlos.rodriguez@email.com",
|
||||
Telefono = "+56987654321"
|
||||
},
|
||||
new DetalleContrato
|
||||
{
|
||||
IdDetalleContrato = 3,
|
||||
IdCursoAbierto = 2,
|
||||
AP_Paterno = "Martinez",
|
||||
AP_Materno = "Fernandez",
|
||||
Nombres = "Ana",
|
||||
Email = "ana.martinez@email.com",
|
||||
Telefono = "+56976543210"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Asistencia.Models;
|
||||
|
||||
namespace Asistencia.Data.Repositories;
|
||||
|
||||
public class AsistenciaRepository
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public AsistenciaRepository(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<AsistenciaProfesor?> BuscarSesionActivaAsync(int idCursoAbierto, DateTime fecha)
|
||||
{
|
||||
return await _context.AsistenciasProfesor
|
||||
.FirstOrDefaultAsync(a =>
|
||||
a.IdCursoAbierto == idCursoAbierto &&
|
||||
a.FechaAsistencia.Date == fecha.Date &&
|
||||
a.Estado == "Activa");
|
||||
}
|
||||
|
||||
public async Task<AsistenciaProfesor> IniciarSesionAsync(int idCursoAbierto, string rut, DateTime fecha, string horaInicio)
|
||||
{
|
||||
var sesion = new AsistenciaProfesor
|
||||
{
|
||||
IdCursoAbierto = idCursoAbierto,
|
||||
RutPasaporte = rut,
|
||||
FechaAsistencia = fecha,
|
||||
HoraInicio = horaInicio,
|
||||
Estado = "Activa"
|
||||
};
|
||||
_context.AsistenciasProfesor.Add(sesion);
|
||||
await _context.SaveChangesAsync();
|
||||
return sesion;
|
||||
}
|
||||
|
||||
public async Task<bool> FinalizarSesionAsync(int idSesion, string horaFin)
|
||||
{
|
||||
var sesion = await _context.AsistenciasProfesor.FindAsync(idSesion);
|
||||
if (sesion == null) return false;
|
||||
|
||||
sesion.HoraFin = horaFin;
|
||||
sesion.Estado = "Finalizada";
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<int, int>> ObtenerAsistenciaAlumnosAsync(int idCursoAbierto, DateTime fecha)
|
||||
{
|
||||
var alumnos = await _context.DetallesContrato
|
||||
.Where(d => d.IdCursoAbierto == idCursoAbierto)
|
||||
.ToListAsync();
|
||||
|
||||
var asistencias = await _context.AsistenciasAlumno
|
||||
.Where(a => alumnos.Select(al => al.IdDetalleContrato).Contains(a.IdDetalleContrato)
|
||||
&& a.FechaAsistencia.Date == fecha.Date)
|
||||
.ToListAsync();
|
||||
|
||||
return asistencias.ToDictionary(a => a.IdDetalleContrato, a => a.IdTipoAsistencia);
|
||||
}
|
||||
|
||||
public async Task GuardarAsistenciaAlumnoAsync(int idDetalleContrato, DateTime fecha, string hora, int tipoAsistencia)
|
||||
{
|
||||
var existing = await _context.AsistenciasAlumno
|
||||
.FirstOrDefaultAsync(a => a.IdDetalleContrato == idDetalleContrato
|
||||
&& a.FechaAsistencia.Date == fecha.Date);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existing.IdTipoAsistencia = tipoAsistencia;
|
||||
existing.Hora = hora;
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.AsistenciasAlumno.Add(new AsistenciaAlumno
|
||||
{
|
||||
IdDetalleContrato = idDetalleContrato,
|
||||
FechaAsistencia = fecha,
|
||||
Hora = hora,
|
||||
IdTipoAsistencia = tipoAsistencia
|
||||
});
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Asistencia.Models;
|
||||
|
||||
namespace Asistencia.Data.Repositories;
|
||||
|
||||
public class CursoRepository
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public CursoRepository(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<List<CursoAbierto>> BuscarCursosPorProfesorAsync(string profesorRun)
|
||||
{
|
||||
return await _context.CursosAbiertos
|
||||
.Include(c => c.Curso)
|
||||
.Where(c => c.ProfesorRun == profesorRun)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<CursoAbierto?> BuscarCursoAbiertoPorIdAsync(int idCursoAbierto)
|
||||
{
|
||||
return await _context.CursosAbiertos
|
||||
.Include(c => c.Curso)
|
||||
.FirstOrDefaultAsync(c => c.IdCursoAbierto == idCursoAbierto);
|
||||
}
|
||||
|
||||
public async Task<List<DetalleContrato>> BuscarAlumnosPorCursoAsync(int idCursoAbierto)
|
||||
{
|
||||
return await _context.DetallesContrato
|
||||
.Where(d => d.IdCursoAbierto == idCursoAbierto)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Asistencia.Models;
|
||||
|
||||
namespace Asistencia.Data.Repositories;
|
||||
|
||||
public class ProfesorRepository
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public ProfesorRepository(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Profesor?> BuscarPorRutAsync(string rut)
|
||||
{
|
||||
return await _context.Profesores.FirstOrDefaultAsync(p => p.RutPasaporte == rut);
|
||||
}
|
||||
|
||||
public async Task<bool> ActualizarClaveAsync(string rut, string nuevaClave)
|
||||
{
|
||||
var profesor = await _context.Profesores.FirstOrDefaultAsync(p => p.RutPasaporte == rut);
|
||||
if (profesor == null) return false;
|
||||
|
||||
profesor.Clave = nuevaClave;
|
||||
profesor.CrearClave = false;
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> ActualizarEmailAsync(string rut, string email)
|
||||
{
|
||||
var profesor = await _context.Profesores.FirstOrDefaultAsync(p => p.RutPasaporte == rut);
|
||||
if (profesor == null) return false;
|
||||
|
||||
profesor.Email = email;
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Profesor?> AutenticarAsync(string rut, string clave)
|
||||
{
|
||||
var profesor = await _context.Profesores.FirstOrDefaultAsync(p => p.RutPasaporte == rut);
|
||||
if (profesor == null) return null;
|
||||
|
||||
if (profesor.CrearClave) return null;
|
||||
|
||||
var claveDescifrada = Helpers.CryptoHelper.Desencriptar(profesor.Clave);
|
||||
return claveDescifrada == clave ? profesor : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user