This commit is contained in:
Ryan Peters 2022-11-28 08:51:10 -05:00
commit af9dc7be36
20 changed files with 210 additions and 38 deletions

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
@ -6,6 +6,16 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="users.json" />
</ItemGroup>
<ItemGroup>
<Content Include="users.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BinaryDad.Extensions" Version="21.4.20.3" /> <PackageReference Include="BinaryDad.Extensions" Version="21.4.20.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />

View File

@ -4,11 +4,11 @@ using System.Text.RegularExpressions;
namespace BinaryDad.AacpsBusAlert.Services namespace BinaryDad.AacpsBusAlert.Services
{ {
public class BusRouteService public class HtmlScrapeBusRouteService : IBusRouteService
{ {
private readonly HttpClient httpClient; private readonly HttpClient httpClient;
public BusRouteService(IHttpClientFactory httpClientFactory) public HtmlScrapeBusRouteService(IHttpClientFactory httpClientFactory)
{ {
httpClient = httpClientFactory.CreateClient(); httpClient = httpClientFactory.CreateClient();
} }

View File

@ -0,0 +1,7 @@
namespace BinaryDad.AacpsBusAlert.Services
{
public interface IBusRouteService
{
Task<ICollection<BusRoute>> GetBusRoutesAsync();
}
}

View File

@ -0,0 +1,8 @@
namespace BinaryDad.AacpsBusAlert.Services
{
public interface IUserService
{
ICollection<User> GetUsers();
User GetUser(Guid id);
}
}

View File

@ -0,0 +1,21 @@
using Newtonsoft.Json;
namespace BinaryDad.AacpsBusAlert.Services
{
public class JsonUserService : IUserService
{
public ICollection<User> GetUsers()
{
var path = Path.Combine(AppContext.BaseDirectory, "users.json");
var usersJson = File.ReadAllText(path);
return JsonConvert.DeserializeObject<ICollection<User>>(usersJson);
}
public User GetUser(Guid id)
{
return GetUsers().First(u => u.Id == id);
}
}
}

View File

@ -0,0 +1,23 @@
[
{
"Id": "b43f4f45-0f7b-4976-849d-8ad4b271199c",
"Email": "ryan@binarydad.com",
"Routes": [
{
"Id": "bfed1017-be53-42f9-bb46-ddbf27d4270f",
"BusNumber": 203,
"Label": "Con's Bus"
},
{
"Id": "bfed1017-be53-42f9-bb46-ddbf27d4270f",
"BusNumber": 457,
"Label": "Con's Activity Bus"
},
{
"Id": "bfed1017-be53-42f9-bb46-ddbf27d4270f",
"BusNumber": 365,
"Label": "Cam's Bus"
}
]
}
]

View File

@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "6.0.9",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@ -6,6 +6,10 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<_WebToolingArtifacts Remove="Properties\PublishProfiles\Release.pubxml" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BinaryDad.Extensions" Version="21.4.20.3" /> <PackageReference Include="BinaryDad.Extensions" Version="21.4.20.3" />
</ItemGroup> </ItemGroup>

View File

@ -6,9 +6,9 @@ namespace BinaryDad.AacpsBusAlert.Web.Controllers
[Route("api")] [Route("api")]
public class ApiController : Controller public class ApiController : Controller
{ {
private readonly BusRouteService busRouteService; private readonly IBusRouteService busRouteService;
public ApiController(BusRouteService busRouteService) public ApiController(IBusRouteService busRouteService)
{ {
this.busRouteService = busRouteService; this.busRouteService = busRouteService;
} }

View File

@ -9,24 +9,33 @@ namespace BinaryDad.AacpsBusAlert.Web.Controllers
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly ILogger<HomeController> logger; private readonly ILogger<HomeController> logger;
private readonly BusRouteService busRouteService; private readonly IBusRouteService busRouteService;
private readonly IUserService userService;
public HomeController(ILogger<HomeController> logger, BusRouteService busRouteService) public HomeController(ILogger<HomeController> logger, IBusRouteService busRouteService, IUserService userService)
{ {
this.logger = logger; this.logger = logger;
this.busRouteService = busRouteService; this.busRouteService = busRouteService;
this.userService = userService;
} }
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
{ {
var userRoutes = new[] { 203, 365, 277, 269, 274 }; var user = userService.GetUser(Guid.Parse("b43f4f45-0f7b-4976-849d-8ad4b271199c"));
//var busRoutes = await CacheHelper.GetAsync("BusRoutes", () => busRouteService.GetBusRoutesAsync()); //var busRoutes = await CacheHelper.GetAsync("BusRoutes", () => busRouteService.GetBusRoutesAsync());
var busRoutes = await busRouteService.GetBusRoutesAsync(); var busRoutes = await busRouteService.GetBusRoutesAsync();
var userRouteIds = user.Routes.Select(r => r.BusNumber).ToList();
var matchedBusRoutes = busRoutes.Join(userRoutes, r => r.BusNumber, u => u, (r, u) => r).ToList(); var matchedBusRoutes = busRoutes.Join(userRouteIds, r => r.BusNumber, u => u, (r, u) => r).ToList();
return View(matchedBusRoutes); var summary = new SummaryViewModel
{
User = user,
Routes = matchedBusRoutes
};
return View(summary);
} }
public IActionResult Privacy() public IActionResult Privacy()

View File

@ -0,0 +1,8 @@
namespace BinaryDad.AacpsBusAlert.Web.Models
{
public class SummaryViewModel
{
public User User { get; set; }
public ICollection<BusRoute> Routes { get; set; }
}
}

View File

@ -1,10 +1,12 @@
using BinaryDad.AacpsBusAlert.Services; using BinaryDad.AacpsBusAlert.Services;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddControllersWithViews(); builder.Services.AddControllersWithViews();
builder.Services.AddTransient<BusRouteService>(); builder.Services.AddSingleton<IBusRouteService, HtmlScrapeBusRouteService>();
builder.Services.AddSingleton<IUserService, JsonUserService>();
builder.Services.AddHttpClient(); builder.Services.AddHttpClient();
var app = builder.Build(); var app = builder.Build();
@ -12,8 +14,10 @@ var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment()) if (!app.Environment.IsDevelopment())
{ {
app.UseHttpsRedirection();
app.UseExceptionHandler("/Home/Error"); app.UseExceptionHandler("/Home/Error");
} }
app.UseStaticFiles(); app.UseStaticFiles();
app.UseRouting(); app.UseRouting();

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>false</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>\\server\Local\Web\AacpsBusAlert</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>67dec24b-132b-47cf-8afb-75e942076bc0</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View File

@ -1,16 +1,43 @@
@model ICollection<BusRoute> @model SummaryViewModel
@{ @{
ViewData["Title"] = "Home Page"; ViewData["Title"] = "Home Page";
var busRoutes = Model.OrderBy(r => r.BusNumber); var busRoutes = Model.Routes.OrderBy(r => r.BusNumber).ToList();
var hasDelays = busRoutes.Any();
var userBusRoutes = Model.User.Routes
.OrderBy(r => r.BusNumber)
.ToList();
} }
@foreach (var busRoute in busRoutes) @if (hasDelays)
{ {
<div> <div class="alert alert-danger">
<h3>@busRoute.BusNumber - @busRoute.Schools</h3> <h3 class="alert-heading">Uh oh</h3>
<p>@busRoute.Impact</p> We have @busRoutes.Count delays
<p>@busRoute.Schedules</p>
</div> </div>
} }
else
{
<div class="alert alert-success">
<h3 class="alert-heading">Good news!</h3>
No delays today!
</div>
}
<h4>My Buses</h4>
@foreach (var busRoute in userBusRoutes)
{
<div><strong>@busRoute.BusNumber - @busRoute.Label</strong></div>
}
<ul id="route-list">
@foreach (var busRoute in busRoutes)
{
<li>
<strong>@busRoute.BusNumber - @busRoute.Schools</strong>
<p>@busRoute.Impact @busRoute.Schedules</p>
</li>
}
</ul>

View File

@ -1,6 +0,0 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -12,7 +12,7 @@
<header> <header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3"> <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">BinaryDad.AacpsBusAlert.Web</a> <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">School Bus Checker</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent" <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation"> aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@ -38,7 +38,7 @@
<footer class="border-top footer text-muted"> <footer class="border-top footer text-muted">
<div class="container"> <div class="container">
&copy; 2022 - BinaryDad.AacpsBusAlert.Web - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> &copy; 2022 - School Bus Checker - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div> </div>
</footer> </footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="~/lib/jquery/dist/jquery.min.js"></script>

View File

@ -1,18 +1,24 @@
html { html {
font-size: 14px; font-size: 14px;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
html { html {
font-size: 16px; font-size: 16px;
} }
} }
html { html {
position: relative; position: relative;
min-height: 100%; min-height: 100%;
} }
body { body {
margin-bottom: 60px; margin-bottom: 60px;
} }
#route-list {
margin: 20px 0 0;
padding: 0;
list-style-type: none;
}

View File

@ -52,7 +52,7 @@ foreach (var userRoute in userRoutes.Value)
foreach (var matchedRoute in matchedRoutes) foreach (var matchedRoute in matchedRoutes)
{ {
Console.WriteLine($" {matchedRoute.BusRoute.BusNumber} ({matchedRoute.UserRoute.Label}): {matchedRoute.BusRoute.Impact} for {matchedRoute.BusRoute.Schedules}"); Console.WriteLine($" {matchedRoute.BusRoute.BusNumber} ({matchedRoute.UserRoute.Label}): {matchedRoute.BusRoute.Impact} for {matchedRoute.BusRoute.Schedules} at {matchedRoute.BusRoute.Schools}");
} }
} }

View File

@ -1,5 +1,6 @@
{ {
"Urls": { "Urls": {
"Api": "http://localhost:5299/" //"Api": "http://localhost:5299/",
"Api": "https://buses.binarydad.com/"
} }
} }

View File

@ -20,6 +20,22 @@
"Label": "Yet another test bus" "Label": "Yet another test bus"
} }
] ]
},
{
"Id": "b43f4f45-0f7b-4976-849d-8ad4b271199c",
"Email": "krystle@allwillynilly.com",
"Routes": [
{
"Id": "bfed1017-be53-42f9-bb46-ddbf27d4270f",
"BusNumber": 203,
"Label": "Vivi's Bus'"
},
{
"Id": "bfed1017-be53-42f9-bb46-ddbf27d4270f",
"BusNumber": 117,
"Label": "Ray's"
}
]
} }
] ]
} }