using CalendarReminder.Api.Data; using CalendarReminder.Api.Models; using CalendarReminder.Api.Services; using CalendarReminder.Domain.Entities; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace CalendarReminder.Api.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly AppDbContext _db; private readonly TokenService _tokenService; private readonly EmailService _emailService; public AuthController(AppDbContext db, TokenService tokenService, EmailService emailService) { _db = db; _tokenService = tokenService; _emailService = emailService; } // POST api/auth/register (interný endpoint — nie je vystavený vo frontende) [HttpPost("register")] public async Task Register(RegisterRequest req) { if (await _db.Users.AnyAsync(u => u.Email == req.Email)) return BadRequest("Email je už registrovaný."); if (await _db.Users.AnyAsync(u => u.Username == req.Username)) return BadRequest("Používateľské meno je obsadené."); var user = new User { Username = req.Username, Email = req.Email, PasswordHash = BCrypt.Net.BCrypt.HashPassword(req.Password) }; _db.Users.Add(user); await _db.SaveChangesAsync(); var token = _tokenService.GenerateToken(user); return Ok(new AuthResponse(token, user.Username, user.Email, user.IsAdmin, user.MustChangePassword)); } // POST api/auth/login [HttpPost("login")] public async Task Login(LoginRequest req) { // Podpor prihlásenie cez email aj username var user = await _db.Users.FirstOrDefaultAsync(u => u.Email == req.Email || u.Username == req.Email); if (user is null || !BCrypt.Net.BCrypt.Verify(req.Password, user.PasswordHash)) return Unauthorized("Nesprávny email/meno alebo heslo."); var token = _tokenService.GenerateToken(user); return Ok(new AuthResponse(token, user.Username, user.Email, user.IsAdmin, user.MustChangePassword)); } // POST api/auth/send-reset-code // Vygeneruje 8-znakový kód a odošle ho emailom (pre budúce použitie) [HttpPost("send-reset-code")] public async Task SendResetCode([FromBody] SendResetCodeRequest req) { var user = await _db.Users.FirstOrDefaultAsync(u => u.Email == req.Email); if (user is null) return BadRequest("Email neexistuje."); // Zneplatni staré tokeny var old = _db.PasswordResetTokens.Where(t => t.Email == req.Email && !t.Used); _db.PasswordResetTokens.RemoveRange(old); // Vygeneruj nový 8-znakový kód const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; var rng = new Random(); var code = new string(Enumerable.Range(0, 8).Select(_ => chars[rng.Next(chars.Length)]).ToArray()); _db.PasswordResetTokens.Add(new PasswordResetToken { Email = req.Email, Code = code, ExpiresAt = DateTime.UtcNow.AddMinutes(30), Used = false }); await _db.SaveChangesAsync(); await _emailService.SendAsync(req.Email, user.Username, "🔑 Obnova hesla — Calendar Reminder", $"""

🔑 Obnova hesla

Tvoj kód na obnovu hesla:

{code}

Kód je platný 30 minút. Ak si o reset nepožiadal, ignoruj tento email.

"""); return Ok("Kód bol odoslaný na email."); } // POST api/auth/reset-password [HttpPost("reset-password")] public async Task ResetPassword([FromBody] ResetPasswordRequest req) { var user = await _db.Users.FirstOrDefaultAsync(u => u.Email == req.Email); if (user is null) return BadRequest("Email neexistuje."); // Ak je kód zadaný — over ho if (!string.IsNullOrEmpty(req.Code)) { var resetToken = await _db.PasswordResetTokens .Where(t => t.Email == req.Email && !t.Used && t.ExpiresAt > DateTime.UtcNow) .OrderByDescending(t => t.ExpiresAt) .FirstOrDefaultAsync(); if (resetToken is null || resetToken.Code != req.Code.ToUpper()) return BadRequest("Nesprávny alebo expirovaný kód."); resetToken.Used = true; } user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(req.NewPassword); await _db.SaveChangesAsync(); return Ok("Heslo bolo úspešne zmenené."); } } public record SendResetCodeRequest(string Email); public record ResetPasswordRequest(string Email, string NewPassword, string? Code);