139 lines
5.5 KiB
C#
139 lines
5.5 KiB
C#
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<IActionResult> 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<IActionResult> 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<IActionResult> 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",
|
|
$"""
|
|
<div style="font-family:Segoe UI,sans-serif;max-width:480px;margin:auto;background:#161b22;color:#e1e4e8;border-radius:10px;overflow:hidden">
|
|
<div style="background:#1f6feb;padding:1.2rem 1.5rem">
|
|
<h2 style="margin:0;color:#fff;font-size:1.1rem">🔑 Obnova hesla</h2>
|
|
</div>
|
|
<div style="padding:1.5rem">
|
|
<p style="margin:0 0 1rem">Tvoj kód na obnovu hesla:</p>
|
|
<div style="background:#0d1117;border:1px solid #30363d;border-radius:8px;padding:1rem;text-align:center;font-size:2rem;font-weight:700;letter-spacing:0.4rem;color:#58a6ff">{code}</div>
|
|
<p style="margin:1rem 0 0;color:#8b949e;font-size:0.85rem">Kód je platný 30 minút. Ak si o reset nepožiadal, ignoruj tento email.</p>
|
|
</div>
|
|
</div>
|
|
""");
|
|
|
|
return Ok("Kód bol odoslaný na email.");
|
|
}
|
|
|
|
// POST api/auth/reset-password
|
|
[HttpPost("reset-password")]
|
|
public async Task<IActionResult> 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);
|
|
user.MustChangePassword = false;
|
|
await _db.SaveChangesAsync();
|
|
|
|
return Ok("Heslo bolo úspešne zmenené.");
|
|
}
|
|
}
|
|
|
|
public record SendResetCodeRequest(string Email);
|
|
public record ResetPasswordRequest(string Email, string NewPassword, string? Code);
|