From deb3492475c606a655a69c891eac1957324938bb Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Wed, 26 Feb 2020 22:45:52 +0100 Subject: [PATCH] applying dto pattern --- Controllers/AppUsersController.cs | 3 +- Controllers/ProjectsController.cs | 7 ++- DTOs/AppUserDTO.cs | 13 ++--- DTOs/ProjectDTO.cs | 20 ++++---- DTOs/TicketDTO.cs | 18 +++---- Models/AppUser.cs | 2 +- Models/Project.cs | 4 +- Models/Ticket.cs | 4 +- README.md | 1 + Scripts/response.http | 47 ------------------- Startup.cs | 15 ++---- .../ProjectControllerTests.cs | 18 +++---- client/src/VM/ProjectVM.ts | 26 ++++++---- client/src/components/UsersModal.tsx | 5 +- client/src/pages/ProjectPage.tsx | 4 +- client/src/types/Project.ts | 4 +- client/src/types/User.ts | 16 ++++++- client/src/utils/http.ts | 12 +++++ 18 files changed, 102 insertions(+), 117 deletions(-) diff --git a/Controllers/AppUsersController.cs b/Controllers/AppUsersController.cs index 98262ef..3a622bd 100644 --- a/Controllers/AppUsersController.cs +++ b/Controllers/AppUsersController.cs @@ -70,14 +70,13 @@ namespace TicketManager.Controllers .ThenInclude(a => a.Project) .Include(u => u.Activities) .AsNoTracking() - .Select(u => new AppUserDTO(u)) .FirstOrDefaultAsync(u => u.Id == id); if (user == null) { return NotFound(); } - return user; + return new AppUserDTO(user); } /// diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index 0b98104..f13e3d9 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -41,7 +41,7 @@ namespace TicketManager.Controllers { return await _context.Projects .Include(p => p.Assignments) - .ThenInclude(a => a.User) + .ThenInclude(a => a.User) .Include(p => p.Tickets) .Include(p => p.Manager) .Include(p => p.Files) @@ -76,14 +76,13 @@ namespace TicketManager.Controllers .Include(p => p.Files) .Include(p => p.Activities) .AsNoTracking() - .Select(p => new ProjectDTO(p)) .FirstOrDefaultAsync(p => p.Id == id); if (project == null) { return NotFound(); } - return project; + return new ProjectDTO(project); } /// @@ -247,7 +246,7 @@ namespace TicketManager.Controllers public async Task> SetProjectMembers(int id, List projectMembers) { Project project = await _context.Projects - .Include(p => p.Assignments) + // .Include(p => p.Assignments) .FirstOrDefaultAsync(p => p.Id == id); if (project == null) diff --git a/DTOs/AppUserDTO.cs b/DTOs/AppUserDTO.cs index b2009d3..cafa9f5 100644 --- a/DTOs/AppUserDTO.cs +++ b/DTOs/AppUserDTO.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using TicketManager.Models; namespace TicketManager.DTO @@ -15,11 +16,11 @@ namespace TicketManager.DTO Presentation = user.Presentation; Email = user.Email; Phone = user.Phone; - Created_at = user.Created_at; + CreationDate = user.CreationDate; Picture = user.Picture; Activities = user.Activities; - Projects = user.GetProjects(); - Tickets = user.GetTickets(); + Projects = user.GetProjects().Select(u => new ProjectDTO(u)).ToList(); + Tickets = user.GetTickets().Select(u => new TicketDTO(u)).ToList(); } public Guid Id { get; set; } @@ -39,14 +40,14 @@ namespace TicketManager.DTO public string Phone { get; set; } [DataType(DataType.Date)] - public DateTime Created_at { get; private set; } = DateTime.Now; + public DateTime CreationDate { get; private set; } = DateTime.Now; public string Picture { get; set; } public List Activities { get; set; } = new List(); - public List Projects { get; set; } = new List(); + public List Projects { get; set; } = new List(); - public List Tickets { get; set; } = new List(); + public List Tickets { get; set; } = new List(); } } \ No newline at end of file diff --git a/DTOs/ProjectDTO.cs b/DTOs/ProjectDTO.cs index ba8d098..33972be 100644 --- a/DTOs/ProjectDTO.cs +++ b/DTOs/ProjectDTO.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections.Generic; using TicketManager.Models; @@ -11,12 +12,13 @@ namespace TicketManager.DTO Id = project.Id; Title = project.Title; Description = project.Description; - CreatedAt = project.CreatedAt; + CreationDate = project.CreationDate; + EndingDate = project.EndingDate; Progression = project.Progression; Status = project.Status.ToString(); - Manager = project.Manager; - Users = project.GetMembers(); - Tickets = project.Tickets; + // Manager = project.Manager != null ? new AppUserDTO(project.Manager) : null; + Users = project.GetMembers().Select(u => new AppUserDTO(u)).ToList(); + Tickets = project.Tickets.Select(t => new TicketDTO(t)).ToList(); Activities = project.Activities; Files = project.Files; } @@ -27,19 +29,19 @@ namespace TicketManager.DTO public string Description { get; set; } - public DateTime CreatedAt { get; private set; } = DateTime.Now; + public DateTime CreationDate { get; private set; } = DateTime.Now; - public DateTime PlannedEnding { get; set; } + public DateTime EndingDate { get; set; } public decimal Progression { get; set; } public string Status { get; set; } - public AppUser Manager { get; set; } + public AppUserDTO Manager { get; set; } - public List Users { get; set; } = new List(); + public List Users { get; set; } = new List(); - public List Tickets { get; set; } = new List(); + public List Tickets { get; set; } = new List(); public List Activities { get; set; } = new List(); diff --git a/DTOs/TicketDTO.cs b/DTOs/TicketDTO.cs index cdacb99..f1aa724 100644 --- a/DTOs/TicketDTO.cs +++ b/DTOs/TicketDTO.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using TicketManager.Models; namespace TicketManager.DTO @@ -12,19 +13,20 @@ namespace TicketManager.DTO Id = ticket.Id; Title = ticket.Title; Description = ticket.Description; - CreatedAt = ticket.CreatedAt; - PlannedEnding = ticket.PlannedEnding; + CreationDate = ticket.CreationDate; + EndingDate = ticket.EndingDate; Status = ticket.Status.ToString(); Impact = ticket.Impact.ToString(); Difficulty = ticket.Difficulty.ToString(); Category = ticket.Category.ToString(); CreatorId = ticket.CreatorId; - Project = ticket.Project; + Project = new ProjectDTO(ticket.Project); Notes = ticket.Notes; Activities = ticket.Activities; Files = ticket.Files; - Users = ticket.GetAssignees(); + Users = ticket.GetAssignees().Select(u => new AppUserDTO(u)).ToList(); } + public int Id { get; set; } public string Title { get; set; } @@ -32,10 +34,10 @@ namespace TicketManager.DTO public string Description { get; set; } [DataType(DataType.Date)] - public DateTime CreatedAt { get; private set; } + public DateTime CreationDate { get; private set; } [DataType(DataType.Date)] - public DateTime PlannedEnding { get; set; } + public DateTime EndingDate { get; set; } public string Status { get; set; } @@ -47,7 +49,7 @@ namespace TicketManager.DTO public Guid CreatorId { get; set; } - public Project Project { get; set; } + public ProjectDTO Project { get; set; } public List Notes { get; set; } = new List(); @@ -55,6 +57,6 @@ namespace TicketManager.DTO public List Files { get; set; } = new List(); - public List Users { get; set; } = new List(); + public List Users { get; set; } = new List(); } } \ No newline at end of file diff --git a/Models/AppUser.cs b/Models/AppUser.cs index ceb557b..28c0660 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; private set; } = DateTime.Now; + public DateTime CreationDate { get; private set; } = DateTime.Now; [Display(Name = "Avatar")] public string Picture { get; set; } diff --git a/Models/Project.cs b/Models/Project.cs index 7f1df5a..6ed7dd1 100644 --- a/Models/Project.cs +++ b/Models/Project.cs @@ -20,11 +20,11 @@ namespace TicketManager.Models [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = false)] - public DateTime CreatedAt { get; private set; } = DateTime.Now; + public DateTime CreationDate { get; private set; } = DateTime.Now; [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] - public DateTime PlannedEnding { get; set; } + public DateTime EndingDate { get; set; } [Display(Name = "Progress")] public decimal Progression diff --git a/Models/Ticket.cs b/Models/Ticket.cs index 0063be7..233d497 100644 --- a/Models/Ticket.cs +++ b/Models/Ticket.cs @@ -18,11 +18,11 @@ namespace TicketManager.Models [DataType(DataType.Date)] [Display(Name = "Creation Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] - public DateTime CreatedAt { get; private set; } = DateTime.Now; + public DateTime CreationDate { 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 DateTime EndingDate { get; set; } public Status Status { get; set; } = Status.ToDo; public Impact Impact { get; set; } = Impact.Undefined; diff --git a/README.md b/README.md index 73fc768..bd72ac2 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,4 @@ - [ ] error page redirect when offline. - [ ] ticket/files/activities list placeholders when empty - [ ] think about public/private DTO's constructor, getters and setters +- [ ] write dtos without circular dependencies diff --git a/Scripts/response.http b/Scripts/response.http index 7223cd0..e69de29 100644 --- a/Scripts/response.http +++ b/Scripts/response.http @@ -1,47 +0,0 @@ -{ - "activities" : [], - "plannedEnding" : "0001-01-01T00:00:00", - "id" : 1, - "title" : "Secret Project", - "createdAt" : "2020-02-24T10:34:18.428046", - "users" : [ - { - "firstName" : "Thomas", - "phone" : "0198237645", - "lastName" : "Price", - "created_at" : "2020-02-25T09:42:54.462374", - "presentation" : "New Team?!", - "email" : "tp@mail.com", - "picture" : null, - "activities" : [], - "id" : "357727fd-5262-4522-b8a3-38271d43de84", - "fullName" : "Thomas Price", - "assignments" : [ - { - "project" : { - "assignments" : [], - "createdAt" : "2020-02-24T10:34:18.428046", - "title" : "Secret Project", - "id" : 1, - "plannedEnding" : "2020-02-17T15:51:02.787373", - "activities" : [], - "description" : "Shhttt Don't tell anyone", - "status" : 1, - "files" : [], - "tickets" : [], - "progression" : 0, - "manager" : null - }, - "userId" : "357727fd-5262-4522-b8a3-38271d43de84", - "projectId" : 1 - } - ] - } - ], - "manager" : null, - "progression" : 0, - "tickets" : [], - "files" : [], - "status" : "ToDo", - "description" : "Shhttt Don't tell anyone" -} diff --git a/Startup.cs b/Startup.cs index a663213..6e88040 100644 --- a/Startup.cs +++ b/Startup.cs @@ -37,9 +37,6 @@ namespace TicketManager options.EnableSensitiveDataLogging(true); //Remove in production. } ); - // services.AddScoped(); - // services.AddScoped(); - // services.AddScoped(); services.AddAuthentication(options => { @@ -49,16 +46,14 @@ namespace TicketManager { options.Authority = "https://dev-fyjrvohx.auth0.com/"; options.Audience = "https://localhost:5001/api/V1/"; - //options.Authority = $"https://{Configuration["Auth0:Domain"]}/"; - //options.Audience = Configuration["Auth0:Audience"]; }); services.AddControllers() - .AddNewtonsoftJson(options => - { - options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors - } - ); + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors + } + ); services.AddSpaStaticFiles(configuration => { diff --git a/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs b/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs index 6bda2fb..0624eba 100644 --- a/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs +++ b/Tests/TicketManager.Tests/UnitTests/ControllersTests/ProjectControllerTests.cs @@ -128,13 +128,13 @@ namespace TicketManager.Tests Id = 1, Title = "Top Secret Project", Description = "Shht Don't Ask don't tell", - PlannedEnding = new DateTime(2020, 7, 21) + EndingDate = 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.Equal(new DateTime(2020, 7, 21), context.Projects.Find(1).EndingDate); Assert.IsType(result); @@ -144,13 +144,13 @@ namespace TicketManager.Tests Id = 1, Title = "Top Secret Project", Description = "Shht Don't Ask don't tell", - PlannedEnding = new DateTime(2020, 7, 21) + EndingDate = 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.NotEqual(new DateTime(2020, 7, 21), context.Projects.Find(2).CreationDate); Assert.IsType(result); // Delete updated project @@ -163,14 +163,14 @@ namespace TicketManager.Tests Id = 1, Title = "Top Secret Project", Description = "Shht Don't Ask don't tell", - PlannedEnding = new DateTime(2020, 7, 21) + EndingDate = 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); + Assert.Equal(new DateTime(2020, 7, 21), context.Projects.Find(1).EndingDate); } } @@ -209,7 +209,7 @@ namespace TicketManager.Tests { Title = "The Third", Description = "Thrice in a row", - PlannedEnding = DateTime.Now + EndingDate = DateTime.Now }; var controller = new ProjectsController(context); @@ -237,14 +237,14 @@ namespace TicketManager.Tests Id = 1, Title = "Secret Project", Description = "Shht Don't Ask don't tell", - PlannedEnding = new DateTime(2021, 7, 21) + EndingDate = 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) + EndingDate = new DateTime(2036, 6, 16) }); context.SaveChanges(); } diff --git a/client/src/VM/ProjectVM.ts b/client/src/VM/ProjectVM.ts index c44a9f7..2a974ce 100644 --- a/client/src/VM/ProjectVM.ts +++ b/client/src/VM/ProjectVM.ts @@ -9,32 +9,40 @@ export default class ProjectVM { public id: number; public title: string; public description: string; - public value: number; - public tickets: Ticket[]; + public creationDate: string; + public endingDate: string; + public progression: number; + public status: string; + public manager: User; public users: User[]; + public tickets: Ticket[]; + public files: AppFile[]; + public activities: Activity[]; public allUsers: User[]; public ticketsTotalCount: number; public ticketsDone: number; public remainingDays: number; - public files: AppFile[]; - public activities: Activity[]; public constructor(project: Project, allUsers: User[]) { this.id = project.id; this.title = project.title; this.description = project.description; + this.creationDate = project.creationDate; + this.endingDate = project.endingDate; + this.progression = project.progression; + this.status = project.status; + this.manager = project.manager; this.users = project.users; - this.allUsers = allUsers; - this.value = project.progression; this.tickets = project.tickets; + this.files = project.files; + this.activities = project.activities; + this.allUsers = allUsers; this.ticketsTotalCount = this.tickets === undefined ? 0 : this.tickets.length; this.ticketsDone = this.tickets === undefined ? 0 : this.tickets.filter(t => t.status === "Done").length; - this.files = project.files; - this.activities = project.activities; - this.remainingDays = getRemainingdays(project.plannedEnding); + this.remainingDays = getRemainingdays(project.endingDate); } } diff --git a/client/src/components/UsersModal.tsx b/client/src/components/UsersModal.tsx index 08800cf..99e8c53 100644 --- a/client/src/components/UsersModal.tsx +++ b/client/src/components/UsersModal.tsx @@ -4,7 +4,7 @@ import { AvatarList } from "./AvatarList"; import { User } from "../types/User"; import { FilterBar } from "./FilterBar"; import { HttpResponse } from "../types/HttpResponse"; -import { get, put } from "../utils/http"; +import { get, put, patch } from "../utils/http"; import { Constants } from "../utils/Constants"; import { UsersModalEntry } from "./UsersModalEntry"; import { useParams } from "react-router-dom"; @@ -38,12 +38,13 @@ export const UsersModal: FC = ({ ) => { e.preventDefault(); - const response: HttpResponse = await put( + const response: HttpResponse = await patch( `${Constants.projectsURI}/${id}/members`, members ); console.log(response); }; + console.log(allUsers); return ( diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index c7af7ec..f7680d8 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -17,7 +17,7 @@ export const ProjectPage: FC = ({ viewModel }) => { description, users, allUsers, - value, + progression, tickets, ticketsDone, ticketsTotalCount, @@ -49,7 +49,7 @@ export const ProjectPage: FC = ({ viewModel }) => { /> ( return await http(new Request(path, args)); } +export async function patch( + path: string, + body: any, + args: RequestInit = { + method: "patch", + headers: headers, + body: JSON.stringify(body) + } +): Promise> { + return await http(new Request(path, args)); +} + const headers: Headers = new Headers({ Accept: "application/json", "Content-Type": "application/json"