Add project files.

This commit is contained in:
roman
2026-06-05 21:39:38 +02:00
parent 63bb199a1f
commit 841037013a
28 changed files with 2342 additions and 0 deletions
@@ -0,0 +1,58 @@
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;
public AuthController(AppDbContext db, TokenService tokenService)
{
_db = db;
_tokenService = tokenService;
}
// POST api/auth/register
[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));
}
// POST api/auth/login
[HttpPost("login")]
public async Task<IActionResult> Login(LoginRequest req)
{
var user = await _db.Users.FirstOrDefaultAsync(u => u.Email == req.Email);
if (user is null || !BCrypt.Net.BCrypt.Verify(req.Password, user.PasswordHash))
return Unauthorized("Nesprávny email alebo heslo.");
var token = _tokenService.GenerateToken(user);
return Ok(new AuthResponse(token, user.Username, user.Email));
}
}
@@ -0,0 +1,203 @@
using CalendarReminder.Api.Data;
using CalendarReminder.Api.Services;
using CalendarReminder.Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
namespace CalendarReminder.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class RemindersController : ControllerBase
{
private readonly AppDbContext _db;
private readonly EmailService _email;
public RemindersController(AppDbContext db, EmailService email)
{
_db = db;
_email = email;
}
private int UserId => int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
// GET api/reminders — moje + zdieľané so mnou
[HttpGet]
public async Task<IActionResult> GetAll()
{
var myId = UserId;
var reminders = await _db.Reminders
.Include(r => r.User)
.Include(r => r.Shares).ThenInclude(s => s.SharedWithUser)
.Where(r => r.UserId == myId || r.Shares.Any(s => s.SharedWithUserId == myId))
.OrderBy(r => r.ReminderDate)
.Select(r => new
{
r.Id, r.Title, r.Description, r.ReminderDate,
r.IsCompleted, r.NotificationSent, r.UserId, r.CreatedAt,
Owner = r.User!.Username,
IsOwner = r.UserId == myId,
SharedWith = r.Shares.Select(s => new { s.SharedWithUser!.Id, s.SharedWithUser.Username })
})
.ToListAsync();
return Ok(reminders);
}
// GET api/reminders/5
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var myId = UserId;
var r = await _db.Reminders
.Include(r => r.Shares)
.FirstOrDefaultAsync(r => r.Id == id &&
(r.UserId == myId || r.Shares.Any(s => s.SharedWithUserId == myId)));
return r is null ? NotFound() : Ok(r);
}
// POST api/reminders
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateReminderRequest req)
{
var reminder = new Reminder
{
Title = req.Title,
Description = req.Description,
ReminderDate = req.ReminderDate,
IsCompleted = false,
NotificationSent = false,
UserId = UserId,
CreatedAt = DateTime.UtcNow
};
_db.Reminders.Add(reminder);
await _db.SaveChangesAsync();
// Zdieľaj s vybranými používateľmi
foreach (var uid in req.ShareWithUserIds ?? [])
{
_db.ReminderShares.Add(new ReminderShare { ReminderId = reminder.Id, SharedWithUserId = uid });
}
if (req.ShareWithUserIds?.Count > 0)
await _db.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = reminder.Id }, reminder);
}
// PUT api/reminders/5
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody] UpdateReminderRequest req)
{
var reminder = await _db.Reminders
.Include(r => r.Shares)
.FirstOrDefaultAsync(r => r.Id == id && r.UserId == UserId);
if (reminder is null) return NotFound();
bool dateChanged = reminder.ReminderDate != req.ReminderDate;
reminder.Title = req.Title;
reminder.Description = req.Description;
reminder.ReminderDate = req.ReminderDate;
reminder.IsCompleted = req.IsCompleted;
if (dateChanged) reminder.NotificationSent = false;
// Aktualizuj zdieľanie
_db.ReminderShares.RemoveRange(reminder.Shares);
foreach (var uid in req.ShareWithUserIds ?? [])
_db.ReminderShares.Add(new ReminderShare { ReminderId = id, SharedWithUserId = uid });
await _db.SaveChangesAsync();
return Ok(reminder);
}
// DELETE api/reminders/5
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var reminder = await _db.Reminders
.FirstOrDefaultAsync(r => r.Id == id && r.UserId == UserId);
if (reminder is null) return NotFound();
_db.Reminders.Remove(reminder);
await _db.SaveChangesAsync();
return NoContent();
}
// POST api/reminders/5/send-email
[HttpPost("{id}/send-email")]
public async Task<IActionResult> SendEmail(int id)
{
var myId = UserId;
var reminder = await _db.Reminders
.Include(r => r.User)
.Include(r => r.Shares).ThenInclude(s => s.SharedWithUser)
.FirstOrDefaultAsync(r => r.Id == id && r.UserId == myId);
if (reminder is null) return NotFound();
if (!reminder.Shares.Any()) return BadRequest("Pripomienka nie je zdieľaná so žiadnym používateľom.");
var date = reminder.ReminderDate.ToLocalTime();
var dateStr = date.ToString("dd.MM.yyyy");
var timeStr = date.ToString("HH:mm");
var body = $"""
<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:#1f6feb;padding:1.2rem 1.5rem">
<h2 style="margin:0;color:#fff;font-size:1.1rem">📅 Calendar Reminder</h2>
</div>
<div style="padding:1.5rem">
<h3 style="margin:0 0 1rem;color:#58a6ff;font-size:1.2rem">{reminder.Title}</h3>
<table style="width:100%;border-collapse:collapse">
<tr>
<td style="padding:0.4rem 0;color:#8b949e;width:80px">Dátum</td>
<td style="padding:0.4rem 0;font-weight:600">{dateStr}</td>
</tr>
<tr>
<td style="padding:0.4rem 0;color:#8b949e">Čas</td>
<td style="padding:0.4rem 0;font-weight:600">{timeStr}</td>
</tr>
{(reminder.Description != null ? $"""
<tr>
<td style="padding:0.4rem 0;color:#8b949e;vertical-align:top">Popis</td>
<td style="padding:0.4rem 0">{reminder.Description}</td>
</tr>
""" : "")}
<tr>
<td style="padding:0.4rem 0;color:#8b949e">Od</td>
<td style="padding:0.4rem 0">{reminder.User!.Username}</td>
</tr>
</table>
</div>
<div style="padding:0.75rem 1.5rem;border-top:1px solid #30363d;font-size:0.78rem;color:#6e7681">
Calendar Reminder automatická správa
</div>
</div>
""";
var tasks = reminder.Shares
.Where(s => s.SharedWithUser != null)
.Select(s => _email.SendAsync(
s.SharedWithUser!.Email,
s.SharedWithUser.Username,
$"📅 Pripomienka: {reminder.Title} — {dateStr} {timeStr}",
body));
await Task.WhenAll(tasks);
return Ok(new { sent = reminder.Shares.Count });
}
}
public record CreateReminderRequest(
string Title,
string? Description,
DateTime ReminderDate,
List<int>? ShareWithUserIds);
public record UpdateReminderRequest(
string Title,
string? Description,
DateTime ReminderDate,
bool IsCompleted,
List<int>? ShareWithUserIds);
@@ -0,0 +1,34 @@
using CalendarReminder.Api.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace CalendarReminder.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly AppDbContext _db;
public UsersController(AppDbContext db) => _db = db;
// GET api/users?search=jan
[HttpGet]
public async Task<IActionResult> Search([FromQuery] string? search)
{
var myId = int.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)!.Value);
var query = _db.Users.Where(u => u.Id != myId);
if (!string.IsNullOrWhiteSpace(search))
query = query.Where(u => u.Username.Contains(search) || u.Email.Contains(search));
var users = await query
.Select(u => new { u.Id, u.Username, u.Email })
.Take(20)
.ToListAsync();
return Ok(users);
}
}