From 3d3a55266473976bcf59620daa7b6cd2039ef9f5 Mon Sep 17 00:00:00 2001 From: "chris.watts90@outlook.com" Date: Sun, 18 Jun 2017 19:38:01 +0100 Subject: [PATCH] ignore resharper settings file. centralise content on html pages. replaced single quote with double. added full racesession form to create competition race separate Monitor.cshtml js into own file. remove js manual redirection as solved server side redirect (Context.AsRedirect) add methods to create and stop race session in IDbProvider interface. implement file upload for pilot pictures. Will upload picture, save into /images/ folder, update pilot profile to take new image, delete the old one, and refresh the edit screen. --- .gitignore | 1 + .../ApiControllers/MonitorApiModule.cs | 2 +- .../ApiControllers/PilotApiModule.cs | 53 ++++++++++- .../ApiControllers/RaceSessionApiModule.cs | 12 ++- RaceLapTimer/RaceLapTimer/IDbProvider.cs | 9 +- .../RaceLapTimer/Modules/PilotModule.cs | 2 +- RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj | 35 ++++++- RaceLapTimer/RaceLapTimer/TestProvider.cs | 64 ++++++++++--- .../RaceLapTimer/www/Views/EditPilot.cshtml | 47 ++++++++++ .../RaceLapTimer/www/Views/Monitor.cshtml | 31 +------ .../RaceLapTimer/www/Views/Pilots.cshtml | 2 +- .../www/Views/RaceDirector.cshtml | 32 ++++++- .../www/Views/razor-layout.cshtml | 91 ++++++++++--------- .../RaceLapTimer/www/js/PilotObject.js | 9 ++ .../RaceLapTimer/www/js/RaceSessionObject.js | 15 +++ RaceLapTimer/RaceLapTimer/www/js/editPilot.js | 23 +++++ .../RaceLapTimer/www/js/raceDirector.js | 29 +++--- .../RaceLapTimer/www/js/supportingPages.js | 2 - 18 files changed, 336 insertions(+), 123 deletions(-) create mode 100644 RaceLapTimer/RaceLapTimer/www/Views/EditPilot.cshtml create mode 100644 RaceLapTimer/RaceLapTimer/www/js/PilotObject.js create mode 100644 RaceLapTimer/RaceLapTimer/www/js/RaceSessionObject.js create mode 100644 RaceLapTimer/RaceLapTimer/www/js/editPilot.js diff --git a/.gitignore b/.gitignore index 52a509f..1747694 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ **/packages/** **/.vs/** **dotsettings +**.DotSettings.user diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs index b11404c..177e329 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs @@ -15,7 +15,7 @@ namespace RaceLapTimer.ApiControllers private dynamic GetRootMonitorData(dynamic args) { - return Response.AsJson(new { data=_provider.GetRaceSessions(true)}); + return Response.AsJson(new { data = _provider.GetRaceSessions(true)}); } } } diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs index 2d14a9c..b88b4cc 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs @@ -1,21 +1,66 @@ -using System.Web.Http; +using System; +using System.IO; +using System.Linq; +using System.Web.Http; using Interfaces; using Nancy; +using Nancy.Extensions; using Nancy.ModelBinding; +using Nancy.Responses; namespace RaceLapTimer.ApiControllers { public class PilotApiModule:NancyModule { private readonly IDbProvider _provider; - public PilotApiModule(IDbProvider provider) : base("/api/pilot") + private readonly IRootPathProvider _rootPathProvider; + + public PilotApiModule(IDbProvider provider, IRootPathProvider pathProvider) : base("/api/pilot") { _provider = provider; + _rootPathProvider = pathProvider; Get["/{id}"] = args => GetPilot(args); Post["/edit"] = args => EditCreatePilot(args); Post["/create"] = args => EditCreatePilot(args); Get["/delete/{id}"] = args => DeletePilot(args); + Post["/upload/{id}"] = args => UploadPicture(args); + } + + private dynamic UploadPicture(dynamic args) + { + var pilotId = args.Id; + var pilot = (Pilot)_provider.GetPilot(pilotId); + var oldImagePath = pilot.ImageUrl; + + var uploadDirectory = Path.Combine(_rootPathProvider.GetRootPath(), "images"); + + if (!Directory.Exists(uploadDirectory)) + { + Directory.CreateDirectory(uploadDirectory); + } + + var file = Request.Files.First(); + + var newFileName = Guid.NewGuid(); + var generatedFileName = string.Format("{0}{1}",newFileName,Path.GetExtension(file.Name)); //0000-0000.....ext + + var filename = Path.Combine(uploadDirectory, generatedFileName); + + using (FileStream fileStream = new FileStream(filename, FileMode.Create)) + { + file.Value.CopyTo(fileStream); + fileStream.Flush(); + fileStream.Close(); + } + + pilot.ImageUrl = "/images/" + generatedFileName; + _provider.UpdatePilot(pilot); + + File.Delete(Path.Combine(uploadDirectory, oldImagePath)); + + string returnurl = "/pilot/edit/" + pilotId; + return Context.GetRedirect(returnurl); } private dynamic DeletePilot(dynamic args) @@ -34,9 +79,7 @@ namespace RaceLapTimer.ApiControllers { var pilotObject = this.Bind(); var resp = _provider.CreatePilot(pilotObject); - if(resp) - return new {url = "/pilots"}; - return "error"; + return Context.GetRedirect("/pilots"); } } } diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs index 8d2ea26..c4d0c97 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using Interfaces; using Nancy; +using Nancy.Extensions; using Nancy.ModelBinding; using Nancy.Responses; namespace RaceLapTimer.ApiControllers { - public class RaceSessionApiModule:NancyModule + public class RaceSessionApiModule : NancyModule { private readonly IDbProvider _provider; public RaceSessionApiModule(IDbProvider provider) : base("/api/racesession") @@ -20,19 +21,20 @@ namespace RaceLapTimer.ApiControllers private dynamic GetHistoricRaceSessions() { var sessions = _provider.GetRaceSessions(false); - return Response.AsJson(new {data= sessions}); + return Response.AsJson(new { data = sessions }); } private dynamic GetRaceSessions() { var sessions = _provider.GetRaceSessions(true); - return Response.AsJson(new {data= sessions}); + return Response.AsJson(new { data = sessions }); } private dynamic CreateRaceSession(dynamic args) { - var postObject = this.Bind(); - return new {url="/racedirector"}; + var session = this.Bind(); + var res = _provider.CreateRaceSession(session); + return Context.GetRedirect("/racedirector"); } } } \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/IDbProvider.cs b/RaceLapTimer/RaceLapTimer/IDbProvider.cs index f267c70..51d9dcd 100644 --- a/RaceLapTimer/RaceLapTimer/IDbProvider.cs +++ b/RaceLapTimer/RaceLapTimer/IDbProvider.cs @@ -1,18 +1,25 @@ using System.Collections.Generic; using Interfaces; +using RaceLapTimer.ApiControllers; -namespace RaceLapTimer.ApiControllers +namespace RaceLapTimer { public interface IDbProvider { List GetRaceSessions(bool getActive); + bool CreateRaceSession(RaceSession session); + + bool StopRaceSession(RaceSession session); + List GetPilotsList(); Pilot GetPilot(int pilotId); bool CreatePilot(Pilot pilot); + bool UpdatePilot(Pilot pilot); + int GetLastScannedId(); void StoreTransponderLog(SatelliteLog log); diff --git a/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs b/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs index 9211af0..6435161 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs @@ -18,7 +18,7 @@ namespace RaceLapTimer.Modules private dynamic EditPilot(dynamic args) { - return View["EditPilot.cshtml"]; + return View["EditPilot.cshtml", new {Id=args.id}]; } } } diff --git a/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj b/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj index bf79b05..a643791 100644 --- a/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj +++ b/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj @@ -155,6 +155,13 @@ + + + + + + Always + Always @@ -178,10 +185,7 @@ Always - - - - + {bc7dea8b-5029-459a-aa54-ea81eb390f87} @@ -199,9 +203,32 @@ PreserveNewest + + + + + + Always + + Always + + + + Always + + + Always + + + + Always + + + Always + Always diff --git a/RaceLapTimer/RaceLapTimer/TestProvider.cs b/RaceLapTimer/RaceLapTimer/TestProvider.cs index bdabdca..a89ca43 100644 --- a/RaceLapTimer/RaceLapTimer/TestProvider.cs +++ b/RaceLapTimer/RaceLapTimer/TestProvider.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Linq; using Interfaces; +using RaceLapTimer.ApiControllers; -namespace RaceLapTimer.ApiControllers +namespace RaceLapTimer { public class TestProvider : IDbProvider { - readonly List _pilots; + private readonly List _pilots; + private readonly List _sessions; public TestProvider() { @@ -21,7 +23,7 @@ namespace RaceLapTimer.ApiControllers TeamName = "PilotTeam 1", ThingyName = "Kart1", TransponderToken = 222, - ImageUrl = "images/pilotPic.png" + ImageUrl = "/images/pilotPic.png" }, new Pilot { @@ -31,13 +33,10 @@ namespace RaceLapTimer.ApiControllers ThingyName = "Kart2", TransponderToken = 200 } - }; + }; #endregion - } - - public List GetRaceSessions(bool getActive) - { - return new List + #region RaceSessions + _sessions = new List { #region Session 1 new RaceSession @@ -72,7 +71,7 @@ namespace RaceLapTimer.ApiControllers #region Session 3 new RaceSession { - Active = getActive, + Active = false, CreatedAt = DateTime.UtcNow, HotSeatEnabled = false, Id = 3, @@ -87,7 +86,7 @@ namespace RaceLapTimer.ApiControllers #region Session 3 new RaceSession { - Active = getActive, + Active = false, CreatedAt = DateTime.UtcNow, HotSeatEnabled = false, Id = 4, @@ -100,6 +99,34 @@ namespace RaceLapTimer.ApiControllers } #endregion }; + #endregion + } + + public List GetRaceSessions(bool getActive) + { + return getActive ? _sessions.Where(x => x.Active == getActive).ToList() : _sessions; + } + + public bool CreateRaceSession(RaceSession session) + { + _sessions.Add(session); + return true; + } + + public bool StopRaceSession(RaceSession session) + { + var selectedSession = _sessions.FirstOrDefault(x => x.CreatedAt == session.CreatedAt + && x.Title == session.Title + && x.MaxLaps == session.MaxLaps + && x.Mode == session.Mode + && x.IdleTimeSeconds == session.IdleTimeSeconds); + if (selectedSession == null) + { + return false; + } + selectedSession.Active = false; + selectedSession.UpdatedAt = DateTime.UtcNow; + return true; } public List GetPilotsList() @@ -121,6 +148,21 @@ namespace RaceLapTimer.ApiControllers return true; } + public bool UpdatePilot(Pilot pilot) + { + if (_pilots.All(x => x.Id != pilot.Id)) + { + return false; + } + var p = _pilots.First(x => x.Id == pilot.Id); + p.ImageUrl = pilot.ImageUrl; + p.TransponderToken = pilot.TransponderToken; + p.Name = pilot.Name; + p.TeamName = pilot.TeamName; + p.ThingyName = pilot.ThingyName; + return true; + } + public bool DeletePilot(int id) { return _pilots.Remove(_pilots.FirstOrDefault(x => x.Id == id)); diff --git a/RaceLapTimer/RaceLapTimer/www/Views/EditPilot.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/EditPilot.cshtml new file mode 100644 index 0000000..742069a --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/Views/EditPilot.cshtml @@ -0,0 +1,47 @@ +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@{ + Layout = "razor-layout.cshtml"; + ViewBag.Title = "Pilot Editor"; + ViewBag.EditPilotEndpoint = "/api/pilot/edit"; + ViewBag.UploadImageUrl = "/api/pilot/upload/" + Model.Id; +} + +

@ViewBag.Title

+ +
+ @Html.AntiForgeryToken() + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + pilotImage +
+ +
+
+
+
+ + +
+ +
+ + + \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/Views/Monitor.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/Monitor.cshtml index 0b8adde..dbd4442 100644 --- a/RaceLapTimer/RaceLapTimer/www/Views/Monitor.cshtml +++ b/RaceLapTimer/RaceLapTimer/www/Views/Monitor.cshtml @@ -21,33 +21,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/Views/Pilots.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/Pilots.cshtml index 52a5899..4996f4b 100644 --- a/RaceLapTimer/RaceLapTimer/www/Views/Pilots.cshtml +++ b/RaceLapTimer/RaceLapTimer/www/Views/Pilots.cshtml @@ -5,7 +5,7 @@ ViewBag.CreateUserEndpoint = "/api/pilot/create"; }

@ViewBag.Title

- +
@Html.AntiForgeryToken() diff --git a/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml index 018a61b..685f107 100644 --- a/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml +++ b/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml @@ -15,16 +15,40 @@

Last Lap Times

- +
- - + +
- +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/Views/razor-layout.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/razor-layout.cshtml index 7d32d07..b71df0e 100644 --- a/RaceLapTimer/RaceLapTimer/www/Views/razor-layout.cshtml +++ b/RaceLapTimer/RaceLapTimer/www/Views/razor-layout.cshtml @@ -4,14 +4,10 @@ @**@ @* - - *@ - @* - - - - *@ - + + *@ + + @@ -20,39 +16,39 @@ Razor Localization Demo -
- -
- -