using System.Security.Claims; using System.Text.Json; using Elements.Data; using Elements.Data.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; namespace Elements.Backend.Controllers; [ApiController] public class SuggestionController : ControllerBase { private readonly ApplicationDbContext _dbContext; public SuggestionController(ApplicationDbContext dbContext) { _dbContext = dbContext; } [Route("/suggestion/search")] [HttpGet] public async Task GetSuggestions(int firstElementId, int secondElementId) { bool firstExists = await _dbContext.Elements.AnyAsync(e => e.Id == firstElementId); bool secondExists = await _dbContext.Elements.AnyAsync(e => e.Id == secondElementId); if (!firstExists || !secondExists) return BadRequest(); IEnumerable suggestion = await _dbContext.Suggestions .Where(s => (s.FirstElementId == firstElementId && s.SecondElementId == secondElementId) || (s.FirstElementId == secondElementId && s.SecondElementId == firstElementId)) .Include(suggestion => suggestion.Votes) .ToListAsync(); if (!suggestion.Any()) return NotFound(); var result = suggestion.Select(s => new { s.Id, s.Name, Icon = Convert.ToBase64String(s.Icon), s.FirstElementId, s.SecondElementId, Votes = s.Votes.Count, s.UserId, s.VotingEnd }).ToList(); var serializeOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; return Ok(JsonSerializer.Serialize(result, serializeOptions)); } public class SuggestionVoteModel { public required int Id { get; set; } } [Route("/suggestion/vote")] [Authorize] [HttpPost] public async Task PostVote([FromBody] SuggestionVoteModel vote) { Suggestion? suggestion = await _dbContext.Suggestions .Include(s => s.Votes) .FirstOrDefaultAsync(s => s.Id == vote.Id); if (suggestion == null) return NotFound(); IEnumerable claims = User.Claims; string? currentUserId = claims.FirstOrDefault(claim => claim.Type == "id")?.Value; if (currentUserId == null) return StatusCode(StatusCodes.Status500InternalServerError); //Check if user is voting for own element if (suggestion.UserId.ToString() == currentUserId) return BadRequest(); //Check if user already voted for this element IEnumerable suggestionVotes = suggestion.Votes; if (suggestionVotes.Any(s => s.UserId.ToString() == currentUserId)) return BadRequest(); Vote newVote = new() { UserId = int.Parse(currentUserId), SuggestionId = suggestion.Id }; await _dbContext.Votes.AddAsync(newVote); await _dbContext.SaveChangesAsync(); return Ok(); } public class SuggestionCreateModel { public required string Name { get; set; } public required string IconBitmap { get; set; } public required int FirstElementId { get; set; } public required int SecondElementId { get; set; } } [Route("/suggestion/create")] [Authorize] [HttpPost] public async Task PostSuggestion([FromBody] SuggestionCreateModel suggestion) { IEnumerable claims = User.Claims; string? currentUserId = claims.FirstOrDefault(claim => claim.Type == "id")?.Value; if (currentUserId == null) return StatusCode(StatusCodes.Status500InternalServerError); //User already suggested something if (await _dbContext.Suggestions.AnyAsync(s => s.UserId.ToString() == currentUserId)) return BadRequest(); Suggestion newSuggestion = new() { CreationDate = DateTime.UtcNow, Name = suggestion.Name, Icon = ConvertBitmapToPng(Convert.FromBase64String(suggestion.IconBitmap)), FirstElementId = suggestion.FirstElementId, SecondElementId = suggestion.SecondElementId, VotingEnd = DateTime.UtcNow + TimeSpan.FromSeconds(10), UserId = int.Parse(currentUserId) }; await _dbContext.Suggestions.AddAsync(newSuggestion); await _dbContext.SaveChangesAsync(); Vote newVote = new() { UserId = int.Parse(currentUserId), SuggestionId = newSuggestion.Id }; await _dbContext.Votes.AddAsync(newVote); await _dbContext.SaveChangesAsync(); return Ok(); } private static byte[] ConvertBitmapToPng(byte[] bitmapData) { Image image = Image.LoadPixelData(bitmapData, 16, 16); using MemoryStream resultStream = new(); image.Save(resultStream, new PngEncoder()); return resultStream.ToArray(); } }