diff --git a/.gitignore b/.gitignore index f7577c8..e2a1839 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,16 @@ -bin/ -obj/ .vs/ .vscode/ -Migrations/ -app.db* .DS_Store -app.db +bin/ +obj/ +app.db* Data/Interfaces Data/UnitOfWork.cs Data/*Repository.cs +Migrations/ +Properties/ +Tests/TicketManager.Tests/UnitTests/ControllersTests/ControllerTests.cs +Tests/TicketManager.Tests/UnitTests/ControllersTests/SeedDb.cs # client client/src/pages/TestPage.tsx diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index 33d4891..0b98104 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -37,7 +37,7 @@ namespace TicketManager.Controllers /// Returns a list of projects [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetProjects() + public async Task> GetProjects() { return await _context.Projects .Include(p => p.Assignments) @@ -60,7 +60,8 @@ namespace TicketManager.Controllers /// GET: api/v1/Projects/2 /// /// - /// Returns a project object + /// Identifier of the ressource + /// Returns a specific project /// If the required project is null [HttpGet("{id}")] [ProducesResponseType(StatusCodes.Status200OK)] @@ -242,7 +243,7 @@ namespace TicketManager.Controllers /// Not Found [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - [HttpPut("{id}/members")] + [HttpPatch("{id}/members")] public async Task> SetProjectMembers(int id, List projectMembers) { Project project = await _context.Projects diff --git a/DataTransfertObjects/AppUserDTO.cs b/DTOs/AppUserDTO.cs similarity index 99% rename from DataTransfertObjects/AppUserDTO.cs rename to DTOs/AppUserDTO.cs index 250fbcc..b2009d3 100644 --- a/DataTransfertObjects/AppUserDTO.cs +++ b/DTOs/AppUserDTO.cs @@ -48,6 +48,5 @@ namespace TicketManager.DTO public List Projects { get; set; } = new List(); public List Tickets { get; set; } = new List(); - } } \ No newline at end of file diff --git a/DataTransfertObjects/ProjectDTO.cs b/DTOs/ProjectDTO.cs similarity index 99% rename from DataTransfertObjects/ProjectDTO.cs rename to DTOs/ProjectDTO.cs index ccfa8a3..ba8d098 100644 --- a/DataTransfertObjects/ProjectDTO.cs +++ b/DTOs/ProjectDTO.cs @@ -36,6 +36,7 @@ namespace TicketManager.DTO public string Status { get; set; } public AppUser Manager { get; set; } + public List Users { get; set; } = new List(); public List Tickets { get; set; } = new List(); diff --git a/DataTransfertObjects/TicketDTO.cs b/DTOs/TicketDTO.cs similarity index 99% rename from DataTransfertObjects/TicketDTO.cs rename to DTOs/TicketDTO.cs index 4ff3bae..cdacb99 100644 --- a/DataTransfertObjects/TicketDTO.cs +++ b/DTOs/TicketDTO.cs @@ -38,14 +38,23 @@ namespace TicketManager.DTO public DateTime PlannedEnding { get; set; } public string Status { get; set; } + public string Impact { get; set; } + public string Difficulty { get; set; } + public string Category { get; set; } + public Guid CreatorId { get; set; } + public Project Project { get; set; } + public List Notes { get; set; } = new List(); + public List Activities { get; set; } = new List(); + public List Files { get; set; } = new List(); + public List Users { get; set; } = new List(); } } \ No newline at end of file diff --git a/Models/Project.cs b/Models/Project.cs index fceedcf..7f1df5a 100644 --- a/Models/Project.cs +++ b/Models/Project.cs @@ -95,6 +95,10 @@ namespace TicketManager.Models public void RemoveMembers(List membersToRemove) { this.Assignments.RemoveAll(a => membersToRemove.Contains(a.User)); + + // membersToRemove.ForEach( + // m => m.Assignments.RemoveAll(a => (a.Project == this)) + // ); } public void SetMembers(List projectMembers) diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 42e74be..7fb0bbb 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -20,7 +20,7 @@ "TicketManager": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "weatherforecast", + "launchUrl": "/", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/Startup.cs b/Startup.cs index f86c247..a663213 100644 --- a/Startup.cs +++ b/Startup.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Reflection; +using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; @@ -13,13 +12,10 @@ using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; -using System.Reflection; -using System.IO; -using TicketManager.Data; -using TicketManager.Models; using Microsoft.AspNetCore.Mvc.NewtonsoftJson; -using Newtonsoft.Json; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Newtonsoft.Json; +using TicketManager.Data; [assembly: ApiController] namespace TicketManager @@ -36,10 +32,14 @@ namespace TicketManager public void ConfigureServices(IServiceCollection services) { services.AddDbContext(options => - options.UseSqlite(Configuration.GetConnectionString("Sqlite"))); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); + { + options.UseSqlite(Configuration.GetConnectionString("Sqlite")); + options.EnableSensitiveDataLogging(true); //Remove in production. + } + ); + // services.AddScoped(); + // services.AddScoped(); + // services.AddScoped(); services.AddAuthentication(options => { diff --git a/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs b/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs new file mode 100644 index 0000000..6bda2fb --- /dev/null +++ b/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs @@ -0,0 +1,253 @@ +using System; +using Xunit; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.Sqlite; +using TicketManager.Controllers; +using TicketManager.Data; +using TicketManager.Models; +using TicketManager.DTO; + + +namespace TicketManager.Tests +{ + public class ProjectsControllerTests + { + [Fact] + public async Task Get_ReturnsListWith2Projects() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + try + { + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + // creates DB schema + using (var context = new AppDbContext(options)) + { + context.Database.EnsureCreated(); + } + + // Seed DB usng one context instance + SeedDb(options); + + using (var context = new AppDbContext(options)) + { + var controller = new ProjectsController(context); + + var result = await controller.GetProjects(); + + Assert.IsAssignableFrom>(result); + Assert.Equal(2, result.Count); + } + } + finally + { + connection.Close(); + } + } + + [Fact] + public async Task Get1_Returns1Project() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + try + { + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + // creates DB schema + using (var context = new AppDbContext(options)) + { + context.Database.EnsureCreated(); + } + + // Seed DB usng one context instance + SeedDb(options); + + using (var context = new AppDbContext(options)) + { + var controller = new ProjectsController(context); + + // Should Return 1 Project + var result = await controller.GetProject(1); + Assert.IsAssignableFrom(result); + + // Should Return NotFound + result = await controller.GetProject(3); + Assert.IsType(result); + } + } + finally + { + connection.Close(); + } + } + + [Fact] + public async Task Put1_Updates1Project() + { + // ControllersTests.Wrapper(Test_PutProject, SeedDb); + // } + + // private static async Task Test_PutProject() + // { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + try + { + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + // creates DB schema + using (var context = new AppDbContext(options)) + { + context.Database.EnsureCreated(); + } + + // Seed DB usng one context instance + SeedDb(options); + + using (var context = new AppDbContext(options)) + { + var controller = new ProjectsController(context); + + var result = await controller.PutProject(1, + new Project() + { + Id = 1, + Title = "Top Secret Project", + Description = "Shht Don't Ask don't tell", + PlannedEnding = new DateTime(2020, 7, 21) + } + ); + + // Should Update + Assert.Equal("Top Secret Project", context.Projects.Find(1).Title); + Assert.Equal(new DateTime(2020, 7, 21), context.Projects.Find(1).PlannedEnding); + Assert.IsType(result); + + + result = await controller.PutProject(2, + new Project() + { + Id = 1, + Title = "Top Secret Project", + Description = "Shht Don't Ask don't tell", + PlannedEnding = new DateTime(2020, 7, 21) + } + ); + + // Should Return BadRequest + Assert.NotEqual("Top Secret Project", context.Projects.Find(2).Title); + Assert.NotEqual(new DateTime(2020, 7, 21), context.Projects.Find(2).CreatedAt); + Assert.IsType(result); + + // Delete updated project + context.Projects.RemoveRange(context.Projects.Find(1)); + await context.SaveChangesAsync(); + + result = await controller.PutProject(1, + new Project() + { + Id = 1, + Title = "Top Secret Project", + Description = "Shht Don't Ask don't tell", + PlannedEnding = new DateTime(2020, 7, 21) + } + ); + + // Should Throw + Assert.IsType(result); + Assert.Equal("Top Secret Project", context.Projects.Find(1).Title); + Assert.Equal(new DateTime(2020, 7, 21), context.Projects.Find(1).PlannedEnding); + } + } + + finally + { + connection.Close(); + } + } + + [Fact] + public async Task Post_CreatesProject() + { + // Create inMemory Test Database + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + try + { + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + // creates DB schema + using (var context = new AppDbContext(options)) + { + context.Database.EnsureCreated(); + } + + // Seed DB usng one context instance + SeedDb(options); + + // use another context instance to run the test + using (var context = new AppDbContext(options)) + { + var proj = new Project() + { + Title = "The Third", + Description = "Thrice in a row", + PlannedEnding = DateTime.Now + }; + + var controller = new ProjectsController(context); + + var result = await controller.PostProject(proj); + + Assert.IsAssignableFrom(result); + Assert.Equal(3, await context.Projects.CountAsync()); + } + } + finally + { + connection.Close(); + } + } + + private static void SeedDb(DbContextOptions options) + // Seed DB usng one context instance + { + using (var context = new AppDbContext(options)) + { + context.Projects.AddRange( + new Project() + { + Id = 1, + Title = "Secret Project", + Description = "Shht Don't Ask don't tell", + PlannedEnding = new DateTime(2021, 7, 21) + }, + new Project() + { + Id = 2, + Title = "Public Project", + Description = "It's quite obvious, isn't it?!", + PlannedEnding = new DateTime(2036, 6, 16) + }); + context.SaveChanges(); + } + } + } +} diff --git a/Tests/TicketManager.Tests/UnitTests/AppUserModelTests.cs b/Tests/TicketManager.Tests/UnitTests/ModelTests/AppUserModelTests.cs similarity index 100% rename from Tests/TicketManager.Tests/UnitTests/AppUserModelTests.cs rename to Tests/TicketManager.Tests/UnitTests/ModelTests/AppUserModelTests.cs index 8243ef1..2016528 100644 --- a/Tests/TicketManager.Tests/UnitTests/AppUserModelTests.cs +++ b/Tests/TicketManager.Tests/UnitTests/ModelTests/AppUserModelTests.cs @@ -50,6 +50,13 @@ namespace TicketManager.Tests Ticket t5 = new Ticket(); Ticket t6 = new Ticket(); + p1.Tickets.Add(t1); + p2.Tickets.Add(t2); + p2.Tickets.Add(t3); + p3.Tickets.Add(t4); + p3.Tickets.Add(t5); + p3.Tickets.Add(t6); + Assignment a1 = new Assignment() { User = user, @@ -69,13 +76,6 @@ namespace TicketManager.Tests }; user.Assignments.Add(a3); - p1.Tickets.Add(t1); - p2.Tickets.Add(t2); - p2.Tickets.Add(t3); - p3.Tickets.Add(t4); - p3.Tickets.Add(t5); - p3.Tickets.Add(t6); - var res = user.GetTickets().Count; Assert.Equal(6, res); } diff --git a/Tests/TicketManager.Tests/UnitTests/ProjectModelTests.cs b/Tests/TicketManager.Tests/UnitTests/ModelTests/ProjectModelTests.cs similarity index 100% rename from Tests/TicketManager.Tests/UnitTests/ProjectModelTests.cs rename to Tests/TicketManager.Tests/UnitTests/ModelTests/ProjectModelTests.cs diff --git a/Tests/TicketManager.Tests/UnitTests/TicketModelTests.cs b/Tests/TicketManager.Tests/UnitTests/ModelTests/TicketModelTests.cs similarity index 100% rename from Tests/TicketManager.Tests/UnitTests/TicketModelTests.cs rename to Tests/TicketManager.Tests/UnitTests/ModelTests/TicketModelTests.cs diff --git a/Tests/TicketManager.Tests/UnitTests/ProjectControllerTests.cs b/Tests/TicketManager.Tests/UnitTests/ProjectControllerTests.cs deleted file mode 100644 index 6e1d788..0000000 --- a/Tests/TicketManager.Tests/UnitTests/ProjectControllerTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Xunit; -using System.Collections.Generic; -using TicketManager.Controllers; -using TicketManager.Data; -using TicketManager.Models; - -namespace TicketManager.Tests -{ - public class ProjectsControllerTests - { - - - public ProjectsControllerTests() - { - // _context = context; - } - - // [Fact] - // public void Get_ReturnsProjectList() - // { - // // Arange - // // var controller = new ProjectsController(); - - // // Act - // // var result = controller.GetProjects(); - - // // Assert - // // Assert.IsType>(result); - // } - } -} diff --git a/TicketManager.csproj b/TicketManager.csproj index 812b03b..d68b951 100644 --- a/TicketManager.csproj +++ b/TicketManager.csproj @@ -3,7 +3,7 @@ netcoreapp3.1 - + 8.0 @@ -26,9 +26,14 @@ + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all +