applying dto pattern

This commit is contained in:
Ruidy Nemausat 2020-02-26 22:45:52 +01:00
parent eec20793bc
commit deb3492475
18 changed files with 102 additions and 117 deletions

View file

@ -70,14 +70,13 @@ namespace TicketManager.Controllers
.ThenInclude(a => a.Project) .ThenInclude(a => a.Project)
.Include(u => u.Activities) .Include(u => u.Activities)
.AsNoTracking() .AsNoTracking()
.Select(u => new AppUserDTO(u))
.FirstOrDefaultAsync(u => u.Id == id); .FirstOrDefaultAsync(u => u.Id == id);
if (user == null) if (user == null)
{ {
return NotFound(); return NotFound();
} }
return user; return new AppUserDTO(user);
} }
/// <summary> /// <summary>

View file

@ -41,7 +41,7 @@ namespace TicketManager.Controllers
{ {
return await _context.Projects return await _context.Projects
.Include(p => p.Assignments) .Include(p => p.Assignments)
.ThenInclude(a => a.User) .ThenInclude(a => a.User)
.Include(p => p.Tickets) .Include(p => p.Tickets)
.Include(p => p.Manager) .Include(p => p.Manager)
.Include(p => p.Files) .Include(p => p.Files)
@ -76,14 +76,13 @@ namespace TicketManager.Controllers
.Include(p => p.Files) .Include(p => p.Files)
.Include(p => p.Activities) .Include(p => p.Activities)
.AsNoTracking() .AsNoTracking()
.Select(p => new ProjectDTO(p))
.FirstOrDefaultAsync(p => p.Id == id); .FirstOrDefaultAsync(p => p.Id == id);
if (project == null) if (project == null)
{ {
return NotFound(); return NotFound();
} }
return project; return new ProjectDTO(project);
} }
/// <summary> /// <summary>
@ -247,7 +246,7 @@ namespace TicketManager.Controllers
public async Task<ActionResult<Project>> SetProjectMembers(int id, List<AppUser> projectMembers) public async Task<ActionResult<Project>> SetProjectMembers(int id, List<AppUser> projectMembers)
{ {
Project project = await _context.Projects Project project = await _context.Projects
.Include(p => p.Assignments) // .Include(p => p.Assignments)
.FirstOrDefaultAsync(p => p.Id == id); .FirstOrDefaultAsync(p => p.Id == id);
if (project == null) if (project == null)

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using TicketManager.Models; using TicketManager.Models;
namespace TicketManager.DTO namespace TicketManager.DTO
@ -15,11 +16,11 @@ namespace TicketManager.DTO
Presentation = user.Presentation; Presentation = user.Presentation;
Email = user.Email; Email = user.Email;
Phone = user.Phone; Phone = user.Phone;
Created_at = user.Created_at; CreationDate = user.CreationDate;
Picture = user.Picture; Picture = user.Picture;
Activities = user.Activities; Activities = user.Activities;
Projects = user.GetProjects(); Projects = user.GetProjects().Select(u => new ProjectDTO(u)).ToList();
Tickets = user.GetTickets(); Tickets = user.GetTickets().Select(u => new TicketDTO(u)).ToList();
} }
public Guid Id { get; set; } public Guid Id { get; set; }
@ -39,14 +40,14 @@ namespace TicketManager.DTO
public string Phone { get; set; } public string Phone { get; set; }
[DataType(DataType.Date)] [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 string Picture { get; set; }
public List<Activity> Activities { get; set; } = new List<Activity>(); public List<Activity> Activities { get; set; } = new List<Activity>();
public List<Project> Projects { get; set; } = new List<Project>(); public List<ProjectDTO> Projects { get; set; } = new List<ProjectDTO>();
public List<Ticket> Tickets { get; set; } = new List<Ticket>(); public List<TicketDTO> Tickets { get; set; } = new List<TicketDTO>();
} }
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using TicketManager.Models; using TicketManager.Models;
@ -11,12 +12,13 @@ namespace TicketManager.DTO
Id = project.Id; Id = project.Id;
Title = project.Title; Title = project.Title;
Description = project.Description; Description = project.Description;
CreatedAt = project.CreatedAt; CreationDate = project.CreationDate;
EndingDate = project.EndingDate;
Progression = project.Progression; Progression = project.Progression;
Status = project.Status.ToString(); Status = project.Status.ToString();
Manager = project.Manager; // Manager = project.Manager != null ? new AppUserDTO(project.Manager) : null;
Users = project.GetMembers(); Users = project.GetMembers().Select(u => new AppUserDTO(u)).ToList();
Tickets = project.Tickets; Tickets = project.Tickets.Select(t => new TicketDTO(t)).ToList();
Activities = project.Activities; Activities = project.Activities;
Files = project.Files; Files = project.Files;
} }
@ -27,19 +29,19 @@ namespace TicketManager.DTO
public string Description { get; set; } 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 decimal Progression { get; set; }
public string Status { get; set; } public string Status { get; set; }
public AppUser Manager { get; set; } public AppUserDTO Manager { get; set; }
public List<AppUser> Users { get; set; } = new List<AppUser>(); public List<AppUserDTO> Users { get; set; } = new List<AppUserDTO>();
public List<Ticket> Tickets { get; set; } = new List<Ticket>(); public List<TicketDTO> Tickets { get; set; } = new List<TicketDTO>();
public List<Activity> Activities { get; set; } = new List<Activity>(); public List<Activity> Activities { get; set; } = new List<Activity>();

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using TicketManager.Models; using TicketManager.Models;
namespace TicketManager.DTO namespace TicketManager.DTO
@ -12,19 +13,20 @@ namespace TicketManager.DTO
Id = ticket.Id; Id = ticket.Id;
Title = ticket.Title; Title = ticket.Title;
Description = ticket.Description; Description = ticket.Description;
CreatedAt = ticket.CreatedAt; CreationDate = ticket.CreationDate;
PlannedEnding = ticket.PlannedEnding; EndingDate = ticket.EndingDate;
Status = ticket.Status.ToString(); Status = ticket.Status.ToString();
Impact = ticket.Impact.ToString(); Impact = ticket.Impact.ToString();
Difficulty = ticket.Difficulty.ToString(); Difficulty = ticket.Difficulty.ToString();
Category = ticket.Category.ToString(); Category = ticket.Category.ToString();
CreatorId = ticket.CreatorId; CreatorId = ticket.CreatorId;
Project = ticket.Project; Project = new ProjectDTO(ticket.Project);
Notes = ticket.Notes; Notes = ticket.Notes;
Activities = ticket.Activities; Activities = ticket.Activities;
Files = ticket.Files; Files = ticket.Files;
Users = ticket.GetAssignees(); Users = ticket.GetAssignees().Select(u => new AppUserDTO(u)).ToList();
} }
public int Id { get; set; } public int Id { get; set; }
public string Title { get; set; } public string Title { get; set; }
@ -32,10 +34,10 @@ namespace TicketManager.DTO
public string Description { get; set; } public string Description { get; set; }
[DataType(DataType.Date)] [DataType(DataType.Date)]
public DateTime CreatedAt { get; private set; } public DateTime CreationDate { get; private set; }
[DataType(DataType.Date)] [DataType(DataType.Date)]
public DateTime PlannedEnding { get; set; } public DateTime EndingDate { get; set; }
public string Status { get; set; } public string Status { get; set; }
@ -47,7 +49,7 @@ namespace TicketManager.DTO
public Guid CreatorId { get; set; } public Guid CreatorId { get; set; }
public Project Project { get; set; } public ProjectDTO Project { get; set; }
public List<Note> Notes { get; set; } = new List<Note>(); public List<Note> Notes { get; set; } = new List<Note>();
@ -55,6 +57,6 @@ namespace TicketManager.DTO
public List<File> Files { get; set; } = new List<File>(); public List<File> Files { get; set; } = new List<File>();
public List<AppUser> Users { get; set; } = new List<AppUser>(); public List<AppUserDTO> Users { get; set; } = new List<AppUserDTO>();
} }
} }

View file

@ -34,7 +34,7 @@ namespace TicketManager.Models
[DataType(DataType.Date)] [DataType(DataType.Date)]
[Display(Name = "Member since"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] [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")] [Display(Name = "Avatar")]
public string Picture { get; set; } public string Picture { get; set; }

View file

@ -20,11 +20,11 @@ namespace TicketManager.Models
[DataType(DataType.Date)] [DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = false)] [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)] [DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime PlannedEnding { get; set; } public DateTime EndingDate { get; set; }
[Display(Name = "Progress")] [Display(Name = "Progress")]
public decimal Progression public decimal Progression

View file

@ -18,11 +18,11 @@ namespace TicketManager.Models
[DataType(DataType.Date)] [DataType(DataType.Date)]
[Display(Name = "Creation Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] [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)] [DataType(DataType.Date)]
[Display(Name = "Estimated Ending Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")] [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 Status Status { get; set; } = Status.ToDo;
public Impact Impact { get; set; } = Impact.Undefined; public Impact Impact { get; set; } = Impact.Undefined;

View file

@ -48,3 +48,4 @@
- [ ] error page redirect when offline. - [ ] error page redirect when offline.
- [ ] ticket/files/activities list placeholders when empty - [ ] ticket/files/activities list placeholders when empty
- [ ] think about public/private DTO's constructor, getters and setters - [ ] think about public/private DTO's constructor, getters and setters
- [ ] write dtos without circular dependencies

View file

@ -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"
}

View file

@ -37,9 +37,6 @@ namespace TicketManager
options.EnableSensitiveDataLogging(true); //Remove in production. options.EnableSensitiveDataLogging(true); //Remove in production.
} }
); );
// services.AddScoped<IProjectRepository, ProjectRepository>();
// services.AddScoped<IAppUserRepository, AppUserRepository>();
// services.AddScoped<ITicketRepository, TicketRepository>();
services.AddAuthentication(options => services.AddAuthentication(options =>
{ {
@ -49,16 +46,14 @@ namespace TicketManager
{ {
options.Authority = "https://dev-fyjrvohx.auth0.com/"; options.Authority = "https://dev-fyjrvohx.auth0.com/";
options.Audience = "https://localhost:5001/api/V1/"; options.Audience = "https://localhost:5001/api/V1/";
//options.Authority = $"https://{Configuration["Auth0:Domain"]}/";
//options.Audience = Configuration["Auth0:Audience"];
}); });
services.AddControllers() services.AddControllers()
.AddNewtonsoftJson(options => .AddNewtonsoftJson(options =>
{ {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors
} }
); );
services.AddSpaStaticFiles(configuration => services.AddSpaStaticFiles(configuration =>
{ {

View file

@ -128,13 +128,13 @@ namespace TicketManager.Tests
Id = 1, Id = 1,
Title = "Top Secret Project", Title = "Top Secret Project",
Description = "Shht Don't Ask don't tell", Description = "Shht Don't Ask don't tell",
PlannedEnding = new DateTime(2020, 7, 21) EndingDate = new DateTime(2020, 7, 21)
} }
); );
// Should Update // Should Update
Assert.Equal("Top Secret Project", context.Projects.Find(1).Title); 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<NoContentResult>(result); Assert.IsType<NoContentResult>(result);
@ -144,13 +144,13 @@ namespace TicketManager.Tests
Id = 1, Id = 1,
Title = "Top Secret Project", Title = "Top Secret Project",
Description = "Shht Don't Ask don't tell", Description = "Shht Don't Ask don't tell",
PlannedEnding = new DateTime(2020, 7, 21) EndingDate = new DateTime(2020, 7, 21)
} }
); );
// Should Return BadRequest // Should Return BadRequest
Assert.NotEqual("Top Secret Project", context.Projects.Find(2).Title); 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<BadRequestResult>(result); Assert.IsType<BadRequestResult>(result);
// Delete updated project // Delete updated project
@ -163,14 +163,14 @@ namespace TicketManager.Tests
Id = 1, Id = 1,
Title = "Top Secret Project", Title = "Top Secret Project",
Description = "Shht Don't Ask don't tell", Description = "Shht Don't Ask don't tell",
PlannedEnding = new DateTime(2020, 7, 21) EndingDate = new DateTime(2020, 7, 21)
} }
); );
// Should Throw // Should Throw
Assert.IsType<NotFoundResult>(result); Assert.IsType<NotFoundResult>(result);
Assert.Equal("Top Secret Project", context.Projects.Find(1).Title); 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", Title = "The Third",
Description = "Thrice in a row", Description = "Thrice in a row",
PlannedEnding = DateTime.Now EndingDate = DateTime.Now
}; };
var controller = new ProjectsController(context); var controller = new ProjectsController(context);
@ -237,14 +237,14 @@ namespace TicketManager.Tests
Id = 1, Id = 1,
Title = "Secret Project", Title = "Secret Project",
Description = "Shht Don't Ask don't tell", Description = "Shht Don't Ask don't tell",
PlannedEnding = new DateTime(2021, 7, 21) EndingDate = new DateTime(2021, 7, 21)
}, },
new Project() new Project()
{ {
Id = 2, Id = 2,
Title = "Public Project", Title = "Public Project",
Description = "It's quite obvious, isn't it?!", Description = "It's quite obvious, isn't it?!",
PlannedEnding = new DateTime(2036, 6, 16) EndingDate = new DateTime(2036, 6, 16)
}); });
context.SaveChanges(); context.SaveChanges();
} }

View file

@ -9,32 +9,40 @@ export default class ProjectVM {
public id: number; public id: number;
public title: string; public title: string;
public description: string; public description: string;
public value: number; public creationDate: string;
public tickets: Ticket[]; public endingDate: string;
public progression: number;
public status: string;
public manager: User;
public users: User[]; public users: User[];
public tickets: Ticket[];
public files: AppFile[];
public activities: Activity[];
public allUsers: User[]; public allUsers: User[];
public ticketsTotalCount: number; public ticketsTotalCount: number;
public ticketsDone: number; public ticketsDone: number;
public remainingDays: number; public remainingDays: number;
public files: AppFile[];
public activities: Activity[];
public constructor(project: Project, allUsers: User[]) { public constructor(project: Project, allUsers: User[]) {
this.id = project.id; this.id = project.id;
this.title = project.title; this.title = project.title;
this.description = project.description; 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.users = project.users;
this.allUsers = allUsers;
this.value = project.progression;
this.tickets = project.tickets; this.tickets = project.tickets;
this.files = project.files;
this.activities = project.activities;
this.allUsers = allUsers;
this.ticketsTotalCount = this.ticketsTotalCount =
this.tickets === undefined ? 0 : this.tickets.length; this.tickets === undefined ? 0 : this.tickets.length;
this.ticketsDone = this.ticketsDone =
this.tickets === undefined this.tickets === undefined
? 0 ? 0
: this.tickets.filter(t => t.status === "Done").length; : this.tickets.filter(t => t.status === "Done").length;
this.files = project.files; this.remainingDays = getRemainingdays(project.endingDate);
this.activities = project.activities;
this.remainingDays = getRemainingdays(project.plannedEnding);
} }
} }

View file

@ -4,7 +4,7 @@ import { AvatarList } from "./AvatarList";
import { User } from "../types/User"; import { User } from "../types/User";
import { FilterBar } from "./FilterBar"; import { FilterBar } from "./FilterBar";
import { HttpResponse } from "../types/HttpResponse"; import { HttpResponse } from "../types/HttpResponse";
import { get, put } from "../utils/http"; import { get, put, patch } from "../utils/http";
import { Constants } from "../utils/Constants"; import { Constants } from "../utils/Constants";
import { UsersModalEntry } from "./UsersModalEntry"; import { UsersModalEntry } from "./UsersModalEntry";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
@ -38,12 +38,13 @@ export const UsersModal: FC<IProps> = ({
) => { ) => {
e.preventDefault(); e.preventDefault();
const response: HttpResponse<User[]> = await put<User[]>( const response: HttpResponse<User[]> = await patch<User[]>(
`${Constants.projectsURI}/${id}/members`, `${Constants.projectsURI}/${id}/members`,
members members
); );
console.log(response); console.log(response);
}; };
console.log(allUsers);
return ( return (
<Modal show={show} handleClose={handleClose}> <Modal show={show} handleClose={handleClose}>

View file

@ -17,7 +17,7 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
description, description,
users, users,
allUsers, allUsers,
value, progression,
tickets, tickets,
ticketsDone, ticketsDone,
ticketsTotalCount, ticketsTotalCount,
@ -49,7 +49,7 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
/> />
</div> </div>
<ProgressBar <ProgressBar
value={value} value={progression}
tasksDone={ticketsDone} tasksDone={ticketsDone}
tasksTotalCount={ticketsTotalCount} tasksTotalCount={ticketsTotalCount}
remainingDays={remainingDays} remainingDays={remainingDays}

View file

@ -7,8 +7,8 @@ export interface Project {
id: number; id: number;
title: string; title: string;
description: string; description: string;
createdAt: string; creationDate: string;
plannedEnding: string; endingDate: string;
progression: number; progression: number;
status: string; status: string;
manager: User; manager: User;

View file

@ -1,6 +1,18 @@
import { Activity } from "./Activity";
import { Project } from "./Project";
import { Ticket } from "./Ticket";
export interface User { export interface User {
id: string; id: string;
picture: string;
firstName: string; firstName: string;
fullName?: string; lastName: string;
fullName: string;
presentation: string;
email: string;
phone: string;
createdAt: string;
picture: string;
activities: Activity[];
projects: Project[];
tickets: Ticket[];
} }

View file

@ -42,6 +42,18 @@ export async function put<T>(
return await http<T>(new Request(path, args)); return await http<T>(new Request(path, args));
} }
export async function patch<T>(
path: string,
body: any,
args: RequestInit = {
method: "patch",
headers: headers,
body: JSON.stringify(body)
}
): Promise<HttpResponse<T>> {
return await http<T>(new Request(path, args));
}
const headers: Headers = new Headers({ const headers: Headers = new Headers({
Accept: "application/json", Accept: "application/json",
"Content-Type": "application/json" "Content-Type": "application/json"