diff --git a/Controllers/AppUsersController.cs b/Controllers/AppUsersController.cs index ff45085..d6bbc2b 100644 --- a/Controllers/AppUsersController.cs +++ b/Controllers/AppUsersController.cs @@ -10,7 +10,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class UsersController : ControllerBase { diff --git a/Controllers/FilesController.cs b/Controllers/FilesController.cs index 22aa086..6481b76 100644 --- a/Controllers/FilesController.cs +++ b/Controllers/FilesController.cs @@ -10,7 +10,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class FilesController : ControllerBase { diff --git a/Controllers/HistoriesController.cs b/Controllers/HistoriesController.cs index 85c8d89..0934909 100644 --- a/Controllers/HistoriesController.cs +++ b/Controllers/HistoriesController.cs @@ -10,7 +10,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class HistoriesController : ControllerBase { diff --git a/Controllers/NotesController.cs b/Controllers/NotesController.cs index 0646e83..f2a537b 100644 --- a/Controllers/NotesController.cs +++ b/Controllers/NotesController.cs @@ -10,7 +10,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class NotesController : ControllerBase { diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index f4b3da6..611273e 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -13,7 +13,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { [Produces("application/json")] - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class ProjectsController : ControllerBase { @@ -152,7 +152,7 @@ namespace TicketManager.Controllers return project.GetMembers(); } - [HttpPut("{id}/setMembers")] + [HttpPut("{id}/members")] public async Task> SetProjectMembers(int id, List projectMembers) { Project project = await GetProjectByIdAsync(id); diff --git a/Controllers/TicketsController.cs b/Controllers/TicketsController.cs index bddebe9..c61ce5b 100644 --- a/Controllers/TicketsController.cs +++ b/Controllers/TicketsController.cs @@ -10,7 +10,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { - [Route("api/[controller]")] + [Route("api/v1/[controller]")] [ApiController] public class TicketsController : ControllerBase { @@ -25,25 +25,14 @@ namespace TicketManager.Controllers [HttpGet] public async Task>> GetTickets() { - return await _context.Tickets - .Include(t => t.Creator) - .Include(p => p.Notes) - .Include(p => p.Edits) - .Include(p => p.Files) - .AsNoTracking() - .ToListAsync(); + return await getAllTicketsAsync(); } // GET: api/Tickets/5 [HttpGet("{id}")] public async Task> GetTicket(int id) { - var ticket = await _context.Tickets - .Include(t => t.Creator) - .Include(p => p.Notes) - .Include(p => p.Edits) - .Include(p => p.Files) - .FirstOrDefaultAsync(t => t.Id == id); + var ticket = await getTicketByIdAsync(id); if (ticket == null) { @@ -113,9 +102,47 @@ namespace TicketManager.Controllers return ticket; } + [HttpGet("{id}/assignees")] + public async Task>> GetTicketAssignees(int id) + { + Ticket ticket = await getTicketByIdAsync(id); + return ticket.GetAssignees(); + } + + [HttpPut("{id}/closed")] + public async Task CloseTicket(int id) + { + Ticket ticket = await getTicketByIdAsync(id); + ticket.Close(); + return NoContent(); + } + private bool TicketExists(int id) { return _context.Tickets.Any(e => e.Id == id); } + + private IQueryable ticketQuery() // problem with link + { + return _context.Tickets + .Include(p => p.Project) + .ThenInclude(a => a.Assignments) + .ThenInclude(p => p.User) + // .Include(p => p.Edits) + // .Include(p => p.Notes) + // .Include(p => p.Files) + .Include(p => p.Creator) + ; + } + + private async Task>> getAllTicketsAsync() + { + return await ticketQuery().ToListAsync(); + } + + private async Task getTicketByIdAsync(int id) + { + return await ticketQuery().FirstOrDefaultAsync(a => a.Id == id); + } } } diff --git a/Models/AppUser.cs b/Models/AppUser.cs index 216007a..fb53b1a 100644 --- a/Models/AppUser.cs +++ b/Models/AppUser.cs @@ -34,7 +34,7 @@ namespace TicketManager.Models [DataType(DataType.Date)] [Display(Name = "Member since"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] - public DateTime Created_at { get; set; } = DateTime.Now; + public DateTime Created_at { get; private set; } = DateTime.Now; // [Display(Name = "Avatar")] // public byte[] Picture { get; set; } diff --git a/Models/File.cs b/Models/File.cs index 2b5c3b8..8dd01e4 100644 --- a/Models/File.cs +++ b/Models/File.cs @@ -5,11 +5,25 @@ namespace TicketManager.Models { public class File { + + public int Id { get; set; } - public string Location { get; set; } + + public string FileName { get; set; } + + private string _location; + public string Location + { + get { return _location; } + private set + { + string filesUrl = ""; + _location = $"{filesUrl}/{FileName}"; + } + } public string Description { get; set; } - public int Size { get; set; } - public string Format { get; set; } + public int Size { get; set; } // deduce auto from FileName + public string Format { get; set; } // deduce auto from FileName public AppUser AddedBy { get; set; } public int UserId { get; set; } diff --git a/Models/Project.cs b/Models/Project.cs index 4ebe976..2048ccf 100644 --- a/Models/Project.cs +++ b/Models/Project.cs @@ -34,7 +34,7 @@ namespace TicketManager.Models { return _progression; } - set + private set { _progression = Tickets.Count() == 0 ? 0 : (decimal)this.Tickets. diff --git a/Models/Ticket.cs b/Models/Ticket.cs index a423c09..29c5e01 100644 --- a/Models/Ticket.cs +++ b/Models/Ticket.cs @@ -1,14 +1,27 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; namespace TicketManager.Models { public class Ticket : ITask { public int Id { get; set; } + + [Required] + [StringLength(100)] public string Title { get; set; } + + [StringLength(100)] public string Description { get; set; } - public DateTime CreatedAt { get; set; } = DateTime.Now; + + [DataType(DataType.Date)] + [Display(Name = "Creation Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] + public DateTime CreatedAt { get; private set; } = DateTime.Now; + + [DataType(DataType.Date)] + [Display(Name = "Estimated Ending Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] public DateTime PlannedEnding { get; set; } public Status Status { get; set; } = Status.ToDo; @@ -16,42 +29,28 @@ namespace TicketManager.Models public Difficulty Difficulty { get; set; } = Difficulty.Undefined; public Category Category { get; set; } = Category.Undefined; + [Display(Name = "Created By")] public AppUser Creator { get; set; } public Guid CreatorId { get; set; } + + [Display(Name = "Project")] public Project Project { get; set; } public int ProjectId { get; set; } - private List _notes; - public List Notes - { - get - { - return _notes ?? new List(); - } - set { _notes = value; } - } - private List _edits; - public List Edits - { - get - { - return _edits ?? new List(); - } - set { _edits = value; } - } - private List _files; - public List Files - { - get - { - return _files ?? new List(); - } - set { _files = value; } - } + public List Notes = new List(); + + public List Edits = new List(); + + public List Files = new List(); // Methods - public void GetAssignees() { throw new NotImplementedException("Not Implemented"); } + public List GetAssignees() + { + return Project.Assignments.Select(a => a.User).ToList(); + } public void GetLastUpdateTime() { throw new NotImplementedException("Not Implemented"); } - public void Close() { throw new NotImplementedException("Not Implemented"); } - public void AddFile() { throw new NotImplementedException("Not Implemented"); } + public void Close() + { + Status = Status.Done; + } } } \ No newline at end of file diff --git a/README.md b/README.md index f8613bc..0b0c2eb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ ## API Documentation -- [Internal Link. Don't forget to update](https://localhost:5001/swagger/index.html) +### v1 + +- [Internal Link. Don't forget to update](https://localhost:5001/swagger) ## Features @@ -39,3 +41,4 @@ - Ensure Tickets Files belong to Project Files - Write a query class to refactor code and optimize perf on get queries (AsNoTracking) - Async model methods ? +- setMembers & removeMembers from project api not working diff --git a/Startup.cs b/Startup.cs index 0a40edf..b169da0 100644 --- a/Startup.cs +++ b/Startup.cs @@ -53,7 +53,7 @@ namespace TicketManager { Version = "v1", Title = "Ticket Manager API", - Description = "A simple example ASP.NET Core Web API", + Description = "Ticket Manger API for Teams", Contact = new OpenApiContact { Name = "Ruidy Nemausat", @@ -91,7 +91,7 @@ namespace TicketManager app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ticket Manager API V1"); + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ticket Manager API v1"); });