diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index be8be59..debbc55 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -22,6 +22,7 @@ public class AuthController : ControllerBase _appsettings = appsettings; } + // POST /api/v1/auth/login [HttpPost("login")] public async Task Login([FromBody] UserLoginDTO formUser, GeneralUseHelpers guhf) { @@ -48,6 +49,7 @@ public class AuthController : ControllerBase } else return Unauthorized(new {status = "error", error_msg = "Unknown pair of email and password"}); } + // GET /api/v1/auth/some_values [HttpGet("some_values")] [Authorize] public IActionResult GetValues() diff --git a/Controllers/QuoteAddController.cs b/Controllers/QuoteAddController.cs deleted file mode 100644 index d171711..0000000 --- a/Controllers/QuoteAddController.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Authorization; -using QuotifyBE.Data; -using QuotifyBE.Entities; -using System.Security.Claims; -using Microsoft.EntityFrameworkCore; - -namespace QuotifyBE.Controllers -{ - [ApiController] - [Route("controller")] - - public class QuotesController : ControllerBase - { - private readonly ApplicationDbContext _db; - - public QuotesController(ApplicationDbContext db) - { - _db = db; - } - - [HttpPost] - [Authorize(Roles = "Admin")] - public async Task CreateQuote([FromBody] CreateQuoteRequest request) - { - // Get user ID from claims - var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; - if (userIdClaim == null || !int.TryParse(userIdClaim, out int userId)) - return Unauthorized("Invalid user ID"); - - // Find or create image - Image? image = null; - if (!string.IsNullOrEmpty(request.ImageUrl)) - { - image = await _db.Images.FirstOrDefaultAsync(i => i.Url == request.ImageUrl); - if (image == null) - { - image = new Image { Url = request.ImageUrl }; - _db.Images.Add(image); - await _db.SaveChangesAsync(); - } - } - - // Create quote - var quote = new Quote - { - Text = request.Text, - Author = request.Author, - CreatedAt = DateTime.UtcNow, - LastUpdatedAt = DateTime.UtcNow, - ImageId = image?.Id ?? 0, - UserId = userId, - QuoteCategories = new List() - }; - - // Attach categories - foreach (var categoryId in request.CategoryIds) - { - var categoryExists = await _db.Categories.AnyAsync(c => c.Id == categoryId); - if (!categoryExists) - return BadRequest($"Category ID {categoryId} not found"); - - quote.QuoteCategories.Add(new QuoteCategory - { - CategoryId = categoryId, - Quote = quote - }); - } - - _db.Quotes.Add(quote); - await _db.SaveChangesAsync(); - - return CreatedAtAction(nameof(GetQuoteById), new { id = quote.Id }, quote); - } - - [HttpGet("{id}")] - public async Task GetQuoteById(int id) - { - var quote = await _db.Quotes - .Include(q => q.QuoteCategories) - .ThenInclude(qc => qc.Category) - .Include(q => q.User) - .Include(q => q.ImageId) - .FirstOrDefaultAsync(q => q.Id == id); - - if (quote == null) - return NotFound(); - - return Ok(quote); - } - } -} \ No newline at end of file diff --git a/Controllers/QuoteController.cs b/Controllers/QuoteController.cs new file mode 100644 index 0000000..a00efce --- /dev/null +++ b/Controllers/QuoteController.cs @@ -0,0 +1,153 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using QuotifyBE.Data; +using QuotifyBE.Entities; +using System.Security.Claims; +using Microsoft.EntityFrameworkCore; + +namespace QuotifyBE.Controllers; + + +[ApiController] +[Route("api/v1/quotes")] +public class QuotesController : ControllerBase +{ + + private readonly ApplicationDbContext _db; + + public QuotesController(ApplicationDbContext db) + { + _db = db; + } + + // GET /api/v1/quotes + [HttpGet] + public async Task GetQuoteByRange() + { + // TODO... + + return NotFound(new { status = "error", error_msg = "Not implemented" }); + + // TODO: Consider turning the quote into a DTO + } + + // GET /api/v1/quotes/{id} + [HttpGet("{id}")] + public async Task GetQuoteById(int id) + { + // FIXME: The expression 'q.QuoteCategories' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. + var quote = await _db.Quotes + .Include(q => q.QuoteCategories!) + .ThenInclude(qc => qc.Category) + .Include(q => q.User) + .Include(q => q.ImageId) + .FirstOrDefaultAsync(q => q.Id == id); + + if (quote == null) + return NotFound(new { status = "error", error_msg = "Quote not found" }); + + // TODO: Consider turning the quote into a DTO + + return Ok(quote); + } + + // POST /api/v1/quotes/new + [HttpPost("new")] + [Authorize] + public async Task CreateQuote([FromBody] CreateQuoteDTO request) + { + // Get user ID from claims + var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (userIdClaim == null || !int.TryParse(userIdClaim, out int userId)) + return Unauthorized(new {status = "error", error_msg = "Invalid user ID"}); + + // Find or create image + Image? image = null; + if (!string.IsNullOrEmpty(request.ImageUrl)) + { + image = await _db.Images.FirstOrDefaultAsync(i => i.Url == request.ImageUrl); + if (image == null) + { + image = new Image { Url = request.ImageUrl }; + _db.Images.Add(image); + await _db.SaveChangesAsync(); + } + } + + // Create quote + var quote = new Quote + { + Text = request.Text, + Author = request.Author, + CreatedAt = DateTime.UtcNow, + LastUpdatedAt = DateTime.UtcNow, + ImageId = image?.Id ?? 0, + UserId = userId, + QuoteCategories = new List() + }; + + // Attach categories + foreach (var categoryId in request.CategoryIds) + { + var categoryExists = await _db.Categories.AnyAsync(c => c.Id == categoryId); + if (!categoryExists) + return BadRequest(new {status = "error", error_msg = $"Category ID {categoryId} not found"}); + + quote.QuoteCategories.Add(new QuoteCategory + { + CategoryId = categoryId, + Quote = quote + }); + } + + _db.Quotes.Add(quote); + await _db.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetQuoteById), new { id = quote.Id }, quote); + } + + // GET /api/v1/quotes/random + [HttpGet("random")] + [AllowAnonymous] + public async Task GetRandomQuote() + { + var totalQuotes = await _db.Quotes.CountAsync(); + if (totalQuotes == 0) + return NotFound(new { status = "error", error_msg = "No quotes to choose from" }); + + var random = new Random(); + var skip = random.Next(0, totalQuotes); + + // FIXME + var quote = await _db.Quotes + .Include(q => q.QuoteCategories!) + .ThenInclude(qc => qc.Category) + .Skip(skip) + .Take(1) + .FirstOrDefaultAsync(); + + if (quote == null) + return NotFound(); + + Image? image = null; + if (quote.ImageId != 0) + { + image = await _db.Images.FirstOrDefaultAsync(i => i.Id == quote.ImageId); + } + + var dto = new RandomQuote + { + Text = quote.Text, + Author = quote.Author, + ImageUrl = image?.Url, + Categories = quote.QuoteCategories? + .Select(qc => qc.Category?.Name ?? "") + .Where(name => !string.IsNullOrEmpty(name)) + .ToList() ?? new List() + }; + + return Ok(dto); + + } + +} diff --git a/Controllers/RandomQuoteController.cs b/Controllers/RandomQuoteController.cs deleted file mode 100644 index b5bd70a..0000000 --- a/Controllers/RandomQuoteController.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using QuotifyBE.Data; -using QuotifyBE.Entities; -namespace QuotifyBE.Controllers -{ - [ApiController] - [Route("controller")] - public class QuotesController_2 : ControllerBase - { - private readonly ApplicationDbContext _db; - - public QuotesController_2(ApplicationDbContext db) - { - _db = db; - } - [HttpGet] - [AllowAnonymous] - - public async Task GetRandomQuote() - { - var totalQuotes = await _db.Quotes.CountAsync(); - if (totalQuotes == 0) - return NotFound(new { status = "error", error_msg = "brak cytatow" }); - - var random = new Random(); - var skip = random.Next(0, totalQuotes); - - var quote = await _db.Quotes - .Include(q => q.QuoteCategories) - .ThenInclude(qc => qc.Category) - .Skip(skip) - .Take(1) - .FirstOrDefaultAsync(); - - if (quote == null) - return NotFound(); - - Image? image = null; - if (quote.ImageId != 0) - { - image = await _db.Images.FirstOrDefaultAsync(i => i.Id == quote.ImageId); - } - - var dto = new RandomQuote - { - Text = quote.Text, - Author = quote.Author, - ImageUrl = image?.Url, - Categories = quote.QuoteCategories? - .Select(qc => qc.Category?.Name ?? "") - .Where(name => !string.IsNullOrEmpty(name)) - .ToList() ?? new List() - }; - - return Ok(dto); - - } - - - } -} \ No newline at end of file diff --git a/DTOs/CreateQuote.cs b/DTOs/CreateQuoteDTO.cs similarity index 76% rename from DTOs/CreateQuote.cs rename to DTOs/CreateQuoteDTO.cs index ca35264..7e95485 100644 --- a/DTOs/CreateQuote.cs +++ b/DTOs/CreateQuoteDTO.cs @@ -1,7 +1,7 @@ -public record class CreateQuoteRequest -{ - public string Text { get; set; } - public string Author { get; set; } - public List CategoryIds { get; set; } - public string? ImageUrl { get; set; } -}; \ No newline at end of file +public record class CreateQuoteDTO +{ + public string Text { get; set; } + public string Author { get; set; } + public List CategoryIds { get; set; } + public string? ImageUrl { get; set; } +}; diff --git a/DTOs/RandomQuote.cs b/DTOs/RandomQuoteDTO.cs similarity index 96% rename from DTOs/RandomQuote.cs rename to DTOs/RandomQuoteDTO.cs index 88f4c35..e593e6b 100644 --- a/DTOs/RandomQuote.cs +++ b/DTOs/RandomQuoteDTO.cs @@ -1,9 +1,9 @@ -public record class RandomQuote -{ - public string Text { get; set; } = string.Empty; - public string Author { get; set; } = string.Empty; - public string? ImageUrl { get; set; } - public List Categories { get; set; } = new(); - -}; - +public record class RandomQuote +{ + public string Text { get; set; } = string.Empty; + public string Author { get; set; } = string.Empty; + public string? ImageUrl { get; set; } + public List Categories { get; set; } = new(); + +}; + diff --git a/Data/ApplicationDbContext.cs b/Data/ApplicationDbContext.cs index d4850f0..44d7093 100644 --- a/Data/ApplicationDbContext.cs +++ b/Data/ApplicationDbContext.cs @@ -1,4 +1,4 @@ -// using Microsoft.AspNetCore.Identity; +// using Microsoft.AspNetCore.Identity; // using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -17,6 +17,7 @@ namespace QuotifyBE.Data public DbSet Quotes => Set(); public DbSet Categories => Set(); public DbSet Images => Set(); + public DbSet QuoteCategories => Set(); protected override void OnModelCreating(ModelBuilder builder) { @@ -26,4 +27,4 @@ namespace QuotifyBE.Data .HasKey(vs => new { vs.QuoteId, vs.CategoryId }); } } -} \ No newline at end of file +} diff --git a/Entities/Quote.cs b/Entities/Quote.cs index 896c5f6..81a37b2 100644 --- a/Entities/Quote.cs +++ b/Entities/Quote.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; namespace QuotifyBE.Entities {