using Lactose.Mapper; using Lactose.Models; using Lactose.Repositories; using Lactose.Services; using Lactose.Types; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Extensions; namespace Lactose.Controllers; [Authorize] [ApiController] [Route("api/[controller]")] public class TagController( ILogger logger, LactoseAuthService authService, ITagRepository tagRepository ) : ControllerBase { [HttpGet("id")] public ActionResult Get(Guid id, bool children = false, bool ancestors = false) { Tag? tag = tagRepository.Find(id); if (tag == null) { return NotFound(); } var tagDto = TagsMapper.ToTagDto(tag); tagDto.Parent = tag.Parent == null ? null : TagsMapper.ToTagDto(tag.Parent); if (children) { tagDto.Children = []; tagRepository.GetChildren(tag.Id).ForEach(t => tagDto.Children.Add(TagsMapper.ToTagDto(t))); } //TODO: Protect from overflow if (ancestors) { Tag? index = tag.Parent; TagDto? indexDto = tagDto; List ancestorsTags = []; // This is redundant, because circular references shouldn't be present while (index != null && !ancestorsTags.Contains(tag)) { ancestorsTags.Add(index); indexDto.Parent = TagsMapper.ToTagDto(index); index = index.Parent; indexDto = indexDto.Parent; } } return tagDto; } [HttpGet] public ActionResult> GetAll(string? search, uint? page, uint? pageSize) { search ??= string.Empty; List tags = tagRepository.Search(search, page, pageSize); List tagsDto = []; tags.ForEach( t => { var tagDto = TagsMapper.ToTagDto(t); tagDto.Parent = t.Parent == null ? null : TagsMapper.ToTagDto(t.Parent); tagsDto.Add(tagDto); } ); return tagsDto; } [HttpPost] public ActionResult Update([FromBody] TagUpdateDto tagDto) { LactoseAuthenticatedUser? user = authService.GetUserData(User); if (user == null) { logger.LogWarning(@"Anonymous User hasn't enough permissions to create a Tag. it shouldn't be here"); return Unauthorized("Unauthorized"); } if (user.AccessLevel != EAccessLevel.Admin && user.AccessLevel != EAccessLevel.Curator) { return Unauthorized("Unauthorized"); } Tag? tag = tagRepository.Find(tagDto.Id); if (tag == null) { return NotFound(); } if (!tagDto.Name.IsNullOrEmpty()) { tag.Name = tagDto.Name!; } if (tagDto.Parent != null) { if (tagDto.Parent.Equals(Guid.Empty)) { tag.Parent = null; } Tag? parent = tagRepository.Find(tagDto.Parent.Value); if (parent != null) { tag.Parent = parent; } else { return NotFound("Parent tag was not found"); } } tagRepository.Save(); return Ok(); } [Authorize(Roles = "Admin")] [HttpDelete] [Route("{id}")] public ActionResult Delete(Guid id) { throw new NotImplementedException("Tag:Delete is not implemented yet"); } } public class TagDto { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public TagDto? Parent { get; set; } public List? Children { get; set; } } public class TagUpdateDto { public Guid Id { get; set; } public string? Name { get; set; } public Guid? Parent { get; set; } }