Add updatede nancy api modules and views.

This commit is contained in:
chris.watts90@outlook.com 2017-05-12 17:38:14 +01:00
parent 834875aa5f
commit a30a9a5453
16 changed files with 439 additions and 102 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
**/obj/**
**/packages/**
**/.vs/**
**dotsettings

View File

@ -2,6 +2,8 @@
{
public class Pilot
{
public int Id { get; set; }
public string ImageUrl { get; set; }
public string Name { get; set; }
public int TransponderToken { get; set; }
public string ThingyName { get; set; }

View File

@ -4,9 +4,17 @@ namespace RaceLapTimer.ApiControllers
{
public class InfoApiModule:NancyModule
{
public InfoApiModule() : base("/api/info")
private IDbProvider _provider;
public InfoApiModule(IDbProvider provider) : base("/api/info")
{
_provider = provider;
Get["/lastscanned"] = args => GetLastScannedId();
}
private dynamic GetLastScannedId()
{
return Response.AsJson(_provider.GetLastScannedId());
}
}
}

View File

@ -1,12 +1,52 @@
using Nancy;
using System;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class LapTrackApiModule:NancyModule
{
public LapTrackApiModule() : base("/api/laptrack")
private IDbProvider _dbProvider;
public LapTrackApiModule(IDbProvider provider) : base("/api/laptrack")
{
_dbProvider = provider;
Get["/create"] = args => LogLapTime(args);
}
private dynamic LogLapTime(dynamic args)
{
var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]);
var lapTimeInMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]);
var log = new SatelliteLog
{
TransponderToken = transponderToken,
LapTimeMS = lapTimeInMs
};
_dbProvider.StoreTransponderLog(log);
return HttpStatusCode.OK;
}
/*
a non-competition race will result in: 66f92adaf43f8f6ad96204ec being returned?
a competition race will result in:
{
"id": 7,
"created_at": "2017-05-10T19:31:27.517Z",
"created_at_timestamp": 1494444687,
"lap_num": 2,
"lap_time": 95000,
"pilot_id": 2,
"pilot": {
"name": "test2",
"quad": "testste",
"team": "tetststs"
},
"race_session_id": 6,
"race_session": {
"title": "Competition 1",
"mode": "competition"
}
}
*/
}
}

View File

@ -1,12 +1,160 @@
using Nancy;
using System;
using System.Collections.Generic;
using Interfaces;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class MonitorApiModule:NancyModule
public class MonitorApiModule : NancyModule
{
public MonitorApiModule() : base("api/monitor")
private IDbProvider _provider;
public MonitorApiModule(IDbProvider provider) : base("api/monitor")
{
_provider = provider;
Get[""] = args => GetRootMonitorData(args);
}
private dynamic GetRootMonitorData(dynamic args)
{
return Response.AsJson(new { data=_provider.GetRaceSessions(true)});
}
}
public interface IDbProvider
{
List<RaceSession> GetRaceSessions(bool getActive);
List<Pilot> GetPilotsList();
Pilot GetPilot(int pilotId);
bool CreatePilot(Pilot pilot);
int GetLastScannedId();
void StoreTransponderLog(SatelliteLog log);
}
public class TestProvider : IDbProvider
{
public List<RaceSession> GetRaceSessions(bool getActive)
{
return new List<RaceSession>
{
#region Session 1
new RaceSession
{
Active = true,
CreatedAt = DateTime.UtcNow,
HotSeatEnabled = false,
Id = 1,
IdleTimeSeconds = 400,
Mode = RaceMode.STANDARD,
MaxLaps = 20,
SatelliteCount = 1,
TimePenaltyPerSatellite = 100,
Title = "TEST Session 1"
},
#endregion
#region Session 2
new RaceSession
{
Active = true,
CreatedAt = DateTime.UtcNow,
HotSeatEnabled = false,
Id = 2,
IdleTimeSeconds = 400,
Mode = RaceMode.STANDARD,
MaxLaps = 10,
SatelliteCount = 1,
TimePenaltyPerSatellite = 100,
Title = "TEST Session 2"
},
#endregion
#region Session 3
new RaceSession
{
Active = getActive,
CreatedAt = DateTime.UtcNow,
HotSeatEnabled = false,
Id = 3,
IdleTimeSeconds = 400,
Mode = RaceMode.STANDARD,
MaxLaps = 10,
SatelliteCount = 1,
TimePenaltyPerSatellite = 100,
Title = "TEST Session 3"
},
#endregion
#region Session 3
new RaceSession
{
Active = getActive,
CreatedAt = DateTime.UtcNow,
HotSeatEnabled = false,
Id = 4,
IdleTimeSeconds = 400,
Mode = RaceMode.STANDARD,
MaxLaps = 10,
SatelliteCount = 1,
TimePenaltyPerSatellite = 100,
Title = "TEST Session 4"
}
#endregion
};
}
public List<Pilot> GetPilotsList()
{
return new List<Pilot>
{
new Pilot
{
Name = "Pilot1",
TeamName = "PilotTeam 1",
ThingyName = "Kart1",
TransponderToken = 222,
ImageUrl = "images/pilotPic.png"
},
new Pilot
{
Name = "Pilot 2",
TeamName = "Pilot Team 2",
ThingyName = "Kart2",
TransponderToken = 200
}
};
}
public Pilot GetPilot(int pilotId)
{
return new Pilot
{
Id = pilotId,
Name = "Pilot " + pilotId,
TeamName = "Team " + pilotId,
ThingyName = "Id:" + pilotId,
TransponderToken = pilotId
};
}
public bool CreatePilot(Pilot pilot)
{
var rand = new Random();
var numb = rand.NextDouble();
return numb > 0.5;
}
public int GetLastScannedId()
{
var rand = new Random();
return rand.Next(0, 100);
}
public void StoreTransponderLog(SatelliteLog log)
{
//do nothing.
}
}
}

View File

@ -1,13 +1,31 @@
using System.Web.Http;
using Interfaces;
using Nancy;
using Nancy.ModelBinding;
namespace RaceLapTimer.ApiControllers
{
public class PilotApiModule:NancyModule
{
public PilotApiModule() : base("/api/pilot")
private IDbProvider _provider;
public PilotApiModule(IDbProvider provider) : base("/api/pilot")
{
_provider = provider;
Get["/{id}"] = args => GetPilot(args);
Post["/edit"] = args => EditCreatePilot(args);
}
private dynamic GetPilot(dynamic args)
{
int pilotId = args.Id;
return Response.AsJson(_provider.GetPilot(pilotId));
}
private dynamic EditCreatePilot(dynamic args)
{
var pilotObject = this.Bind<Pilot>();
var resp = _provider.CreatePilot(pilotObject);
return Response.AsRedirect("/pilots");
}
}
}

View File

@ -0,0 +1,19 @@
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class PilotsApiModule : NancyModule
{
private readonly IDbProvider _provider;
public PilotsApiModule(IDbProvider provider) : base("/api/pilots")
{
_provider = provider;
Get[""] = args => GetPilotsList();
}
private dynamic GetPilotsList()
{
return Response.AsJson(new { data = _provider.GetPilotsList() });
}
}
}

View File

@ -1,4 +1,5 @@
using Interfaces;
using System.Collections.Generic;
using Interfaces;
using Nancy;
using Nancy.ModelBinding;
@ -6,9 +7,25 @@ namespace RaceLapTimer.ApiControllers
{
public class RaceSessionApiModule:NancyModule
{
public RaceSessionApiModule() : base("/api/racesession")
private readonly IDbProvider _provider;
public RaceSessionApiModule(IDbProvider provider) : base("/api/racesession")
{
_provider = provider;
Get[""] = args => GetRaceSessions();
Post["/create"] = args => CreateRaceSession(args);
Get["/historic"] = args => GetHistoricRaceSessions();
}
private dynamic GetHistoricRaceSessions()
{
var sessions = _provider.GetRaceSessions(false);
return Response.AsJson(new {data= sessions});
}
private dynamic GetRaceSessions()
{
var sessions = _provider.GetRaceSessions(true);
return Response.AsJson(new {data= sessions});
}
private dynamic CreateRaceSession(dynamic args)

View File

@ -1,12 +1,35 @@
using Nancy;
using System;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class SatelliteApiModule:NancyModule
{
public SatelliteApiModule() : base("/api/satellite")
private IDbProvider _provider;
public SatelliteApiModule(IDbProvider provider) : base("/api/satellite")
{
_provider = provider;
Get[""] = args => LogNewLapSatelliteTime(args);
}
private dynamic LogNewLapSatelliteTime(dynamic args)
{
var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]);
var lapTimeMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]);
var logObj = new SatelliteLog
{
TransponderToken = transponderToken,
LapTimeMS = lapTimeMs
};
_provider.StoreTransponderLog(logObj);
return HttpStatusCode.OK;
}
}
public class SatelliteLog
{
public int TransponderToken { get; set; }
public int LapTimeMS { get; set; }
}
}

View File

@ -1,17 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class SystemApiModule:NancyModule
public class SystemApiModule : NancyModule
{
public SystemApiModule() : base("/api/system")
{
Get["info"] = args => GetSystemInfo();
}
private dynamic GetSystemInfo()
{
return Response.AsJson(
new SystemInfo
{
Version = Assembly.GetEntryAssembly().GetName().Version.ToString()
});
}
}
public class SystemInfo
{
public string Version { get; set; }
}
}

View File

@ -2,8 +2,10 @@
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.Conventions;
using Nancy.Diagnostics;
using Nancy.TinyIoc;
using RaceLapTimer.ApiControllers;
namespace RaceLapTimer
{
@ -22,6 +24,7 @@ namespace RaceLapTimer
// Here we register our user mapper as a per-request singleton.
// As this is now per-request we could inject a request scoped
// database "context" or other request scoped services.
container.Register<IDbProvider, TestProvider>();
container.Register<IUserStorage, UserStorage>(); //register the storage provider..
container.Register<IUserMapper, UserDatabase>().AsSingleton();
}
@ -53,5 +56,13 @@ namespace RaceLapTimer
}
protected override IRootPathProvider RootPathProvider { get {return new NancyRootPathProvider();} }
protected override void ConfigureConventions(NancyConventions conventions)
{
base.ConfigureConventions(conventions);
conventions.StaticContentsConventions.Add(
StaticContentConventionBuilder.AddDirectory("images","images")
);
}
}
}

View File

@ -101,6 +101,7 @@
<Compile Include="ApiControllers\LapTrackApiModule.cs" />
<Compile Include="ApiControllers\MonitorApiModule.cs" />
<Compile Include="ApiControllers\PilotApiModule.cs" />
<Compile Include="ApiControllers\PilotsApiModule.cs" />
<Compile Include="ApiControllers\SatelliteApiModule.cs" />
<Compile Include="ApiControllers\SoundApiModule.cs" />
<Compile Include="ApiControllers\SystemApiModule.cs" />
@ -158,7 +159,6 @@
<ItemGroup>
<Folder Include="www\css\" />
<Folder Include="www\fonts\" />
<Folder Include="www\images\" />
<Folder Include="www\js\" />
</ItemGroup>
<ItemGroup>
@ -171,6 +171,11 @@
<Name>Interfaces</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="www\images\pilotPic.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets" Condition="Exists('..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@ -5,34 +5,42 @@
}
<h3>@ViewBag.Title</h3>
<table>
<table data-bind="with: raceSessions" class="table table-striped">
<thead>
<tr>
<td>Race Name</td>
<td>Pilot Count</td>
<td>Lap Count</td>
</tr>
<tr>
<td>Race Name</td>
<td>Idle Time (s)</td>
<td>Lap Count</td>
</tr>
</thead>
<tbody>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
</tr>
<tbody data-bind="foreach: data">
<tr>
<td data-bind="text: title"></td>
<td data-bind="text: idleTimeSeconds"></td>
<td data-bind="text: maxLaps"></td>
</tr>
</tbody>
</table>
</table>
<script type="text/javascript">
function ViewModel() {
'use strict';
var self = this;
self.raceSessions = ko.observable();
$.get("/api/monitor", {}, self.raceSessions);
self.tmrHandle = setInterval(function () {
self.getData();
}, 2000);
self.getData = function() {
$.get("/api/monitor", {}, self.raceSessions);
};
};
ViewModel.prototype.dispose = function () {
'use strict';
window.clearInterval(self.tmrHandle);
console.log("disposed of timer");
};
ko.applyBindings(new ViewModel());
</script>

View File

@ -5,39 +5,50 @@
}
<h3>@ViewBag.Title</h3>
<table>
<table class="table table-striped" data-bind="with: pilotsList">
<thead>
<tr>
<td>Name</td>
<td>Quad</td>
<td>Total Races</td>
<td>Total Laps</td>
<th></th>
<th>Pilot Name</th>
<th>Transponder Number</th>
<th>Kart Name</th>
<th>Team Name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tbody data-bind="foreach: data">
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
<td>10</td>
</tr>
<tr>
<td>None</td>
<td>0</td>
<td>10</td>
<td>10</td>
<td><img data-bind="attr:{src: imageUrl}" alt="pilotLogo" height="50" width="50"/></td>
<td data-bind="text: name"></td>
<td data-bind="text: transponderToken">-</td>
<td data-bind="text: thingyName">-</td>
<td data-bind="text: teamName">-</td>
<td><button class="btn btn-default" type="button">Edit</button></td>
<td><button class="btn btn-default" type="button">Delete</button></td>
</tr>
</tbody>
</table>
</table>
<script type="text/javascript">
function ViewModel() {
"use strict";
var self = this;
self.pilotsList = ko.observable();
$.get("/api/pilots", {}, self.pilotsList);
//self.tmrHandle = setInterval(function () {
// self.getData();
//}, 2000);
self.getData = function() {
$.get("/api/pilots", {}, self.pilotsList);
};
};
ViewModel.prototype.dispose = function () {
'use strict';
//window.clearInterval(self.tmrHandle);
console.log("disposed of timer");
};
ko.applyBindings(new ViewModel());
</script>

View File

@ -2,10 +2,21 @@
<!DOCTYPE html>
<html>
<head>
<script src="~/Content/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="~/Content/css/bootstrap.css" />
@*<script src="~/Content/js/jquery-3.2.1.min.js"></script>*@
@*<link rel="stylesheet" href="~/Content/css/bootstrap.css" />
<script src="~/Content/js/bootstrap.js"></script>
<link rel="stylesheet" href="~/Content/css/site.css"/>
<link rel="stylesheet" href="~/Content/css/site.css"/>*@
@*<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/fonts/glyphicons-halflings-regular.eot" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/fonts/glyphicons-halflings-regular.svg" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/fonts/glyphicons-halflings-regular.ttf" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2" />*@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js" type="text/javascript"></script>
<title>Razor Localization Demo</title>
</head>
<body>
@ -65,32 +76,32 @@
<!-- /.nav-collapse -->
</div>
</navbar>
<div class='container-fluid'>
<div class='container-fluid'>
<div class='row' style="margin-top: 40px;">
<div class='col-xs-12 center'>
@RenderBody()
</div>
</div>
<footer>
<div class='row'>
<div class='col-xs-12 center'>
@RenderBody()
<div class='col-lg-12'>
<p>
Made & Sponsored by
<a href='http://www.airbirds.de' rel='nofollow'>AirBirds</a>.
</p>
<p>
Code released under the
<a href='http://www.gnu.org/licenses/gpl-3.0.de.html'>GPL V3</a>.
</p>
<ul class='list-unstyled'>
<li class='pull-right'>
<a class='backtotop' href='#top'>Back to top</a>
</li>
</ul>
</div>
</div>
<footer>
<div class='row'>
<div class='col-lg-12'>
<p>
Made & Sponsored by
<a href='http://www.airbirds.de' rel='nofollow'>AirBirds</a>.
</p>
<p>
Code released under the
<a href='http://www.gnu.org/licenses/gpl-3.0.de.html'>GPL V3</a>.
</p>
<ul class='list-unstyled'>
<li class='pull-right'>
<a class='backtotop' href='#top'>Back to top</a>
</li>
</ul>
</div>
</div>
</footer>
</footer>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB