From 515c964d559b8feb9d7d43d79a4d0ce5691fd502 Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Mon, 20 Jan 2020 16:28:21 -0800 Subject: [PATCH 1/6] #583 add unique email validation for create/edit user --- Machete.Web/Controllers/Legacy/AccountController.cs | 12 ++++++++++++ Machete.Web/Resources/ValidationStrings.Designer.cs | 9 +++++++++ Machete.Web/Resources/ValidationStrings.es.resx | 3 +++ Machete.Web/Resources/ValidationStrings.resx | 3 +++ 4 files changed, 27 insertions(+) diff --git a/Machete.Web/Controllers/Legacy/AccountController.cs b/Machete.Web/Controllers/Legacy/AccountController.cs index a802e18fb..758abf057 100644 --- a/Machete.Web/Controllers/Legacy/AccountController.cs +++ b/Machete.Web/Controllers/Legacy/AccountController.cs @@ -213,6 +213,12 @@ public async Task Register(RegisterViewModel model) { if (!ModelState.IsValid) return View(model); var newUserName = model.FirstName.Trim() + "." + model.LastName.Trim(); + var dupeUser = await _userManager.FindByEmailAsync(model.Email); + if (dupeUser != null && dupeUser.Email == model.Email) + { + ModelState.AddModelError("", ValidationStrings.dupeEmail); + return View(model); + } var user = new MacheteUser { UserName = newUserName, LoweredUserName = newUserName.ToLower(), ApplicationId = GetApplicationId(), Email = model.Email.Trim(), LoweredEmail = model.Email.Trim() }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) @@ -354,8 +360,14 @@ public async Task Edit([Bind]EditUserViewModel model) { var user = _context.Users.First(u => u.Id == model.Id); var macheteUserName = model.FirstName.Trim() + "." + model.LastName.Trim(); + var dupeUser = await _userManager.FindByEmailAsync(model.Email); user.UserName = macheteUserName; user.LoweredUserName = macheteUserName.ToLower(); + if (dupeUser != null && dupeUser.Email == model.Email) + { + ModelState.AddModelError("ErrorMessage", ValidationStrings.dupeEmail); + return View(model); + } user.Email = model.Email.Trim(); user.LoweredEmail = model.Email.Trim().ToLower(); user.IsApproved = model.IsApproved; diff --git a/Machete.Web/Resources/ValidationStrings.Designer.cs b/Machete.Web/Resources/ValidationStrings.Designer.cs index b1ebe669a..f7fe032f1 100644 --- a/Machete.Web/Resources/ValidationStrings.Designer.cs +++ b/Machete.Web/Resources/ValidationStrings.Designer.cs @@ -149,6 +149,15 @@ public static string emailValidation { return ResourceManager.GetString("emailValidation", resourceCulture); } } + + /// + /// Looks up a localized string to duplicate email error on Create. + /// + public static string dupeEmail { + get { + return ResourceManager.GetString("dupeEmail", resourceCulture); + } + } /// /// Looks up a localized string similar to First Name. diff --git a/Machete.Web/Resources/ValidationStrings.es.resx b/Machete.Web/Resources/ValidationStrings.es.resx index 9e5dbc47b..130f600ca 100644 --- a/Machete.Web/Resources/ValidationStrings.es.resx +++ b/Machete.Web/Resources/ValidationStrings.es.resx @@ -219,6 +219,9 @@ The email format is invalid + + Intente denuevo con otro email + Invalid username or password. diff --git a/Machete.Web/Resources/ValidationStrings.resx b/Machete.Web/Resources/ValidationStrings.resx index 4b4c9db18..5fa865ac6 100644 --- a/Machete.Web/Resources/ValidationStrings.resx +++ b/Machete.Web/Resources/ValidationStrings.resx @@ -231,6 +231,9 @@ The email format is invalid + + Please try a different email + Invalid username or password. From 48dcb0f3349b7eec6e37e318dde75c00a1fdbe33 Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Sun, 26 Jan 2020 20:54:16 -0800 Subject: [PATCH 2/6] #577 #581 print view TZ fix and new Activity report --- Machete.Data/Helpers/ClientTimeZoneHelper.cs | 10 ++++++++++ .../Initialize/MacheteReportDefinitions.cs | 20 +++++++++++++++++++ Machete.Data/Repositories/AllRepositories.cs | 7 ++++--- Machete.Service/WorkOrderService.cs | 2 +- .../Controllers/Legacy/WorkOrderController.cs | 4 ++-- 5 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 Machete.Data/Helpers/ClientTimeZoneHelper.cs diff --git a/Machete.Data/Helpers/ClientTimeZoneHelper.cs b/Machete.Data/Helpers/ClientTimeZoneHelper.cs new file mode 100644 index 000000000..8af7bca46 --- /dev/null +++ b/Machete.Data/Helpers/ClientTimeZoneHelper.cs @@ -0,0 +1,10 @@ +using System; + +namespace Machete.Data.Helpers +{ + public static class ClientTimeZoneHelper + { + public static DateTime DateBasedOn(this DateTime date, TimeZoneInfo clientTimeZoneInfo) => + TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(date, DateTimeKind.Unspecified), clientTimeZoneInfo).Date; + } +} \ No newline at end of file diff --git a/Machete.Data/Initialize/MacheteReportDefinitions.cs b/Machete.Data/Initialize/MacheteReportDefinitions.cs index 46760cf9a..ac5cc9d96 100644 --- a/Machete.Data/Initialize/MacheteReportDefinitions.cs +++ b/Machete.Data/Initialize/MacheteReportDefinitions.cs @@ -1340,6 +1340,26 @@ join lookups l on (ev.eventType = l.id) WHERE (w.dwccardnum = @dwccardnum)", inputsJson = "{\"beginDate\":false,\"endDate\":false,\"memberNumber\":true}" }, + // Worker Details -- activities + new ReportDefinition + { + name = "WorkerDetailsActivities", + commonName = "Worker Details, Activities attended", + description = + " A list of activities that a given worker attended", + category = "WorkerDetail", + sqlquery = + @"SELECT +a.nameEN as [Activity Name], +a.typeEN as [Activity Type], +a.teacher as [Teacher], +CONVERT(varchar, a.dateStart, 22) as [Start Time] +FROM ActivitySignins asi +JOIN Activities a +on asi.ActivityID = a.ID +WHERE asi.dwccardnum = @dwccardnum", + inputsJson = "{\"beginDate\":false,\"endDate\":false,\"memberNumber\":true}" + }, // Worker details -- jobs summary new ReportDefinition { diff --git a/Machete.Data/Repositories/AllRepositories.cs b/Machete.Data/Repositories/AllRepositories.cs index 46704230d..8d9ff8645 100644 --- a/Machete.Data/Repositories/AllRepositories.cs +++ b/Machete.Data/Repositories/AllRepositories.cs @@ -30,6 +30,7 @@ using Microsoft.EntityFrameworkCore; using System.Linq; using System.Text; +using Machete.Data.Helpers; namespace Machete.Data { @@ -60,7 +61,7 @@ public interface IEmailRepository : IRepository public interface IWorkOrderRepository : IRepository { - IEnumerable GetActiveOrders(DateTime date); + IEnumerable GetActiveOrders(DateTime date, TimeZoneInfo clientTimeZoneInfo); } public interface IWorkerRequestRepository : IRepository { WorkerRequest GetByID(int woid, int workerID); @@ -163,10 +164,10 @@ public class WorkOrderRepository : RepositoryBase, IWorkOrderReposito { public WorkOrderRepository(IDatabaseFactory databaseFactory) : base(databaseFactory) { } - public IEnumerable GetActiveOrders(DateTime date) + public IEnumerable GetActiveOrders(DateTime date, TimeZoneInfo clientTimeZoneInfo) { return dbset.Where(wo => wo.statusID == WorkOrder.iActive - && wo.dateTimeofWork.Date == date.Date) + && wo.dateTimeofWork.DateBasedOn(clientTimeZoneInfo) == date.Date) .Include(a => a.Employer) .Include(a => a.workerRequestsDDD) .ThenInclude(a => a.workerRequested) diff --git a/Machete.Service/WorkOrderService.cs b/Machete.Service/WorkOrderService.cs index 0478aaeae..5ab7e902a 100644 --- a/Machete.Service/WorkOrderService.cs +++ b/Machete.Service/WorkOrderService.cs @@ -109,7 +109,7 @@ ITenantService tenantService /// WorkOrders associated with a given date that are active public IEnumerable GetActiveOrders(DateTime date, bool assignedOnly) { - var matching = repo.GetActiveOrders(date); + var matching = repo.GetActiveOrders(date, _clientTimeZoneInfo); // .Where(wo => wo.statusID == WorkOrder.iActive // && wo.dateTimeofWork.Date == date.Date).ToList(); diff --git a/Machete.Web/Controllers/Legacy/WorkOrderController.cs b/Machete.Web/Controllers/Legacy/WorkOrderController.cs index e4c63e9de..dc4e743f3 100644 --- a/Machete.Web/Controllers/Legacy/WorkOrderController.cs +++ b/Machete.Web/Controllers/Legacy/WorkOrderController.cs @@ -353,9 +353,9 @@ public ActionResult ViewForEmail(int id) [Authorize(Roles = "Administrator, Manager")] public ActionResult GroupView(DateTime date, bool? assignedOnly) { - var utcDate = TimeZoneInfo.ConvertTimeToUtc(date, _clientTimeZoneInfo); + // var utcDate = TimeZoneInfo.ConvertTimeToUtc(date, _clientTimeZoneInfo); - var v = _woServ.GetActiveOrders(utcDate, assignedOnly ?? false).ToList(); + var v = _woServ.GetActiveOrders(date, assignedOnly ?? false).ToList(); MapperHelpers.ClientTimeZoneInfo = _clientTimeZoneInfo; MapperHelpers.Defaults = _defaults; From 64b8727dce87e9de6c123874b610797111236966 Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Sat, 1 Feb 2020 23:57:13 -0800 Subject: [PATCH 3/6] #580 feedback on validation fail - has space --- Machete.Web/Controllers/Legacy/AccountController.cs | 4 +++- Machete.Web/Resources/ValidationStrings.Designer.cs | 9 +++++++++ Machete.Web/Resources/ValidationStrings.es.resx | 3 +++ Machete.Web/Resources/ValidationStrings.resx | 3 +++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Machete.Web/Controllers/Legacy/AccountController.cs b/Machete.Web/Controllers/Legacy/AccountController.cs index 758abf057..d25db2a14 100644 --- a/Machete.Web/Controllers/Legacy/AccountController.cs +++ b/Machete.Web/Controllers/Legacy/AccountController.cs @@ -230,7 +230,9 @@ public async Task Register(RegisterViewModel model) foreach (var error in result.Errors) { - ModelState.AddModelError(error.Code, error.Description); + ModelState.AddModelError("", error.Description); + if (error.Description.Contains("is invalid, can only contain letters or digits") && newUserName.Contains(" ")) + ModelState.AddModelError("", ValidationStrings.NameHasSpace); } // If we got this far, something failed, redisplay form diff --git a/Machete.Web/Resources/ValidationStrings.Designer.cs b/Machete.Web/Resources/ValidationStrings.Designer.cs index f7fe032f1..a223f4ef4 100644 --- a/Machete.Web/Resources/ValidationStrings.Designer.cs +++ b/Machete.Web/Resources/ValidationStrings.Designer.cs @@ -320,6 +320,15 @@ public static string Register { return ResourceManager.GetString("Register", resourceCulture); } } + + /// + /// Looks up a localized string similar to NameHasSpace. + /// + public static string NameHasSpace { + get { + return ResourceManager.GetString("NameHasSpace", resourceCulture); + } + } /// /// Looks up a localized string similar to Use the form below to create a new account.. diff --git a/Machete.Web/Resources/ValidationStrings.es.resx b/Machete.Web/Resources/ValidationStrings.es.resx index 130f600ca..e07b243fa 100644 --- a/Machete.Web/Resources/ValidationStrings.es.resx +++ b/Machete.Web/Resources/ValidationStrings.es.resx @@ -156,6 +156,9 @@ Contraseña nueva + + Nombre y apellido no pueden contener espacios. Por favor, usar un guion " - " para unir dos palabras + Crear una cuenta diff --git a/Machete.Web/Resources/ValidationStrings.resx b/Machete.Web/Resources/ValidationStrings.resx index 5fa865ac6..12e2f1353 100644 --- a/Machete.Web/Resources/ValidationStrings.resx +++ b/Machete.Web/Resources/ValidationStrings.resx @@ -174,6 +174,9 @@ New Password + + Last name and first name must not contain spaces. To enter a name with multiple words, use hyphens " - " + Register From bbc8ed576eb96acdb217fc9297a86e69259920a9 Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Sat, 8 Feb 2020 17:48:53 -0800 Subject: [PATCH 4/6] Addressed all review items --- Machete.Data/Helpers/ClientTimeZoneHelper.cs | 10 ---------- Machete.Data/Initialize/MacheteReportDefinitions.cs | 3 ++- Machete.Data/Repositories/AllRepositories.cs | 3 +-- Machete.Web/Controllers/Legacy/WorkOrderController.cs | 4 ++-- Machete.Web/Resources/ValidationStrings.es.resx | 2 +- 5 files changed, 6 insertions(+), 16 deletions(-) delete mode 100644 Machete.Data/Helpers/ClientTimeZoneHelper.cs diff --git a/Machete.Data/Helpers/ClientTimeZoneHelper.cs b/Machete.Data/Helpers/ClientTimeZoneHelper.cs deleted file mode 100644 index 8af7bca46..000000000 --- a/Machete.Data/Helpers/ClientTimeZoneHelper.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Machete.Data.Helpers -{ - public static class ClientTimeZoneHelper - { - public static DateTime DateBasedOn(this DateTime date, TimeZoneInfo clientTimeZoneInfo) => - TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(date, DateTimeKind.Unspecified), clientTimeZoneInfo).Date; - } -} \ No newline at end of file diff --git a/Machete.Data/Initialize/MacheteReportDefinitions.cs b/Machete.Data/Initialize/MacheteReportDefinitions.cs index ac5cc9d96..fae026f8c 100644 --- a/Machete.Data/Initialize/MacheteReportDefinitions.cs +++ b/Machete.Data/Initialize/MacheteReportDefinitions.cs @@ -1357,7 +1357,8 @@ join lookups l on (ev.eventType = l.id) FROM ActivitySignins asi JOIN Activities a on asi.ActivityID = a.ID -WHERE asi.dwccardnum = @dwccardnum", +WHERE asi.dwccardnum = @dwccardnum +", inputsJson = "{\"beginDate\":false,\"endDate\":false,\"memberNumber\":true}" }, // Worker details -- jobs summary diff --git a/Machete.Data/Repositories/AllRepositories.cs b/Machete.Data/Repositories/AllRepositories.cs index 8d9ff8645..fcf681fea 100644 --- a/Machete.Data/Repositories/AllRepositories.cs +++ b/Machete.Data/Repositories/AllRepositories.cs @@ -30,7 +30,6 @@ using Microsoft.EntityFrameworkCore; using System.Linq; using System.Text; -using Machete.Data.Helpers; namespace Machete.Data { @@ -167,7 +166,7 @@ public WorkOrderRepository(IDatabaseFactory databaseFactory) : base(databaseFact public IEnumerable GetActiveOrders(DateTime date, TimeZoneInfo clientTimeZoneInfo) { return dbset.Where(wo => wo.statusID == WorkOrder.iActive - && wo.dateTimeofWork.DateBasedOn(clientTimeZoneInfo) == date.Date) + && TimeZoneInfo.ConvertTimeFromUtc(wo.dateTimeofWork, clientTimeZoneInfo).Date == TimeZoneInfo.ConvertTimeFromUtc(date, clientTimeZoneInfo).Date) .Include(a => a.Employer) .Include(a => a.workerRequestsDDD) .ThenInclude(a => a.workerRequested) diff --git a/Machete.Web/Controllers/Legacy/WorkOrderController.cs b/Machete.Web/Controllers/Legacy/WorkOrderController.cs index dc4e743f3..e4c63e9de 100644 --- a/Machete.Web/Controllers/Legacy/WorkOrderController.cs +++ b/Machete.Web/Controllers/Legacy/WorkOrderController.cs @@ -353,9 +353,9 @@ public ActionResult ViewForEmail(int id) [Authorize(Roles = "Administrator, Manager")] public ActionResult GroupView(DateTime date, bool? assignedOnly) { - // var utcDate = TimeZoneInfo.ConvertTimeToUtc(date, _clientTimeZoneInfo); + var utcDate = TimeZoneInfo.ConvertTimeToUtc(date, _clientTimeZoneInfo); - var v = _woServ.GetActiveOrders(date, assignedOnly ?? false).ToList(); + var v = _woServ.GetActiveOrders(utcDate, assignedOnly ?? false).ToList(); MapperHelpers.ClientTimeZoneInfo = _clientTimeZoneInfo; MapperHelpers.Defaults = _defaults; diff --git a/Machete.Web/Resources/ValidationStrings.es.resx b/Machete.Web/Resources/ValidationStrings.es.resx index e07b243fa..ff3fcdc06 100644 --- a/Machete.Web/Resources/ValidationStrings.es.resx +++ b/Machete.Web/Resources/ValidationStrings.es.resx @@ -157,7 +157,7 @@ Contraseña nueva - Nombre y apellido no pueden contener espacios. Por favor, usar un guion " - " para unir dos palabras + Nombre y apellido no pueden contener espacios. Por favor, usar un guión "-" para unir dos palabras Crear una cuenta From 1fcafe7f336e47dcb9388168de4483b8dbbf0547 Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Sat, 8 Feb 2020 18:33:27 -0800 Subject: [PATCH 5/6] Fixed to pass tests --- Machete.Data/Repositories/AllRepositories.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Machete.Data/Repositories/AllRepositories.cs b/Machete.Data/Repositories/AllRepositories.cs index fcf681fea..ea2a3dc2a 100644 --- a/Machete.Data/Repositories/AllRepositories.cs +++ b/Machete.Data/Repositories/AllRepositories.cs @@ -165,8 +165,11 @@ public WorkOrderRepository(IDatabaseFactory databaseFactory) : base(databaseFact public IEnumerable GetActiveOrders(DateTime date, TimeZoneInfo clientTimeZoneInfo) { + // date parameter comes in as Utc datetime, so convert before comparing + DateTime clientDate = TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(date, DateTimeKind.Unspecified), clientTimeZoneInfo); + return dbset.Where(wo => wo.statusID == WorkOrder.iActive - && TimeZoneInfo.ConvertTimeFromUtc(wo.dateTimeofWork, clientTimeZoneInfo).Date == TimeZoneInfo.ConvertTimeFromUtc(date, clientTimeZoneInfo).Date) + && TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(wo.dateTimeofWork, DateTimeKind.Unspecified), clientTimeZoneInfo).Date == clientDate.Date) .Include(a => a.Employer) .Include(a => a.workerRequestsDDD) .ThenInclude(a => a.workerRequested) From 8ec8fa353c62baff180290a439eb8a01ef4909bd Mon Sep 17 00:00:00 2001 From: esteban-gs Date: Sat, 8 Feb 2020 19:04:41 -0800 Subject: [PATCH 6/6] remove spaces because they are misleading --- Machete.Web/Resources/ValidationStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machete.Web/Resources/ValidationStrings.resx b/Machete.Web/Resources/ValidationStrings.resx index 12e2f1353..0cfb1b05f 100644 --- a/Machete.Web/Resources/ValidationStrings.resx +++ b/Machete.Web/Resources/ValidationStrings.resx @@ -175,7 +175,7 @@ New Password - Last name and first name must not contain spaces. To enter a name with multiple words, use hyphens " - " + Last name and first name must not contain spaces. To enter a name with multiple words, use hyphens "-" Register