Files
CalendarReminder/CalendarReminder.Api/Controllers/AdminController.cs
T
2026-06-11 19:33:03 +02:00

177 lines
7.2 KiB
C#

using CalendarReminder.Api.Data;
using CalendarReminder.Api.Services;
using CalendarReminder.Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace CalendarReminder.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/admin")]
public class AdminController : ControllerBase
{
private readonly AppDbContext _db;
private readonly EmailService _email;
public AdminController(AppDbContext db, EmailService email)
{
_db = db;
_email = email;
}
private bool IsAdmin => User.FindFirst("isAdmin")?.Value == "true";
// ══════════════════════════════
// RODINY
// ══════════════════════════════
[HttpGet("families")]
public async Task<IActionResult> GetFamilies()
{
if (!IsAdmin) return Forbid();
var families = await _db.Families
.Include(f => f.Users)
.Select(f => new { f.Id, f.Name, MemberCount = f.Users.Count })
.ToListAsync();
return Ok(families);
}
[HttpPost("families")]
public async Task<IActionResult> CreateFamily([FromBody] FamilyRequest req)
{
if (!IsAdmin) return Forbid();
if (await _db.Families.AnyAsync(f => f.Name == req.Name))
return BadRequest("Rodina s týmto názvom už existuje.");
var family = new Family { Name = req.Name };
_db.Families.Add(family);
await _db.SaveChangesAsync();
return Ok(new { family.Id, family.Name, MemberCount = 0 });
}
[HttpPut("families/{id}")]
public async Task<IActionResult> UpdateFamily(int id, [FromBody] FamilyRequest req)
{
if (!IsAdmin) return Forbid();
var family = await _db.Families.FindAsync(id);
if (family is null) return NotFound();
if (await _db.Families.AnyAsync(f => f.Name == req.Name && f.Id != id))
return BadRequest("Názov je obsadený.");
family.Name = req.Name;
await _db.SaveChangesAsync();
return Ok(family);
}
[HttpDelete("families/{id}")]
public async Task<IActionResult> DeleteFamily(int id)
{
if (!IsAdmin) return Forbid();
var family = await _db.Families.Include(f => f.Users).FirstOrDefaultAsync(f => f.Id == id);
if (family is null) return NotFound();
if (family.Users.Any()) return BadRequest("Rodina má členov. Najprv presun alebo odstraň používateľov.");
_db.Families.Remove(family);
await _db.SaveChangesAsync();
return NoContent();
}
// ══════════════════════════════
// POUŽÍVATELIA
// ══════════════════════════════
[HttpGet("users")]
public async Task<IActionResult> GetUsers()
{
if (!IsAdmin) return Forbid();
var users = await _db.Users
.Include(u => u.Family)
.Select(u => new {
u.Id, u.Username, u.Email, u.IsAdmin,
u.MustChangePassword, u.CreatedAt,
FamilyId = u.FamilyId,
FamilyName = u.Family != null ? u.Family.Name : null
})
.ToListAsync();
return Ok(users);
}
[HttpPost("users")]
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest req)
{
if (!IsAdmin) return Forbid();
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("Meno je obsadené.");
var user = new User
{
Username = req.Username,
Email = req.Email,
FamilyId = req.FamilyId,
PasswordHash = BCrypt.Net.BCrypt.HashPassword("user"),
MustChangePassword = true
};
_db.Users.Add(user);
await _db.SaveChangesAsync();
// Email notifikácia
await _email.SendAsync(req.Email, req.Username,
"👋 Vítaj v Calendar Reminder — bol ti vytvorený účet",
$"""
<div style="font-family:Segoe UI,sans-serif;max-width:520px;margin:auto;background:#161b22;color:#e1e4e8;border-radius:10px;overflow:hidden">
<div style="background:#238636;padding:1.2rem 1.5rem">
<h2 style="margin:0;color:#fff;font-size:1.1rem">👋 Bol ti vytvorený účet</h2>
</div>
<div style="padding:1.5rem">
<p style="margin:0 0 1rem">Ahoj <strong>{req.Username}</strong>, bol ti vytvorený účet v aplikácii <strong>Calendar Reminder</strong>.</p>
<table style="width:100%;border-collapse:collapse">
<tr><td style="padding:0.4rem 0;color:#8b949e;width:80px">Meno</td><td style="padding:0.4rem 0;font-weight:600">{req.Username}</td></tr>
<tr><td style="padding:0.4rem 0;color:#8b949e">Email</td><td style="padding:0.4rem 0;font-weight:600">{req.Email}</td></tr>
<tr><td style="padding:0.4rem 0;color:#8b949e">Heslo</td><td style="padding:0.4rem 0;font-weight:600">user</td></tr>
</table>
<p style="margin:1.25rem 0 0;color:#f85149;font-size:0.88rem">⚠️ Po prvom prihlásení si zmeň heslo cez Zabudol som heslo".</p>
</div>
<div style="padding:0.75rem 1.5rem;border-top:1px solid #30363d;font-size:0.78rem;color:#6e7681">Calendar Reminder</div>
</div>
""");
return Ok(new { user.Id, user.Username, user.Email, user.FamilyId, user.MustChangePassword });
}
[HttpPut("users/{id}")]
public async Task<IActionResult> UpdateUser(int id, [FromBody] UpdateUserRequest req)
{
if (!IsAdmin) return Forbid();
var user = await _db.Users.FindAsync(id);
if (user is null) return NotFound();
if (await _db.Users.AnyAsync(u => u.Email == req.Email && u.Id != id))
return BadRequest("Email je obsadený.");
if (await _db.Users.AnyAsync(u => u.Username == req.Username && u.Id != id))
return BadRequest("Meno je obsadené.");
user.Username = req.Username;
user.Email = req.Email;
user.FamilyId = req.FamilyId;
await _db.SaveChangesAsync();
return Ok(new { user.Id, user.Username, user.Email, user.FamilyId });
}
[HttpDelete("users/{id}")]
public async Task<IActionResult> DeleteUser(int id)
{
if (!IsAdmin) return Forbid();
var myId = int.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)!.Value);
if (id == myId) return BadRequest("Nemôžeš zmazať sám seba.");
var user = await _db.Users.FindAsync(id);
if (user is null) return NotFound();
_db.Users.Remove(user);
await _db.SaveChangesAsync();
return NoContent();
}
}
public record FamilyRequest(string Name);
public record CreateUserRequest(string Username, string Email, int? FamilyId);
public record UpdateUserRequest(string Username, string Email, int? FamilyId);