Port across BaseController functionality to ASP.NET Core Middleware

This commit is contained in:
BuildFeed Bot 2018-10-24 22:45:18 +01:00
parent 6895178168
commit 5d3502325d
No known key found for this signature in database
GPG Key ID: 3757685ADD91E0A1
31 changed files with 353 additions and 205 deletions

6
.gitignore vendored
View File

@ -232,3 +232,9 @@ $RECYCLE.BIN/
*.msp
*.pubxml
BuildFeed/settings.config
# JetBrains IDEA config
.idea/
# VSCode
.vscode/

View File

@ -3,7 +3,9 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnet-BuildFeed-794E2AE1-72C2-4F00-B783-1C78917251E7</UserSecretsId>
<TypeScriptToolsVersion>3.0</TypeScriptToolsVersion>
<TypeScriptToolsVersion>3.1</TypeScriptToolsVersion>
<MSBuildGitHashValidate>False</MSBuildGitHashValidate>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
@ -15,6 +17,7 @@
<PackageReference Include="Humanizer" Version="2.5.1" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.5" PrivateAssets="All" />
<PackageReference Include="MSBuildGitHash" Version="0.3.0" />
<PackageReference Include="OneSignal.RestAPIv3.Client" Version="1.0.3" />
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
</ItemGroup>

View File

@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

View File

@ -6,12 +6,12 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace BuildFeed.Code
namespace BuildFeed
{
public static class MvcExtensions
{
public static string CheckboxListForEnum<T>(this HtmlHelper html, string id, T currentItem)
where T : struct
where T : Enum
{
var sb = new StringBuilder();
@ -58,11 +58,12 @@ public static string CheckboxListForEnum<T>(this HtmlHelper html, string id, T c
return sb.ToString();
}
public static string GetDisplayTextForEnum(object o)
public static string GetDisplayTextForEnum<T>(T enumObj)
where T : Enum
{
string result = null;
DisplayAttribute display = o.GetType()
.GetMember(o.ToString())
DisplayAttribute display = enumObj.GetType()
.GetMember(enumObj.ToString())
.First()
.GetCustomAttributes(false)
.OfType<DisplayAttribute>()
@ -73,14 +74,15 @@ public static string GetDisplayTextForEnum(object o)
result = display.GetName();
}
return result ?? o.ToString();
return result ?? enumObj.ToString();
}
public static string GetDisplayDescriptionForEnum(object o)
public static string GetDisplayDescriptionForEnum<T>(T enumObj)
where T : Enum
{
string result = null;
DisplayAttribute display = o.GetType()
.GetMember(o.ToString())
DisplayAttribute display = enumObj.GetType()
.GetMember(enumObj.ToString())
.First()
.GetCustomAttributes(false)
.OfType<DisplayAttribute>()
@ -91,7 +93,7 @@ public static string GetDisplayDescriptionForEnum(object o)
result = display.GetDescription() ?? display.GetName();
}
return result ?? o.ToString();
return result ?? enumObj.ToString();
}
public static string ToLongDateWithoutDay(this DateTime dt)

View File

@ -0,0 +1,48 @@
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace BuildFeed.Middleware
{
public static class LocaleMiddleware
{
private const string LANG_COOKIE_NAME = "bf_lang";
private static Task LoadLocaleFromCookie(HttpContext context, Func<Task> next)
{
bool cookieHasValue = context.Request.Cookies.TryGetValue(LANG_COOKIE_NAME, out string langCookie);
if (!cookieHasValue || string.IsNullOrEmpty(langCookie))
{
return next();
}
try
{
var ci = (CultureInfo)CultureInfo.GetCultureInfo(langCookie).Clone();
// Get Gregorian Calendar in locale if available
Calendar gc = ci.OptionalCalendars.FirstOrDefault(c
=> c is GregorianCalendar calendar
&& calendar.CalendarType == GregorianCalendarTypes.Localized);
if (gc != null)
{
ci.DateTimeFormat.Calendar = gc;
}
CultureInfo.CurrentCulture = ci;
CultureInfo.CurrentUICulture = ci;
}
catch (CultureNotFoundException)
{
}
return next();
}
public static IApplicationBuilder UseLocalisation(this IApplicationBuilder app) => app.Use(LoadLocaleFromCookie);
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Threading.Tasks;
using BuildFeed.Options;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace BuildFeed.Middleware
{
public static class ThemeMiddleware
{
private const string THEME_COOKIE_NAME = "bf_theme";
private static Task LoadThemeFromCookie(HttpContext context, Func<Task> next)
{
bool cookieHasValue = context.Request.Cookies.TryGetValue(THEME_COOKIE_NAME, out string themeCookie);
var theme = SiteTheme.Dark;
if (cookieHasValue && !string.IsNullOrEmpty(themeCookie))
{
Enum.TryParse(themeCookie, out theme);
}
var themeObj = new Theme(theme);
context.Features.Set(themeObj);
return next();
}
public static IApplicationBuilder UseThemes(this IApplicationBuilder app) => app.Use(LoadThemeFromCookie);
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace BuildFeed.Middleware
{
public static class OptionsMiddleware
{
private static Task LoadVersionInfo(HttpContext context, Func<Task> next)
{
string versionString = Assembly.GetExecutingAssembly()
.GetCustomAttributes(typeof(AssemblyMetadataAttribute))
.OfType<AssemblyMetadataAttribute>()
.FirstOrDefault(a => a.Key == "GitHash")
?.Value
?? "N/A";
context.Items.TryAdd("Version", versionString);
return next();
}
public static IApplicationBuilder UseVersion(this IApplicationBuilder app) => app.Use(LoadVersionInfo);
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using BuildFeed.Local;
using BuildFeed.Model;
@ -8,7 +7,7 @@
using OneSignal.RestAPIv3.Client.Resources;
using OneSignal.RestAPIv3.Client.Resources.Notifications;
namespace BuildFeed.Code
namespace BuildFeed
{
public static class OneSignalHelper
{
@ -46,9 +45,7 @@ public static void PushNewBuild(this OneSignalClient osc, Guid appId, Build buil
{ LanguageCodes.Lithuanian, GetNewBuildTitleForLanguage("lt") },
{ LanguageCodes.Dutch, GetNewBuildTitleForLanguage("nl") },
{ LanguageCodes.Polish, GetNewBuildTitleForLanguage("pl") },
{
LanguageCodes.Portuguese, GetNewBuildTitleForLanguage("pt")
}, // Portuguese translation has notification translation ready, Brazil is used more, but not available right now.
{ LanguageCodes.Portuguese, GetNewBuildTitleForLanguage("pt") }, // Portuguese translation has notification translation ready, Brazil is used more, but not available right now.
{ LanguageCodes.Romanian, GetNewBuildTitleForLanguage("ro") },
{ LanguageCodes.Russian, GetNewBuildTitleForLanguage("ru") },
{ LanguageCodes.Slovak, GetNewBuildTitleForLanguage("sk") },

View File

@ -0,0 +1,56 @@
using System.Globalization;
using System.Linq;
namespace BuildFeed.Options
{
public class Locale
{
public static readonly Locale[] AvailableLocales =
{
new Locale("ar"),
//new Locale("bn"),
new Locale("cs"),
new Locale("de"),
new Locale("el"),
new Locale("en"),
new Locale("es"),
new Locale("fa"),
new Locale("fi"),
new Locale("fr"),
new Locale("he"),
new Locale("hr"),
new Locale("hu"),
new Locale("id"),
new Locale("it"),
new Locale("ja"),
new Locale("ko"),
new Locale("lt"),
new Locale("nl"),
new Locale("pl"),
new Locale("pt"),
new Locale("pt-BR"),
new Locale("qps-Ploc"),
new Locale("ro"),
new Locale("ru"),
new Locale("sk"),
new Locale("sl"),
new Locale("sv"),
new Locale("tr"),
new Locale("uk"),
new Locale("vi"),
new Locale("zh-Hans"),
new Locale("zh-Hant")
};
public string DisplayName => Info.NativeName;
public CultureInfo Info { get; }
public string LocaleId { get; }
private Locale(string localeId)
{
LocaleId = localeId;
Info = CultureInfo.GetCultureInfo(localeId);
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using BuildFeed.Local;
namespace BuildFeed.Options
{
public class Theme
{
public static readonly ImmutableArray<Theme> AvailableThemes = Enum.GetValues(typeof(SiteTheme))
.Cast<SiteTheme>()
.Select(st => new Theme(st))
.ToImmutableArray();
public string CookieValue => Value.ToString();
public string CssPath => $"~/res/css/{Value.ToString().ToLower()}.css";
public string DisplayName => MvcExtensions.GetDisplayTextForEnum(Value);
public SiteTheme Value { get; }
public Theme(SiteTheme st)
{
Value = st;
}
}
public enum SiteTheme
{
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeDark))]
Dark = 0,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeLight))]
Light,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeWinter))]
Winter
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
@ -8,10 +7,8 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BuildFeed.Code;
using BuildFeed.Model;
using BuildFeed.Model.View;
using Microsoft.AspNetCore.Authorization;
@ -19,14 +16,13 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Protocols;
using OneSignal.RestAPIv3.Client;
namespace BuildFeed.Controllers
{
public class FrontController : Controller
{
public const int PAGE_SIZE = 72;
private const int PAGE_SIZE = 72;
private readonly BuildRepository _bModel;
private readonly MetaItem _mModel;
@ -42,10 +38,6 @@ public FrontController(IHostingEnvironment env, IConfiguration config, BuildRepo
}
[Route("", Order = 1)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> Index()
{
ViewBag.Versions = await _bModel.SelectAllFamilies();
@ -57,10 +49,6 @@ public async Task<ActionResult> Index()
}
[Route("page-{page:int:min(1)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> IndexPage(int page)
{
var buildGroups = await _bModel.SelectAllGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE);
@ -79,11 +67,6 @@ public async Task<ActionResult> IndexPage(int page)
[Route("group/{major}.{minor}.{number}.{revision}/", Order = 1)]
[Route("group/{major}.{minor}.{number}/", Order = 5)]
// for when there is no revision
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewGroup(uint major, uint minor, uint number, uint? revision = null)
{
var bg = new BuildGroup
@ -106,10 +89,6 @@ public async Task<ActionResult> ViewGroup(uint major, uint minor, uint number, u
}
[Route("build/{id:guid}/", Name = "Build")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewBuild(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -138,10 +117,6 @@ public async Task<ActionResult> ViewBuild(long id)
}
[Route("twitter/{id:guid}/", Name = "Twitter")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[CustomContentType(ContentType = "image/png", Order = 2)]
#endif
public async Task<ActionResult> TwitterCard(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -286,20 +261,12 @@ public async Task<ActionResult> TwitterCard(long id)
}
[Route("family/{family}/", Order = 1, Name = "Family Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewFamily(ProjectFamily family)
{
return await ViewFamilyPage(family, 1);
}
[Route("family/{family}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewFamilyPage(ProjectFamily family, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -325,20 +292,12 @@ public async Task<ActionResult> ViewFamilyPage(ProjectFamily family, int page)
}
[Route("lab/{lab}/", Order = 1, Name = "Lab Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewLab(string lab)
{
return await ViewLabPage(lab, 1);
}
[Route("lab/{lab}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewLabPage(string lab, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -364,20 +323,12 @@ public async Task<ActionResult> ViewLabPage(string lab, int page)
}
[Route("source/{source}/", Order = 1, Name = "Source Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewSource(TypeOfSource source)
{
return await ViewSourcePage(source, 1);
}
[Route("source/{source}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewSourcePage(TypeOfSource source, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -403,20 +354,12 @@ public async Task<ActionResult> ViewSourcePage(TypeOfSource source, int page)
}
[Route("year/{year}/", Order = 1, Name = "Year Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewYear(int year)
{
return await ViewYearPage(year, 1);
}
[Route("year/{year}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewYearPage(int year, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -441,20 +384,12 @@ public async Task<ActionResult> ViewYearPage(int year, int page)
}
[Route("version/{major}.{minor}/", Order = 1, Name = "Version Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewVersion(uint major, uint minor)
{
return await ViewVersionPage(major, minor, 1);
}
[Route("version/{major}.{minor}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewVersionPage(uint major, uint minor, int page)
{
string valueString = $"{major}.{minor}";

View File

@ -3,14 +3,14 @@
namespace BuildFeed
{
public class Program
public static class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

View File

@ -1,7 +1,7 @@
using BuildFeed.Model;
using BuildFeed.Middleware;
using BuildFeed.Model;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@ -10,7 +10,7 @@ namespace BuildFeed
{
public class Startup
{
public IConfiguration Configuration { get; }
private IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
@ -22,7 +22,7 @@ public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient(provider => Configuration);
services.AddSingleton(provider => Configuration);
var config = new MongoConfig(
Configuration.GetValue<string>("data:MongoHost"),
@ -55,12 +55,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
});
app.UseThemes();
app.UseLocalisation();
app.UseVersion();
app.UseMvc();
}
}
}

View File

@ -1,6 +1,9 @@
@using System.Globalization
@using BuildFeed.Options
@using System.Globalization
@{
bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
var theme = Context.Features.Get<Theme>();
string version = Context.Items["Version"] as string;
}<!DOCTYPE html>
<html dir="@(isRtl
? "rtl"
@ -12,7 +15,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>@ViewBag.Title</title>
<link href="~/res/css/default.css" rel="stylesheet" type="text/css" />
<link href="~/res/css/dark.css" rel="stylesheet" type="text/css" />
<link href="@(Url.Content(theme.CssPath))" rel="stylesheet" type="text/css" />
@if (isRtl)
{
<link href="~/res/css/rtl.css" rel="stylesheet" type="text/css" />
@ -205,35 +208,35 @@
<ul class="dropdown-menu">
<li id="settings-theme-menu" class="dropdown-menu-block">
<h4>@VariantTerms.Common_NavigationTheme</h4>
@*<ul>
@foreach (Theme item in Theme.AvailableThemes)
{
<li>
<a href="#" data-theme="@item.CookieValue">@item.DisplayName</a>
</li>
}
</ul>*@
<ul>
@foreach (Theme item in Theme.AvailableThemes)
{
<li>
<a href="#" data-theme="@item.CookieValue">@item.DisplayName</a>
</li>
}
</ul>
</li>
<li id="settings-lang-menu" class="dropdown-menu-block">
<h4>@VariantTerms.Common_NavigationLanguage</h4>
@*<ul>
@foreach (Locale locale in Locale.AvailableLocales)
{
<li>
<a href="#" data-lang="@locale.LocaleId" dir="@(locale.Info.TextInfo.IsRightToLeft
? "rtl"
: "ltr")">
@locale.DisplayName
</a>
</li>
}
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>*@
<ul>
@foreach (Locale locale in Locale.AvailableLocales)
{
<li>
<a href="#" data-lang="@locale.LocaleId" dir="@(locale.Info.TextInfo.IsRightToLeft
? "rtl"
: "ltr")">
@locale.DisplayName
</a>
</li>
}
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</li>
</ul>
</li>
@ -274,7 +277,7 @@
</div>
<div class="footer-flex-item">
<p>
<span dir="ltr">@InvariantTerms.SiteName @($"v{ViewBag.Version}")</span>
<span dir="ltr">@InvariantTerms.SiteName @($"v{version}")</span>
</p>
<p>
&copy; 2013 - @DateTime.Now.Year.ToString(), @Html.Raw(string.Format(VariantTerms.Common_DevelopedBy, $"<a href=\"https://twitter.com/buildfeed\" target=\"_blank\" dir=\"ltr\" rel=\"noopener\">{InvariantTerms.DeveloperName}</a>"))
@ -302,11 +305,11 @@
<div id="menu-open-overlay"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.0-rc.70/jsrender.min.js" integrity="sha256-3UBtL0tzgKVuJU8ZZiWLXEWGEjXEr6Z023rpauMnBUE=" crossorigin="anonymous"></script>
<script type="text/javascript" src="~/res/ts/bfs.js" async="async"></script>
@*@if (((Theme)ViewBag.Theme).Value == SiteTheme.Winter)
{
<script type="text/javascript" src="~/res/ts/christmas.js" async="async"></script>
}*@
<script type="text/javascript" src="~/res/js/bfs.js" async="async"></script>
@if (theme.Value == SiteTheme.Winter)
{
<script type="text/javascript" src="~/res/js/christmas.js" async="async"></script>
}
@RenderSection("scripts", false)
<script id="result-template" type="text/x-jsrender">
<a href="{{:Url}}" class="search-result-item" title="{{:Title}}">

View File

@ -1,5 +1,4 @@
@using BuildFeed
@using BuildFeed.Code
@using BuildFeed.Controllers
@using BuildFeed.Model
@using BuildFeed.Model.View

View File

@ -42,10 +42,13 @@
"dev": true
},
"@types/jquery": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.11.tgz",
"integrity": "sha512-wdPdonsSg1pf+OY1tlAxB31XHGUZgVGcIR55Fa74U9s43tGdWwrbwOCfjub8NrjF9H+8gPD2wyFdoXsQmfAQjg==",
"dev": true
"version": "3.3.21",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.21.tgz",
"integrity": "sha512-elpRQ9RYn75XJul/PHnklyXKNNWBNOFi8Rcq9wwpAhllHFsf3ke5+32/TMUdMBOfTYk5n+uM2uleWOS9X0MA0g==",
"dev": true,
"requires": {
"@types/sizzle": "*"
}
},
"@types/jsrender": {
"version": "0.0.29",
@ -56,6 +59,12 @@
"@types/jquery": "*"
}
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
"dev": true
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -88,7 +97,7 @@
},
"ansi-colors": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
"integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
"dev": true,
"requires": {
@ -473,7 +482,6 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"optional": true,
"requires": {
"tweetnacl": "^0.14.3"
}
@ -586,7 +594,7 @@
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
"requires": {
@ -1103,7 +1111,6 @@
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"optional": true,
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
@ -1465,25 +1472,14 @@
"dev": true
},
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "1.0.6",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"dependencies": {
"combined-stream": {
"version": "1.0.6",
"resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
}
}
},
"fragment-cache": {
@ -2292,9 +2288,9 @@
}
},
"gulp-sass": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.0.1.tgz",
"integrity": "sha512-OMQEgWNggpog8Tc5v1MuI6eo+5iiPkVeLL76iBhDoEEScLUPfZlpvzmgTnLkpcqdrNodZxpz5qcv6mS2rulk3g==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.0.2.tgz",
"integrity": "sha512-q8psj4+aDrblJMMtRxihNBdovfzGrXJp1l4JU0Sz4b/Mhsi2DPrKFYCGDwjIWRENs04ELVHxdOJQ7Vs98OFohg==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
@ -2398,7 +2394,7 @@
},
"kind-of": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
"dev": true
},
@ -2452,12 +2448,12 @@
"dev": true
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
"dev": true,
"requires": {
"ajv": "^5.1.0",
"ajv": "^5.3.0",
"har-schema": "^2.0.0"
}
},
@ -2648,7 +2644,7 @@
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
@ -2850,8 +2846,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
"dev": true
},
"json-schema": {
"version": "0.2.3",
@ -2965,7 +2960,7 @@
},
"load-json-file": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
@ -3095,7 +3090,7 @@
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
"requires": {
@ -3275,7 +3270,7 @@
"dependencies": {
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
"dev": true
}
@ -3291,9 +3286,9 @@
}
},
"node-sass": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz",
"integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==",
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.4.tgz",
"integrity": "sha512-MXyurANsUoE4/6KmfMkwGcBzAnJQ5xJBGW7Ei6ea8KnUKuzHr/SguVBIi3uaUAHtZCPUYkvlJ3Ef5T5VAwVpaA==",
"dev": true,
"requires": {
"async-foreach": "^0.1.3",
@ -3311,7 +3306,7 @@
"nan": "^2.10.0",
"node-gyp": "^3.8.0",
"npmlog": "^4.0.0",
"request": "2.87.0",
"request": "^2.88.0",
"sass-graph": "^2.2.4",
"stdout-stream": "^1.4.0",
"true-case-path": "^1.0.2"
@ -3420,9 +3415,9 @@
"dev": true
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"dev": true
},
"object-assign": {
@ -3556,7 +3551,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
@ -3752,6 +3747,12 @@
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
"dev": true
},
"psl": {
"version": "1.1.29",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==",
"dev": true
},
"pump": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
@ -3935,31 +3936,31 @@
}
},
"request": {
"version": "2.87.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
"integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"dev": true,
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.6.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.5",
"extend": "~3.0.1",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.1",
"har-validator": "~5.0.3",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.17",
"oauth-sign": "~0.8.2",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.1",
"safe-buffer": "^5.1.1",
"tough-cookie": "~2.3.3",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.1.0"
"uuid": "^3.3.2"
}
},
"require-directory": {
@ -4325,9 +4326,9 @@
}
},
"sshpk": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz",
"integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==",
"dev": true,
"requires": {
"asn1": "~0.2.3",
@ -4411,7 +4412,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
@ -4589,11 +4590,12 @@
}
},
"tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"dev": true,
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
},
@ -4625,8 +4627,7 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
"dev": true
},
"typedarray": {
"version": "0.0.6",
@ -4635,9 +4636,9 @@
"dev": true
},
"typescript": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.1.tgz",
"integrity": "sha512-Veu0w4dTc/9wlWNf2jeRInNodKlcdLgemvPsrNpfu5Pq39sgfFjvIIgTsvUHCoLBnMhPoUA+tFxsXjU6VexVRQ==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.3.tgz",
"integrity": "sha512-+81MUSyX+BaSo+u2RbozuQk/UWx6hfG0a5gHu4ANEM4sU96XbuIyAB+rWBW1u70c6a5QuZfuYICn3s2UjuHUpA==",
"dev": true
},
"unc-path-regex": {
@ -4909,7 +4910,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {

View File

@ -4,17 +4,17 @@
"private": true,
"devDependencies": {
"@types/google.analytics": "0.0.39",
"@types/jquery": "3.3.11",
"@types/jquery": "3.3.21",
"@types/jsrender": "0.0.29",
"gulp": "4.0.0",
"gulp-autoprefixer": "6.0.0",
"gulp-clean-css": "3.10.0",
"gulp-sass": "4.0.1",
"gulp-sass": "4.0.2",
"gulp-sourcemaps": "2.6.4",
"gulp-typescript": "4.0.2",
"gulp-uglify-es": "1.0.4",
"multipipe": "2.0.3",
"node-sass": "4.9.3",
"typescript": "3.1.1"
"node-sass": "4.9.4",
"typescript": "3.1.3"
}
}