Lotsa fixes, some Localisation

This commit is contained in:
Thomas Hounsell 2015-09-12 00:45:17 +01:00
parent b17e622280
commit 3d41bcba1d
16 changed files with 1262 additions and 900 deletions

View File

@ -2,106 +2,114 @@
using System.Web.Mvc; using System.Web.Mvc;
using BuildFeed.Areas.admin.Models.ViewModel; using BuildFeed.Areas.admin.Models.ViewModel;
using BuildFeed.Models; using BuildFeed.Models;
using System.Threading.Tasks;
namespace BuildFeed.Areas.admin.Controllers namespace BuildFeed.Areas.admin.Controllers
{ {
[Authorize(Roles = "Administrators")] [Authorize(Roles = "Administrators")]
public class metaController : Controller public class metaController : Controller
{ {
// GET: admin/meta private MetaItem mModel;
public ActionResult index()
{
var currentItems = from i in new MetaItem().Select()
group i by i.Id.Type
into b
select b;
var pendingLabs = new MetaItem().SelectUnusedLabs(); public metaController() : base()
{
mModel = new MetaItem();
}
return View(new MetaListing // GET: admin/meta
{ public async Task<ActionResult> index()
CurrentItems = from i in new MetaItem().Select() {
group i by i.Id.Type var currentItems = from i in await mModel.Select()
into b group i by i.Id.Type
orderby b.Key.ToString() into b
select b, select b;
NewItems = from i in (from l in new MetaItem().SelectUnusedLabs()
select new MetaItemModel var pendingLabs = mModel.SelectUnusedLabs();
{
Id = new MetaItemKey return View(new MetaListing
{ {
Type = MetaType.Lab, CurrentItems = from i in await mModel.Select()
Value = l
}
})
.Concat(from v in new MetaItem().SelectUnusedVersions()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Version,
Value = v
}
})
.Concat(from y in new MetaItem().SelectUnusedYears()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Year,
Value = y
}
})
group i by i.Id.Type group i by i.Id.Type
into b into b
orderby b.Key.ToString() orderby b.Key.ToString()
select b select b,
}); NewItems = from i in (from l in await mModel.SelectUnusedLabs()
} select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Lab,
Value = l
}
})
.Concat(from v in await mModel.SelectUnusedVersions()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Version,
Value = v
}
})
.Concat(from y in await mModel.SelectUnusedYears()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Year,
Value = y
}
})
group i by i.Id.Type
into b
orderby b.Key.ToString()
select b
});
}
public ActionResult create(MetaType type, string value) public ActionResult create(MetaType type, string value)
{ {
return View(new MetaItemModel return View(new MetaItemModel
{
Id = new MetaItemKey
{ {
Id = new MetaItemKey Type = type,
{ Value = value
Type = type,
Value = value
}
});
}
[HttpPost]
public ActionResult create(MetaItemModel meta)
{
if (ModelState.IsValid)
{
new MetaItem().Insert(meta);
return RedirectToAction("index");
} }
});
}
return View(meta); [HttpPost]
} public async Task<ActionResult> create(MetaItemModel meta)
{
if (ModelState.IsValid)
{
await mModel.Insert(meta);
return RedirectToAction("index");
}
public ActionResult edit(MetaType type, string value) return View(meta);
{ }
return View("create", new MetaItem().SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
}
[HttpPost] public async Task<ActionResult> edit(MetaType type, string value)
public ActionResult edit(MetaItemModel meta) {
{ return View("create", await mModel.SelectById(new MetaItemKey
if (ModelState.IsValid) {
{ Type = type,
new MetaItem().Update(meta); Value = value
return RedirectToAction("index"); }));
} }
return View("create", meta); [HttpPost]
} public async Task<ActionResult> edit(MetaItemModel meta)
} {
if (ModelState.IsValid)
{
await mModel.Update(meta);
return RedirectToAction("index");
}
return View("create", meta);
}
}
} }

View File

@ -253,6 +253,11 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Model.resx</DependentUpon> <DependentUpon>Model.resx</DependentUpon>
</Compile> </Compile>
<Compile Include="Local\Support.qps-ploc.Designer.cs">
<DependentUpon>Support.qps-ploc.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="Local\Support.Designer.cs"> <Compile Include="Local\Support.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@ -437,6 +442,10 @@
<LastGenOutput>Model.Designer.cs</LastGenOutput> <LastGenOutput>Model.Designer.cs</LastGenOutput>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Local\Support.qps-ploc.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Support.qps-ploc.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Local\Support.resx"> <EmbeddedResource Include="Local\Support.resx">
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Support.Designer.cs</LastGenOutput> <LastGenOutput>Support.Designer.cs</LastGenOutput>

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web.Http; using System.Web.Http;
using System.Web.Security; using System.Web.Security;
@ -18,22 +19,22 @@ public apiController() : base()
bModel = new Build(); bModel = new Build();
} }
public IEnumerable<BuildModel> GetBuilds() public async Task<IEnumerable<BuildModel>> GetBuilds()
{ {
return bModel.SelectInBuildOrder(); return await bModel.SelectInBuildOrder();
} }
public IEnumerable<string> GetWin10Labs() public async Task<IEnumerable<string>> GetWin10Labs()
{ {
List<string> labs = new List<string>(); List<string> labs = new List<string>();
labs.AddRange(bModel.SelectBuildLabs(6, 4)); labs.AddRange(await bModel.SelectBuildLabs(6, 4));
labs.AddRange(bModel.SelectBuildLabs(10, 0)); labs.AddRange(await bModel.SelectBuildLabs(10, 0));
return labs.GroupBy(l => l).Select(l => l.Key).Where(l => l.All(c => c != '(')).ToArray(); return labs.GroupBy(l => l).Select(l => l.Key).Where(l => l.All(c => c != '(')).ToArray();
} }
[HttpPost] [HttpPost]
public bool AddWin10Builds(NewBuild apiModel) public async Task<bool> AddWin10Builds(NewBuild apiModel)
{ {
if (apiModel == null) if (apiModel == null)
{ {
@ -41,7 +42,7 @@ public bool AddWin10Builds(NewBuild apiModel)
} }
if (Membership.ValidateUser(apiModel.Username, apiModel.Password)) if (Membership.ValidateUser(apiModel.Username, apiModel.Password))
{ {
bModel.InsertAll(apiModel.NewBuilds.Select(nb => new BuildModel() await bModel.InsertAll(apiModel.NewBuilds.Select(nb => new BuildModel()
{ {
MajorVersion = nb.MajorVersion, MajorVersion = nb.MajorVersion,
MinorVersion = nb.MinorVersion, MinorVersion = nb.MinorVersion,
@ -59,7 +60,7 @@ public bool AddWin10Builds(NewBuild apiModel)
} }
} }
public IEnumerable<SearchResult> GetSearchResult(string query) public async Task<IEnumerable<SearchResult>> GetSearchResult(string query)
{ {
if (string.IsNullOrWhiteSpace(query)) if (string.IsNullOrWhiteSpace(query))
{ {
@ -82,7 +83,7 @@ orderby s.Text.ToLower().IndexOf(query.ToLower(), StringComparison.Ordinal) asce
results.AddRange(sourceResults); results.AddRange(sourceResults);
var versionResults = from v in bModel.SelectBuildVersions() var versionResults = from v in await bModel.SelectBuildVersions()
where $"{v.Major}.{v.Minor}".StartsWith(query) where $"{v.Major}.{v.Minor}".StartsWith(query)
orderby v.Major descending, v.Minor descending orderby v.Major descending, v.Minor descending
select new SearchResult() select new SearchResult()
@ -96,7 +97,7 @@ orderby s.Text.ToLower().IndexOf(query.ToLower(), StringComparison.Ordinal) asce
results.AddRange(versionResults); results.AddRange(versionResults);
var yearResults = from y in bModel.SelectBuildYears() var yearResults = from y in await bModel.SelectBuildYears()
where y.ToString().Contains(query) where y.ToString().Contains(query)
orderby y descending orderby y descending
select new SearchResult() select new SearchResult()
@ -110,7 +111,7 @@ orderby y descending
results.AddRange(yearResults); results.AddRange(yearResults);
var labResults = from l in bModel.SearchBuildLabs(query) var labResults = from l in await bModel.SearchBuildLabs(query)
orderby l.IndexOf(query.ToLower()) ascending, orderby l.IndexOf(query.ToLower()) ascending,
l.Length ascending l.Length ascending
select new SearchResult() select new SearchResult()
@ -124,7 +125,7 @@ l.Length ascending
results.AddRange(labResults); results.AddRange(labResults);
var buildResults = from b in bModel.Select() var buildResults = from b in await bModel.Select()
where b.FullBuildString.ToLower().Contains(query.ToLower()) where b.FullBuildString.ToLower().Contains(query.ToLower())
orderby b.FullBuildString.ToLower().IndexOf(query.ToLower(), StringComparison.Ordinal) ascending, orderby b.FullBuildString.ToLower().IndexOf(query.ToLower(), StringComparison.Ordinal) ascending,
b.BuildTime descending b.BuildTime descending

View File

@ -5,6 +5,7 @@
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Drawing.Text; using System.Drawing.Text;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
@ -24,19 +25,19 @@ public frontController() : base()
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult index() { return indexPage(1); } public async Task<ActionResult> index() { return await indexPage(1); }
[Route("page-{page:int:min(2)}/", Order = 0)] [Route("page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif #endif
public ActionResult indexPage(int page) public async Task<ActionResult> indexPage(int page)
{ {
var buildGroups = bModel.SelectBuildGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE); var buildGroups = await bModel.SelectBuildGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page; ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling( ViewBag.PageCount = Math.Ceiling(
Convert.ToDouble(bModel.SelectBuildGroupsCount()) / Convert.ToDouble(await bModel.SelectBuildGroupsCount()) /
Convert.ToDouble(PAGE_SIZE)); Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount) if (ViewBag.PageNumber > ViewBag.PageCount)
@ -51,9 +52,9 @@ public ActionResult indexPage(int page)
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewGroup(byte major, byte minor, ushort number, ushort? revision = null) public async Task<ActionResult> viewGroup(byte major, byte minor, ushort number, ushort? revision = null)
{ {
var builds = bModel.SelectSingleBuildGroup(new BuildGroup() var builds = await bModel.SelectSingleBuildGroup(new BuildGroup()
{ {
Major = major, Major = major,
Minor = minor, Minor = minor,
@ -70,9 +71,9 @@ public ActionResult viewGroup(byte major, byte minor, ushort number, ushort? rev
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewBuild(Guid id) public async Task<ActionResult> viewBuild(Guid id)
{ {
BuildModel b = bModel.SelectById(id); BuildModel b = await bModel.SelectById(id);
return View(b); return View(b);
} }
@ -81,9 +82,9 @@ public ActionResult viewBuild(Guid id)
[OutputCache(Duration = 600, VaryByParam = "none")] [OutputCache(Duration = 600, VaryByParam = "none")]
[CustomContentType(ContentType = "image/png", Order = 2)] [CustomContentType(ContentType = "image/png", Order = 2)]
#endif #endif
public ActionResult twitterCard(Guid id) public async Task<ActionResult> twitterCard(Guid id)
{ {
BuildModel b = bModel.SelectById(id); BuildModel b = await bModel.SelectById(id);
using (Bitmap bm = new Bitmap(560, 300)) using (Bitmap bm = new Bitmap(560, 300))
{ {
@ -116,13 +117,13 @@ public ActionResult twitterCard(Guid id)
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewLab(string lab) { return viewLabPage(lab, 1); } public async Task<ActionResult> viewLab(string lab) { return await viewLabPage(lab, 1); }
[Route("lab/{lab}/page-{page:int:min(2)}/", Order = 0)] [Route("lab/{lab}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewLabPage(string lab, int page) public async Task<ActionResult> viewLabPage(string lab, int page)
{ {
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{ {
@ -131,10 +132,10 @@ public ActionResult viewLabPage(string lab, int page)
}); });
ViewBag.ItemId = lab; ViewBag.ItemId = lab;
var builds = bModel.SelectLab(lab, (page - 1) * PAGE_SIZE, PAGE_SIZE); var builds = await bModel.SelectLab(lab, (page - 1) * PAGE_SIZE, PAGE_SIZE);
ViewBag.PageNumber = page; ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(bModel.SelectLabCount(lab)) / Convert.ToDouble(PAGE_SIZE)); ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await bModel.SelectLabCount(lab)) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount) if (ViewBag.PageNumber > ViewBag.PageCount)
{ {
@ -148,13 +149,13 @@ public ActionResult viewLabPage(string lab, int page)
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewSource(TypeOfSource source) { return viewSourcePage(source, 1); } public async Task<ActionResult> viewSource(TypeOfSource source) { return await viewSourcePage(source, 1); }
[Route("source/{source}/page-{page:int:min(2)}/", Order = 0)] [Route("source/{source}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewSourcePage(TypeOfSource source, int page) public async Task<ActionResult> viewSourcePage(TypeOfSource source, int page)
{ {
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{ {
@ -163,10 +164,10 @@ public ActionResult viewSourcePage(TypeOfSource source, int page)
}); });
ViewBag.ItemId = DisplayHelpers.GetDisplayTextForEnum(source); ViewBag.ItemId = DisplayHelpers.GetDisplayTextForEnum(source);
var builds = bModel.SelectSource(source, (page - 1) * PAGE_SIZE, PAGE_SIZE); var builds = await bModel.SelectSource(source, (page - 1) * PAGE_SIZE, PAGE_SIZE);
ViewBag.PageNumber = page; ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(bModel.SelectSourceCount(source)) / Convert.ToDouble(PAGE_SIZE)); ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await bModel.SelectSourceCount(source)) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount) if (ViewBag.PageNumber > ViewBag.PageCount)
{ {
@ -180,13 +181,13 @@ public ActionResult viewSourcePage(TypeOfSource source, int page)
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewYear(int year) { return viewYearPage(year, 1); } public async Task<ActionResult> viewYear(int year) { return await viewYearPage(year, 1); }
[Route("year/{year}/page-{page:int:min(2)}/", Order = 0)] [Route("year/{year}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewYearPage(int year, int page) public async Task<ActionResult> viewYearPage(int year, int page)
{ {
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{ {
@ -195,10 +196,10 @@ public ActionResult viewYearPage(int year, int page)
}); });
ViewBag.ItemId = year.ToString(); ViewBag.ItemId = year.ToString();
var builds = bModel.SelectYear(year, (page - 1) * PAGE_SIZE, PAGE_SIZE); var builds = await bModel.SelectYear(year, (page - 1) * PAGE_SIZE, PAGE_SIZE);
ViewBag.PageNumber = page; ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(bModel.SelectYearCount(year) / Convert.ToDouble(PAGE_SIZE)); ViewBag.PageCount = Math.Ceiling(await bModel.SelectYearCount(year) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount) if (ViewBag.PageNumber > ViewBag.PageCount)
{ {
@ -212,13 +213,13 @@ public ActionResult viewYearPage(int year, int page)
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewVersion(int major, int minor) { return viewVersionPage(major, minor, 1); } public async Task<ActionResult> viewVersion(int major, int minor) { return await viewVersionPage(major, minor, 1); }
[Route("version/{major}.{minor}/page-{page:int:min(2)}/", Order = 0)] [Route("version/{major}.{minor}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult viewVersionPage(int major, int minor, int page) public async Task<ActionResult> viewVersionPage(int major, int minor, int page)
{ {
string valueString = $"{major}.{minor}"; string valueString = $"{major}.{minor}";
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
@ -228,10 +229,10 @@ public ActionResult viewVersionPage(int major, int minor, int page)
}); });
ViewBag.ItemId = valueString; ViewBag.ItemId = valueString;
var builds = bModel.SelectVersion(major, minor, (page - 1) * PAGE_SIZE, PAGE_SIZE); var builds = await bModel.SelectVersion(major, minor, (page - 1) * PAGE_SIZE, PAGE_SIZE);
ViewBag.PageNumber = page; ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(bModel.SelectVersionCount(major, minor)) / Convert.ToDouble(PAGE_SIZE)); ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await bModel.SelectVersionCount(major, minor)) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount) if (ViewBag.PageNumber > ViewBag.PageCount)
{ {
@ -245,7 +246,7 @@ public ActionResult viewVersionPage(int major, int minor, int page)
public ActionResult addBuild() { return View("editBuild"); } public ActionResult addBuild() { return View("editBuild"); }
[Route("add/"), Authorize, HttpPost] [Route("add/"), Authorize, HttpPost]
public ActionResult addBuild(BuildModel build) public async Task<ActionResult> addBuild(BuildModel build)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
@ -253,7 +254,7 @@ public ActionResult addBuild(BuildModel build)
{ {
build.Added = DateTime.Now; build.Added = DateTime.Now;
build.Modified = DateTime.Now; build.Modified = DateTime.Now;
new Build().Insert(build); await bModel.Insert(build);
} }
catch catch
{ {
@ -268,20 +269,20 @@ public ActionResult addBuild(BuildModel build)
} }
[Route("edit/{id}/"), Authorize] [Route("edit/{id}/"), Authorize]
public ActionResult editBuild(Guid id) public async Task<ActionResult> editBuild(Guid id)
{ {
BuildModel b = new Build().SelectById(id); BuildModel b = await bModel.SelectById(id);
return View(b); return View(b);
} }
[Route("edit/{id}/"), Authorize, HttpPost] [Route("edit/{id}/"), Authorize, HttpPost]
public ActionResult editBuild(long id, BuildModel build) public async Task<ActionResult> editBuild(long id, BuildModel build)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
try try
{ {
new Build().Update(build); await bModel.Update(build);
} }
catch catch
{ {
@ -294,9 +295,9 @@ public ActionResult editBuild(long id, BuildModel build)
} }
[Route("delete/{id}/"), Authorize(Roles = "Administrators")] [Route("delete/{id}/"), Authorize(Roles = "Administrators")]
public ActionResult deleteBuild(Guid id) public async Task<ActionResult> deleteBuild(Guid id)
{ {
new Build().DeleteById(id); await bModel.DeleteById(id);
return RedirectToAction("index"); return RedirectToAction("index");
} }
} }

View File

@ -10,219 +10,237 @@
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
public class rssController : Controller public class rssController : Controller
{ {
[Route("rss/compiled")] private Build bModel;
public async Task<ActionResult> index() private const int RSS_SIZE = 20;
{
var builds = new Build().SelectInBuildOrder().Take(20);
RssDocument rdoc = new RssDocument() public rssController() : base()
{
bModel = new Build();
}
[Route("rss/compiled")]
public async Task<ActionResult> index()
{
var builds = await bModel.SelectInBuildOrder(RSS_SIZE, 0);
RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = "BuildFeed RSS - Recently Compiled",
{ Description = "",
Title = "BuildFeed RSS - Recently Compiled", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Action("viewBuild", new { controller = "front", id = build.Id })) }, Guid = new RssGuid() { IsPermaLink = true, Value = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Action("viewBuild", new { controller = "front", id = build.Id })) },
}).ToList() }).ToList()
} }
}; };
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
[Route("rss/added")] [Route("rss/added")]
public async Task<ActionResult> added() public async Task<ActionResult> added()
{ {
var builds = new Build().Select().OrderByDescending(b => b.Added).Take(20); var builds = await bModel.SelectLatest(RSS_SIZE, 0);
RssDocument rdoc = new RssDocument() RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = "BuildFeed RSS - Recently Added",
{ Description = "",
Title = "BuildFeed RSS - Recently Added", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}" Guid = new RssGuid()
}, {
InternalPubDate = new RssDate(build.Added).DateStringISO8601 // bit of a dirty hack to work around problem in X.Web.RSS with the date format. IsPermaLink = true,
}).ToList() Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"
} },
}; InternalPubDate = new RssDate(build.Added).DateStringISO8601 // bit of a dirty hack to work around problem in X.Web.RSS with the date format.
}).ToList()
}
};
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
[Route("rss/leaked")] [Route("rss/leaked")]
public async Task<ActionResult> leaked() public async Task<ActionResult> leaked()
{ {
var builds = new Build().Select().Where(b => b.LeakDate.HasValue).OrderByDescending(b => b.LeakDate.Value).Take(20); var builds = await bModel.SelectLatestLeaked(RSS_SIZE, 0);
RssDocument rdoc = new RssDocument() RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = "BuildFeed RSS - Recently Leaked",
{ Description = "",
Title = "BuildFeed RSS - Recently Leaked", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}" Guid = new RssGuid()
}, {
InternalPubDate = new RssDate(build.LeakDate.Value).DateStringISO8601 // bit of a dirty hack to work around problem in X.Web.RSS with the date format. IsPermaLink = true,
}).ToList() Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"
} },
}; InternalPubDate = new RssDate(build.LeakDate.Value).DateStringISO8601 // bit of a dirty hack to work around problem in X.Web.RSS with the date format.
}).ToList()
}
};
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
[Route("rss/version")] [Route("rss/version")]
public async Task<ActionResult> version() public async Task<ActionResult> version()
{ {
var builds = new Build().SelectInVersionOrder() var builds = await bModel.SelectInVersionOrder(RSS_SIZE, 0);
.Take(20);
RssDocument rdoc = new RssDocument() RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = "BuildFeed RSS - Highest Version",
{ Description = "",
Title = "BuildFeed RSS - Highest Version", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}" Guid = new RssGuid()
}, {
}).ToList() IsPermaLink = true,
} Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"
}; },
}).ToList()
}
};
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
[Route("rss/flight/{id}")] [Route("rss/flight/{id}")]
public async Task<ActionResult> flight(LevelOfFlight id) public async Task<ActionResult> flight(LevelOfFlight id)
{ {
var builds = new Build().SelectInBuildOrder() var builds = await bModel.SelectFlight(id, RSS_SIZE, 0);
.Where(b => b.FlightLevel == id)
.Take(20);
RssDocument rdoc = new RssDocument() RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = $"BuildFeed RSS - {id} Flight Level",
{ Description = "",
Title = $"BuildFeed RSS - {id} Flight Level", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}" Guid = new RssGuid()
}, {
}).ToList() IsPermaLink = true,
} Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"
}; },
}).ToList()
}
};
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
[Route("rss/lab/{lab}")] [Route("rss/lab/{lab}")]
public async Task<ActionResult> lab(string lab) public async Task<ActionResult> lab(string lab)
{ {
var builds = new Build().SelectInBuildOrder() var builds = await bModel.SelectLab(lab, RSS_SIZE, 0);
.Where(b => b.Lab == lab)
.Take(20);
RssDocument rdoc = new RssDocument() RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{ {
Channel = new RssChannel() Title = $"BuildFeed RSS - {lab} Lab",
{ Description = "",
Title = $"BuildFeed RSS - {lab} Lab", Generator = "BuildFeed.net RSS Controller",
Description = "", Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Generator = "BuildFeed.net RSS Controller", SkipHours = new List<Hour>(),
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"), SkipDays = new List<Day>(),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds Items = (from build in builds
select new RssItem() select new RssItem()
{ {
Title = build.FullBuildString, Title = build.FullBuildString,
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"), Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"),
Guid = new RssGuid() { IsPermaLink = true, Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}" Guid = new RssGuid()
}, {
}).ToList() IsPermaLink = true,
} Value = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action("viewBuild", new { controller = "front", id = build.Id })}"
}; },
}).ToList()
}
};
Response.ContentType = "application/rss+xml"; Response.ContentType = "application/rss+xml";
await Response.Output.WriteAsync(rdoc.ToXml()); await Response.Output.WriteAsync(rdoc.ToXml());
return new EmptyResult(); return new EmptyResult();
} }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
@ -11,135 +12,142 @@
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
public class supportController : Controller public class supportController : Controller
{ {
[Route("login/")] private Build bModel;
public ActionResult login()
{
return View();
}
[HttpPost, Route("login/")] public supportController() : base()
public ActionResult login(LoginUser ru) {
{ bModel = new Build();
if (ModelState.IsValid) }
[Route("login/")]
public ActionResult login()
{
return View();
}
[HttpPost, Route("login/")]
public ActionResult login(LoginUser ru)
{
if (ModelState.IsValid)
{
bool isAuthenticated = Membership.ValidateUser(ru.UserName, ru.Password);
if (isAuthenticated)
{ {
bool isAuthenticated = Membership.ValidateUser(ru.UserName, ru.Password); int expiryLength = ru.RememberMe ? 129600 : 60;
var ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
Expires = DateTime.Now.AddMinutes(expiryLength),
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookieTicket);
if (isAuthenticated) string returnUrl = string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]) ? "/" : Request.QueryString["ReturnUrl"];
{
int expiryLength = ru.RememberMe ? 129600 : 60;
var ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
Expires = DateTime.Now.AddMinutes(expiryLength),
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookieTicket);
string returnUrl = string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]) ? "/" : Request.QueryString["ReturnUrl"]; return Redirect(returnUrl);
return Redirect(returnUrl);
}
} }
}
ViewData["ErrorMessage"] = "The username and password are not valid."; ViewData["ErrorMessage"] = "The username and password are not valid.";
return View(ru); return View(ru);
} }
[Authorize, Route("password/")] [Authorize, Route("password/")]
public ActionResult password() public ActionResult password()
{ {
return View(); return View();
} }
[HttpPost, Authorize, Route("password/")] [HttpPost, Authorize, Route("password/")]
public ActionResult password(ChangePassword cp) public ActionResult password(ChangePassword cp)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{
MembershipUser user = Membership.GetUser();
if (user != null)
{ {
MembershipUser user = Membership.GetUser(); bool success = user.ChangePassword(cp.OldPassword, cp.NewPassword);
if (user != null) if (success)
{ {
bool success = user.ChangePassword(cp.OldPassword, cp.NewPassword); return Redirect("/");
}
if (success)
{
return Redirect("/");
}
}
} }
}
ViewData["ErrorMessage"] = "There was an error changing your password."; ViewData["ErrorMessage"] = "There was an error changing your password.";
return View(cp); return View(cp);
} }
[Route("logout/")] [Route("logout/")]
public ActionResult logout() public ActionResult logout()
{ {
FormsAuthentication.SignOut(); FormsAuthentication.SignOut();
return Redirect("/"); return Redirect("/");
} }
[Route("register/")] [Route("register/")]
public ActionResult register() public ActionResult register()
{ {
return View(); return View();
} }
[HttpPost, Route("register/")] [HttpPost, Route("register/")]
public ActionResult register(RegistrationUser ru) public ActionResult register(RegistrationUser ru)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{
MembershipCreateStatus status;
Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "THIS WILL BE IGNORED", "I WILL BE IGNORED", false, out status);
switch (status)
{ {
MembershipCreateStatus status; case MembershipCreateStatus.Success:
Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "THIS WILL BE IGNORED", "I WILL BE IGNORED", false, out status); return RedirectToAction("thanks_register");
case MembershipCreateStatus.InvalidPassword:
switch (status) ViewData["ErrorMessage"] = "The password is invalid.";
{ break;
case MembershipCreateStatus.Success: case MembershipCreateStatus.DuplicateEmail:
return RedirectToAction("thanks_register"); ViewData["ErrorMessage"] = "A user account with this email address already exists.";
case MembershipCreateStatus.InvalidPassword: break;
ViewData["ErrorMessage"] = "The password is invalid."; case MembershipCreateStatus.DuplicateUserName:
break; ViewData["ErrorMessage"] = "A user account with this user name already exists.";
case MembershipCreateStatus.DuplicateEmail: break;
ViewData["ErrorMessage"] = "A user account with this email address already exists."; default:
break; ViewData["ErrorMessage"] = "Unspecified error.";
case MembershipCreateStatus.DuplicateUserName: break;
ViewData["ErrorMessage"] = "A user account with this user name already exists.";
break;
default:
ViewData["ErrorMessage"] = "Unspecified error.";
break;
}
} }
}
return View(ru); return View(ru);
} }
[Route("register/thanks/")] [Route("register/thanks/")]
public ActionResult thanks_register() public ActionResult thanks_register()
{ {
return View(); return View();
} }
[Route("rss")] [Route("rss")]
public ActionResult rss() public ActionResult rss()
{ {
ViewBag.Labs = new Build().SelectBuildLabs(); ViewBag.Labs = bModel.SelectBuildLabs();
return View(); return View();
} }
[Route("sitemap/")] [Route("sitemap/")]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult sitemap() public async Task<ActionResult> sitemap()
{ {
var builds = new Build().SelectInVersionOrder(); var builds = await bModel.SelectInVersionOrder();
Dictionary<string, SitemapPagedAction[]> actions = new Dictionary<string, SitemapPagedAction[]> Dictionary<string, SitemapPagedAction[]> actions = new Dictionary<string, SitemapPagedAction[]>
{ {
{ {
"Pages", new[] "Pages", new[]
@ -243,145 +251,145 @@ orderby bv.Key
SitemapData model = new SitemapData() SitemapData model = new SitemapData()
{ {
Builds = (from b in new Build().Select() Builds = (from b in await bModel.Select()
group b by new BuildGroup() group b by new BuildGroup()
{ {
Major = b.MajorVersion, Major = b.MajorVersion,
Minor = b.MinorVersion, Minor = b.MinorVersion,
Build = b.Number, Build = b.Number,
Revision = b.Revision Revision = b.Revision
} into bg } into bg
orderby bg.Key.Major descending, orderby bg.Key.Major descending,
bg.Key.Minor descending, bg.Key.Minor descending,
bg.Key.Build descending, bg.Key.Build descending,
bg.Key.Revision descending bg.Key.Revision descending
select new SitemapDataBuildGroup() select new SitemapDataBuildGroup()
{ {
Id = bg.Key, Id = bg.Key,
Builds = (from bgb in bg Builds = (from bgb in bg
select new SitemapDataBuild() select new SitemapDataBuild()
{ {
Id = bgb.Id, Id = bgb.Id,
Name = bgb.FullBuildString Name = bgb.FullBuildString
}).ToArray() }).ToArray()
}).ToArray(), }).ToArray(),
Actions = actions, Actions = actions,
Labs = (from b in builds Labs = (from b in builds
group b by b.Lab into lab group b by b.Lab into lab
select lab.Key).ToArray() select lab.Key).ToArray()
}; };
return View(model); return View(model);
} }
[Route("xml-sitemap/")] [Route("xml-sitemap/")]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult xmlsitemap() public async Task<ActionResult> xmlsitemap()
{ {
XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9"); XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
List<XElement> xlist = new List<XElement>(); List<XElement> xlist = new List<XElement>();
// home page // home page
XElement home = new XElement(xn + "url"); XElement home = new XElement(xn + "url");
home.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + "/")); home.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + "/"));
home.Add(new XElement(xn + "changefreq", "daily")); home.Add(new XElement(xn + "changefreq", "daily"));
xlist.Add(home); xlist.Add(home);
foreach (var b in new Build().Select()) foreach (var b in await bModel.Select())
{
XElement url = new XElement(xn + "url");
url.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + Url.Action("viewBuild", "front", new { id = b.Id })));
if (b.Modified != DateTime.MinValue)
{ {
XElement url = new XElement(xn + "url"); url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd")));
url.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + Url.Action("viewBuild", "front", new { id = b.Id })));
if (b.Modified != DateTime.MinValue)
{
url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd")));
}
xlist.Add(url);
} }
xlist.Add(url);
}
XDeclaration decl = new XDeclaration("1.0", "utf-8", ""); XDeclaration decl = new XDeclaration("1.0", "utf-8", "");
XElement root = new XElement(xn + "urlset", xlist); XElement root = new XElement(xn + "urlset", xlist);
XDocument xdoc = new XDocument(decl, root); XDocument xdoc = new XDocument(decl, root);
Response.ContentType = "application/xml"; Response.ContentType = "application/xml";
xdoc.Save(Response.OutputStream); xdoc.Save(Response.OutputStream);
return new EmptyResult(); return new EmptyResult();
} }
[Route("statistics/")] [Route("statistics/")]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")] [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif #endif
public ActionResult stats() public async Task<ActionResult> stats()
{ {
var builds = new Build().Select().ToArray(); var builds = await bModel.Select();
List<MonthCount> additions = new List<MonthCount>(); List<MonthCount> additions = new List<MonthCount>();
var rawAdditions = (from b in builds var rawAdditions = (from b in builds
where b.Added > DateTime.Now.AddYears(-1) where b.Added > DateTime.Now.AddYears(-1)
group b by new group b by new
{ {
Year = b.Added.Year, Year = b.Added.Year,
Week = Convert.ToInt32(Math.Floor(b.Added.DayOfYear / 7m)) Week = Convert.ToInt32(Math.Floor(b.Added.DayOfYear / 7m))
} into bm } into bm
select new MonthCount() select new MonthCount()
{ {
Month = bm.Key.Week, Month = bm.Key.Week,
Year = bm.Key.Year, Year = bm.Key.Year,
Count = bm.Count() Count = bm.Count()
}).ToArray(); }).ToArray();
for (int i = -52; i <= 0; i++) for (int i = -52; i <= 0; i++)
{
DateTime dt = DateTime.Now.AddDays(i * 7);
additions.Add(new MonthCount()
{ {
DateTime dt = DateTime.Now.AddDays(i * 7); Month = Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)),
additions.Add(new MonthCount() Year = dt.Year,
{ Count = rawAdditions.SingleOrDefault(a => a.Month == Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)) && a.Year == dt.Year).Count
Month = Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)), });
Year = dt.Year, }
Count = rawAdditions.SingleOrDefault(a => a.Month == Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)) && a.Year == dt.Year).Count
});
}
List<MonthCount> compiles = new List<MonthCount>(); List<MonthCount> compiles = new List<MonthCount>();
double logScale = 1.0 / Math.E; double logScale = 1.0 / Math.E;
var rawCompiles = from b in builds var rawCompiles = from b in builds
where b.BuildTime.HasValue where b.BuildTime.HasValue
group b by new group b by new
{ {
Year = b.BuildTime.Value.Year, Year = b.BuildTime.Value.Year,
Month = Convert.ToInt32(Math.Floor((b.BuildTime.Value.Month - 0.1m) / 3m) * 3) + 1 Month = Convert.ToInt32(Math.Floor((b.BuildTime.Value.Month - 0.1m) / 3m) * 3) + 1
} into bm } into bm
select new MonthCount() select new MonthCount()
{ {
Month = bm.Key.Month, Month = bm.Key.Month,
Year = bm.Key.Year, Year = bm.Key.Year,
Count = Math.Pow(Convert.ToDouble(bm.Count()), logScale) Count = Math.Pow(Convert.ToDouble(bm.Count()), logScale)
}; };
var rawLabCounts = from bl in (from b in builds var rawLabCounts = from bl in (from b in builds
where !string.IsNullOrEmpty(b.Lab) where !string.IsNullOrEmpty(b.Lab)
group b by b.Lab into bl group b by b.Lab into bl
select bl) select bl)
where bl.Count() > 99 where bl.Count() > 99
orderby bl.Count() descending orderby bl.Count() descending
select new Tuple<string, int>(bl.Key, bl.Count()); select new Tuple<string, int>(bl.Key, bl.Count());
StatsPage m = new StatsPage() StatsPage m = new StatsPage()
{ {
AdditionsByMonth = additions, AdditionsByMonth = additions,
CompilesByMonth = rawCompiles.OrderBy(r => r.Year).ThenBy(r => r.Month), CompilesByMonth = rawCompiles.OrderBy(r => r.Year).ThenBy(r => r.Month),
BuildsByLab = rawLabCounts BuildsByLab = rawLabCounts
}; };
return View(m); return View(m);
} }
} }
} }

View File

@ -69,6 +69,24 @@ public static string AccountValidation {
} }
} }
/// <summary>
/// Looks up a localized string similar to Additions to BuildFeed.
/// </summary>
public static string AdditionsToBuildFeed {
get {
return ResourceManager.GetString("AdditionsToBuildFeed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Builds Compiled.
/// </summary>
public static string BuildsCompiled {
get {
return ResourceManager.GetString("BuildsCompiled", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Change your password. /// Looks up a localized string similar to Change your password.
/// </summary> /// </summary>
@ -141,6 +159,15 @@ public static string HighestVersion {
} }
} }
/// <summary>
/// Looks up a localized string similar to Labs.
/// </summary>
public static string Labs {
get {
return ResourceManager.GetString("Labs", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Log in. /// Looks up a localized string similar to Log in.
/// </summary> /// </summary>
@ -204,6 +231,42 @@ public static string RememberMe {
} }
} }
/// <summary>
/// Looks up a localized string similar to Builds compiled each quarter.
/// </summary>
public static string StatsCompiled {
get {
return ResourceManager.GetString("StatsCompiled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Recorded builds in each lab.
/// </summary>
public static string StatsLab {
get {
return ResourceManager.GetString("StatsLab", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Only labs with 100 or more recorded builds are included..
/// </summary>
public static string StatsLabIncluded {
get {
return ResourceManager.GetString("StatsLabIncluded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to New additions to BuildFeed over the previous year.
/// </summary>
public static string StatsNewAdditions {
get {
return ResourceManager.GetString("StatsNewAdditions", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Thank you for registering. /// Looks up a localized string similar to Thank you for registering.
/// </summary> /// </summary>
@ -221,5 +284,14 @@ public static string UserName {
return ResourceManager.GetString("UserName", resourceCulture); return ResourceManager.GetString("UserName", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to Week.
/// </summary>
public static string Week {
get {
return ResourceManager.GetString("Week", resourceCulture);
}
}
} }
} }

View File

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AccountValidation" xml:space="preserve">
<value>[!!! ÉƲèř¥ áççôúñƭ ïƨ Ʋáℓïδáƭèδ β¥ áñ Âδ₥ïñïƨƭřáƭôř, ƨô βè ƥáƭïèñƭ áñδ çλèçƙ áϱáïñ ℓáƭèř. ℓôřè₥ ïƥƨú₥ δôℓôř ƨïƭ á₥ !!!]</value>
</data>
<data name="AdditionsToBuildFeed" xml:space="preserve">
<value>[!!! Âδδïƭïôñƨ ƭô ßúïδFèèδ ℓôřè₥ !!!]</value>
</data>
<data name="BuildsCompiled" xml:space="preserve">
<value>[!!! ßúïℓδƨ Çô₥ƥïℓèδ ℓôř !!!]</value>
</data>
<data name="ChangePassword" xml:space="preserve">
<value>[!!! Çλáñϱè ¥ôúř ƥáƨƨωôřδ ℓôřè₥ !!!]</value>
</data>
<data name="ConfirmNewPassword" xml:space="preserve">
<value>[!!! Çôñƒïř₥ ñèω ƥáƨƨωôřδ ℓôřè₥ !!!]</value>
</data>
<data name="ConfirmPassword" xml:space="preserve">
<value>[!!! Çôñƒïř₥ ƥáƨƨωôřδ ℓôřè !!!]</value>
</data>
<data name="EmailAddress" xml:space="preserve">
<value>[!!! É₥áïℓ áδδřèƨƨ ℓôř !!!]</value>
</data>
<data name="EnterCurrentPassword" xml:space="preserve">
<value>[!!! Éñƭèř çúřřèñƭ ƥáƨƨωôřδ ℓôřè₥ !!!]</value>
</data>
<data name="EnterNewPassword" xml:space="preserve">
<value>[!!! Éñƭèř ñèω ƥáƨƨωôřδ ℓôřè !!!]</value>
</data>
<data name="EnterPassword" xml:space="preserve">
<value>[!!! Éñƭèř ƥáƨƨωôřδ ℓôř !!!]</value>
</data>
<data name="HighestVersion" xml:space="preserve">
<value>[!!! Hïϱλèƨƭ Ʋèřƨïôñ ℓôřè !!!]</value>
</data>
<data name="Labs" xml:space="preserve">
<value>[!!! £áβƨ !!!]</value>
</data>
<data name="Login" xml:space="preserve">
<value>[!!! £ôϱ ïñ !!!]</value>
</data>
<data name="Password" xml:space="preserve">
<value>[!!! Þáƨƨωôřδ !!!]</value>
</data>
<data name="RecentlyAdded" xml:space="preserve">
<value>[!!! Rèçèñƭ¥ áδδèδ ℓôř !!!]</value>
</data>
<data name="RecentlyCompiled" xml:space="preserve">
<value>[!!! Rèçèñƭ¥ çô₥ƥïℓèδ ℓôřè !!!]</value>
</data>
<data name="RecentlyLeaked" xml:space="preserve">
<value>[!!! Rèçèñƭ¥ ℓèáƙèδ ℓôřè !!!]</value>
</data>
<data name="Register" xml:space="preserve">
<value>[!!! Rèϱïƨƭèř !!!]</value>
</data>
<data name="RememberMe" xml:space="preserve">
<value>[!!! Rè₥è₥βèř ₥è ℓô !!!]</value>
</data>
<data name="StatsCompiled" xml:space="preserve">
<value>[!!! ßúïℓδƨ çô₥ƥïℓèδ èáçλ 9úářƭèř ℓôřè₥ ï !!!]</value>
</data>
<data name="StatsLab" xml:space="preserve">
<value>[!!! Rèçôřδèδ βúïℓδƨ ïñ èáçλ ℓáβ ℓôřè₥ ï !!!]</value>
</data>
<data name="StatsLabIncluded" xml:space="preserve">
<value>[!!! Óñℓ¥ ℓáβƨ ωïƭλ 100 ôř ₥ôřè řèçôřδèδ βúïℓδƨ ářè ïñçℓúδèδ. ℓôřè₥ ïƥƨú₥ δôℓô !!!]</value>
</data>
<data name="StatsNewAdditions" xml:space="preserve">
<value>[!!! Nèω áδδïƭïôñƨ ƭô ßúïδFèèδ ôƲèř ƭλè ƥřèƲïôúƨ ¥èář ℓôřè₥ ïƥƨú₥ δô !!!]</value>
</data>
<data name="ThanksRegister" xml:space="preserve">
<value>[!!! Tλáñƙ ¥ôú ƒôř řèϱïƨƭèřïñϱ ℓôřè₥ ï !!!]</value>
</data>
<data name="UserName" xml:space="preserve">
<value>[!!! Ûƨèřñá₥è !!!]</value>
</data>
<data name="Week" xml:space="preserve">
<value>[!!! Wèèƙ !!!]</value>
</data>
</root>

View File

@ -120,6 +120,12 @@
<data name="AccountValidation" xml:space="preserve"> <data name="AccountValidation" xml:space="preserve">
<value>Every account is validated by an Administrator, so be patient and check again later.</value> <value>Every account is validated by an Administrator, so be patient and check again later.</value>
</data> </data>
<data name="AdditionsToBuildFeed" xml:space="preserve">
<value>Additions to BuildFeed</value>
</data>
<data name="BuildsCompiled" xml:space="preserve">
<value>Builds Compiled</value>
</data>
<data name="ChangePassword" xml:space="preserve"> <data name="ChangePassword" xml:space="preserve">
<value>Change your password</value> <value>Change your password</value>
</data> </data>
@ -144,6 +150,9 @@
<data name="HighestVersion" xml:space="preserve"> <data name="HighestVersion" xml:space="preserve">
<value>Highest version</value> <value>Highest version</value>
</data> </data>
<data name="Labs" xml:space="preserve">
<value>Labs</value>
</data>
<data name="Login" xml:space="preserve"> <data name="Login" xml:space="preserve">
<value>Log in</value> <value>Log in</value>
</data> </data>
@ -165,10 +174,25 @@
<data name="RememberMe" xml:space="preserve"> <data name="RememberMe" xml:space="preserve">
<value>Remember me</value> <value>Remember me</value>
</data> </data>
<data name="StatsCompiled" xml:space="preserve">
<value>Builds compiled each quarter</value>
</data>
<data name="StatsLab" xml:space="preserve">
<value>Recorded builds in each lab</value>
</data>
<data name="StatsLabIncluded" xml:space="preserve">
<value>Only labs with 100 or more recorded builds are included.</value>
</data>
<data name="StatsNewAdditions" xml:space="preserve">
<value>New additions to BuildFeed over the previous year</value>
</data>
<data name="ThanksRegister" xml:space="preserve"> <data name="ThanksRegister" xml:space="preserve">
<value>Thank you for registering</value> <value>Thank you for registering</value>
</data> </data>
<data name="UserName" xml:space="preserve"> <data name="UserName" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
<data name="Week" xml:space="preserve">
<value>Week</value>
</data>
</root> </root>

View File

@ -10,6 +10,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using Required = System.ComponentModel.DataAnnotations.RequiredAttribute; using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
@ -134,17 +135,35 @@ public Build()
} }
[DataObjectMethod(DataObjectMethodType.Select, true)] [DataObjectMethod(DataObjectMethodType.Select, true)]
public List<BuildModel> Select() public async Task<List<BuildModel>> Select()
{ {
var task = _buildCollection.Find(new BsonDocument()).ToListAsync(); return await _buildCollection.Find(new BsonDocument()).ToListAsync();
task.Wait(); }
return task.Result;
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatest(int limit, int skip)
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.Added)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatestLeaked(int limit, int skip)
{
return await _buildCollection.Find(b => b.Added != null)
.SortByDescending(b => b.Added)
.Skip(skip)
.Limit(limit)
.ToListAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<FrontBuildGroup> SelectBuildGroups(int limit, int skip) public async Task<List<FrontBuildGroup>> SelectBuildGroups(int limit, int skip)
{ {
var pipeline = _buildCollection.Aggregate() return await _buildCollection.Aggregate()
.Group(b => new BuildGroup() .Group(b => new BuildGroup()
{ {
Major = b.MajorVersion, Major = b.MajorVersion,
@ -163,16 +182,12 @@ public List<FrontBuildGroup> SelectBuildGroups(int limit, int skip)
.ThenByDescending(b => b.Key.Build) .ThenByDescending(b => b.Key.Build)
.ThenByDescending(b => b.Key.Revision) .ThenByDescending(b => b.Key.Revision)
.Skip(skip) .Skip(skip)
.Limit(limit); .Limit(limit)
.ToListAsync();
var task = pipeline.ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, true)] [DataObjectMethod(DataObjectMethodType.Select, true)]
public int SelectBuildGroupsCount() public async Task<int> SelectBuildGroupsCount()
{ {
var pipeline = _buildCollection.Aggregate() var pipeline = _buildCollection.Aggregate()
.Group(b => new BuildGroup() .Group(b => new BuildGroup()
@ -184,14 +199,11 @@ public int SelectBuildGroupsCount()
}, },
bg => new BsonDocument()); bg => new BsonDocument());
var task = pipeline.ToListAsync(); return (await pipeline.ToListAsync()).Count;
task.Wait();
return task.Result.Count();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public Tuple<BuildGroup, IEnumerable<BuildModel>> SelectSingleBuildGroup(BuildGroup bGroup) public async Task<Tuple<BuildGroup, List<BuildModel>>> SelectSingleBuildGroup(BuildGroup bGroup)
{ {
var pipeline = _buildCollection.Aggregate() var pipeline = _buildCollection.Aggregate()
.Match(b => b.MajorVersion == bGroup.Major) .Match(b => b.MajorVersion == bGroup.Major)
@ -200,60 +212,78 @@ public Tuple<BuildGroup, IEnumerable<BuildModel>> SelectSingleBuildGroup(BuildGr
.Match(b => b.Revision == bGroup.Revision) .Match(b => b.Revision == bGroup.Revision)
.SortByDescending(b => b.BuildTime); .SortByDescending(b => b.BuildTime);
var task = pipeline.ToListAsync(); return new Tuple<BuildGroup, List<BuildModel>>(bGroup, await pipeline.ToListAsync());
task.Wait();
return new Tuple<BuildGroup, IEnumerable<BuildModel>>(bGroup, task.Result);
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public BuildModel SelectById(Guid id) public async Task<BuildModel> SelectById(Guid id)
{ {
var task = _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync(); return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public BuildModel SelectByLegacyId(long id) public async Task<BuildModel> SelectByLegacyId(long id)
{ {
var task = _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync(); return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectInBuildOrder() public async Task<List<BuildModel>> SelectInBuildOrder()
{ {
var task = _buildCollection.Find(new BsonDocument()) return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.BuildTime) .SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion) .ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number) .ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision) .ThenByDescending(b => b.Revision)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectInVersionOrder() public async Task<List<BuildModel>> SelectInBuildOrder(int limit, int skip)
{ {
var task = _buildCollection.Find(new BsonDocument()) return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> SelectInVersionOrder()
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.MajorVersion) .SortByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number) .ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision) .ThenByDescending(b => b.Revision)
.ThenByDescending(b => b.BuildTime) .ThenByDescending(b => b.BuildTime)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectLab(string lab, int skip, int limit) public async Task<List<BuildModel>> SelectInVersionOrder(int limit, int skip)
{ {
var task = _buildCollection.Find(b => b.Lab != null && (b.Lab.ToLower() == lab.ToLower())) return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.ThenByDescending(b => b.BuildTime)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> SelectFlight(LevelOfFlight flight, int limit, int skip)
{
return await _buildCollection.Find(b => b.FlightLevel == flight)
.SortByDescending(b => b.BuildTime) .SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion) .ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
@ -262,23 +292,12 @@ public List<BuildModel> SelectLab(string lab, int skip, int limit)
.Skip(skip) .Skip(skip)
.Limit(limit) .Limit(limit)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public long SelectLabCount(string lab) public async Task<List<BuildModel>> SelectLab(string lab, int skip, int limit)
{ {
var task = _buildCollection.Find(b => b.Lab != null && (b.Lab.ToLower() == lab.ToLower())) return await _buildCollection.Find(b => b.Lab != null && (b.Lab.ToLower() == lab.ToLower()))
.CountAsync();
task.Wait();
return task.Result;
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectSource(TypeOfSource source, int skip, int limit)
{
var task = _buildCollection.Find(b => b.SourceType == source)
.SortByDescending(b => b.BuildTime) .SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion) .ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
@ -287,23 +306,19 @@ public List<BuildModel> SelectSource(TypeOfSource source, int skip, int limit)
.Skip(skip) .Skip(skip)
.Limit(limit) .Limit(limit)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public long SelectSourceCount(TypeOfSource source) public async Task<long> SelectLabCount(string lab)
{ {
var task = _buildCollection.Find(b => b.SourceType == source) return await _buildCollection.Find(b => b.Lab != null && (b.Lab.ToLower() == lab.ToLower()))
.CountAsync(); .CountAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectYear(int year, int skip, int limit) public async Task<List<BuildModel>> SelectSource(TypeOfSource source, int skip, int limit)
{ {
var task = _buildCollection.Find(b => b.BuildTime.HasValue && b.BuildTime.Value.Year == year) return await _buildCollection.Find(b => b.SourceType == source)
.SortByDescending(b => b.BuildTime) .SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion) .ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
@ -312,23 +327,44 @@ public List<BuildModel> SelectYear(int year, int skip, int limit)
.Skip(skip) .Skip(skip)
.Limit(limit) .Limit(limit)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public long SelectYearCount(int year) public async Task<long> SelectSourceCount(TypeOfSource source)
{ {
var task = _buildCollection.Find(b => b.BuildTime.HasValue && b.BuildTime.Value.Year == year) return await _buildCollection.Find(b => b.SourceType == source)
.CountAsync(); .CountAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildModel> SelectVersion(int major, int minor, int skip, int limit) public async Task<List<BuildModel>> SelectYear(int year, int skip, int limit)
{ {
var task = _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor) return await _buildCollection.Find(b => b.BuildTime != null &&
(b.BuildTime > new DateTime(year, 1, 1, 0, 0, 0)) &&
(b.BuildTime < new DateTime(year, 12, 31, 23, 59, 59)))
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<long> SelectYearCount(int year)
{
return await _buildCollection.Find(b => b.BuildTime != null &&
(b.BuildTime > new DateTime(year, 1, 1, 0, 0, 0)) &&
(b.BuildTime < new DateTime(year, 12, 31, 23, 59, 59)))
.CountAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> SelectVersion(int major, int minor, int skip, int limit)
{
return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.SortByDescending(b => b.BuildTime) .SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion) .ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion) .ThenByDescending(b => b.MinorVersion)
@ -337,23 +373,19 @@ public List<BuildModel> SelectVersion(int major, int minor, int skip, int limit)
.Skip(skip) .Skip(skip)
.Limit(limit) .Limit(limit)
.ToListAsync(); .ToListAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public long SelectVersionCount(int major, int minor) public async Task<long> SelectVersionCount(int major, int minor)
{ {
var task = _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor) return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.CountAsync(); .CountAsync();
task.Wait();
return task.Result;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<BuildVersion> SelectBuildVersions() public async Task<List<BuildVersion>> SelectBuildVersions()
{ {
var task = _buildCollection.Aggregate() var result = await _buildCollection.Aggregate()
.Group(b => new BuildVersion() .Group(b => new BuildVersion()
{ {
Major = b.MajorVersion, Major = b.MajorVersion,
@ -365,16 +397,14 @@ public List<BuildVersion> SelectBuildVersions()
.ThenByDescending(b => b.Item1.Minor) .ThenByDescending(b => b.Item1.Minor)
.ToListAsync(); .ToListAsync();
task.Wait();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return task.Result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<int> SelectBuildYears() public async Task<List<int>> SelectBuildYears()
{ {
var task = _buildCollection.Aggregate() var result = await _buildCollection.Aggregate()
.Match(b => b.BuildTime != null) .Match(b => b.BuildTime != null)
.Group(b => ((DateTime)b.BuildTime).Year, .Group(b => ((DateTime)b.BuildTime).Year,
// incoming bullshit hack // incoming bullshit hack
@ -382,16 +412,14 @@ public IEnumerable<int> SelectBuildYears()
.SortByDescending(b => b.Item1) .SortByDescending(b => b.Item1)
.ToListAsync(); .ToListAsync();
task.Wait();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return task.Result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public List<string> SearchBuildLabs(string query) public async Task<List<string>> SearchBuildLabs(string query)
{ {
var task = _buildCollection.Aggregate() var result = await _buildCollection.Aggregate()
.Match(b => b.Lab != null) .Match(b => b.Lab != null)
.Match(b => b.Lab != "") .Match(b => b.Lab != "")
.Match(b => b.Lab.ToLower().Contains(query.ToLower())) .Match(b => b.Lab.ToLower().Contains(query.ToLower()))
@ -400,16 +428,14 @@ public List<string> SearchBuildLabs(string query)
bg => new Tuple<string>(bg.Key)) bg => new Tuple<string>(bg.Key))
.ToListAsync(); .ToListAsync();
task.Wait();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return task.Result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<string> SelectBuildLabs() public async Task<List<string>> SelectBuildLabs()
{ {
var task = _buildCollection.Aggregate() var result = await _buildCollection.Aggregate()
.Match(b => b.Lab != null) .Match(b => b.Lab != null)
.Match(b => b.Lab != "") .Match(b => b.Lab != "")
.Group(b => b.Lab.ToLower(), .Group(b => b.Lab.ToLower(),
@ -418,16 +444,14 @@ public IEnumerable<string> SelectBuildLabs()
.SortBy(b => b.Item1) .SortBy(b => b.Item1)
.ToListAsync(); .ToListAsync();
task.Wait();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return task.Result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<string> SelectBuildLabs(byte major, byte minor) public async Task<List<string>> SelectBuildLabs(byte major, byte minor)
{ {
var task = _buildCollection.Aggregate() var result = await _buildCollection.Aggregate()
.Match(b => b.MajorVersion == major) .Match(b => b.MajorVersion == major)
.Match(b => b.MinorVersion == minor) .Match(b => b.MinorVersion == minor)
.Match(b => b.Lab != null) .Match(b => b.Lab != null)
@ -438,43 +462,37 @@ public IEnumerable<string> SelectBuildLabs(byte major, byte minor)
.SortBy(b => b.Item1) .SortBy(b => b.Item1)
.ToListAsync(); .ToListAsync();
task.Wait();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return task.Result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
[DataObjectMethod(DataObjectMethodType.Insert, true)] [DataObjectMethod(DataObjectMethodType.Insert, true)]
public void Insert(BuildModel item) public async Task Insert(BuildModel item)
{ {
item.Id = Guid.NewGuid(); item.Id = Guid.NewGuid();
var task = _buildCollection.InsertOneAsync(item); await _buildCollection.InsertOneAsync(item);
task.Wait();
} }
[DataObjectMethod(DataObjectMethodType.Insert, false)] [DataObjectMethod(DataObjectMethodType.Insert, false)]
public void InsertAll(IEnumerable<BuildModel> items) public async Task InsertAll(IEnumerable<BuildModel> items)
{ {
var task = _buildCollection.InsertManyAsync(items); await _buildCollection.InsertManyAsync(items);
task.Wait();
} }
[DataObjectMethod(DataObjectMethodType.Update, true)] [DataObjectMethod(DataObjectMethodType.Update, true)]
public void Update(BuildModel item) public async Task Update(BuildModel item)
{ {
BuildModel old = SelectById(item.Id); BuildModel old = await SelectById(item.Id);
item.Added = old.Added; item.Added = old.Added;
item.Modified = DateTime.Now; item.Modified = DateTime.Now;
var task = _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item); await _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item);
task.Wait();
} }
[DataObjectMethod(DataObjectMethodType.Delete, true)] [DataObjectMethod(DataObjectMethodType.Delete, true)]
public void DeleteById(Guid id) public async Task DeleteById(Guid id)
{ {
var task = _buildCollection.DeleteOneAsync(f => f.Id == id); await _buildCollection.DeleteOneAsync(f => f.Id == id);
task.Wait();
} }
} }

View File

@ -6,159 +6,164 @@
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using Required = System.ComponentModel.DataAnnotations.RequiredAttribute; using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
namespace BuildFeed.Models namespace BuildFeed.Models
{ {
[DataObject] [DataObject]
public class MetaItemModel public class MetaItemModel
{ {
[Key] [Key]
[BsonId] [BsonId]
[@Required] [@Required]
public MetaItemKey Id { get; set; } public MetaItemKey Id { get; set; }
[DisplayName("Page Content")] [DisplayName("Page Content")]
[AllowHtml] [AllowHtml]
public string PageContent { get; set; } public string PageContent { get; set; }
[DisplayName("Meta Description")] [DisplayName("Meta Description")]
public string MetaDescription { get; set; } public string MetaDescription { get; set; }
} }
public class MetaItem public class MetaItem
{ {
private const string _metaCollectionName = "metaitem"; private const string _metaCollectionName = "metaitem";
private MongoClient _dbClient; private MongoClient _dbClient;
private IMongoCollection<MetaItemModel> _metaCollection; private IMongoCollection<MetaItemModel> _metaCollection;
private Build bModel;
public MetaItem() public MetaItem()
{ {
_dbClient = new MongoClient(new MongoClientSettings() _dbClient = new MongoClient(new MongoClientSettings()
{ {
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port) Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
}); });
_metaCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection<MetaItemModel>(_metaCollectionName); _metaCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection<MetaItemModel>(_metaCollectionName);
} bModel = new Build();
}
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<MetaItemModel> Select() public async Task<IEnumerable<MetaItemModel>> Select()
{ {
var task = _metaCollection.Find(new BsonDocument()).ToListAsync(); return await _metaCollection
task.Wait(); .Find(new BsonDocument())
return task.Result; .ToListAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, true)] [DataObjectMethod(DataObjectMethodType.Select, true)]
public IEnumerable<MetaItemModel> SelectByType(MetaType type) public async Task<IEnumerable<MetaItemModel>> SelectByType(MetaType type)
{ {
var task = _metaCollection.Find(f => f.Id.Type == type).ToListAsync(); return await _metaCollection
task.Wait(); .Find(f => f.Id.Type == type)
return task.Result; .ToListAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public MetaItemModel SelectById(MetaItemKey id) public async Task<MetaItemModel> SelectById(MetaItemKey id)
{ {
var task = _metaCollection.Find(f => f.Id.Type == id.Type && f.Id.Value == id.Value).SingleOrDefaultAsync(); return await _metaCollection
task.Wait(); .Find(f => f.Id.Type == id.Type && f.Id.Value == id.Value)
return task.Result; .SingleOrDefaultAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<string> SelectUnusedLabs() public async Task<IEnumerable<string>> SelectUnusedLabs()
{ {
var labs = new Build().SelectBuildLabs(); var labs = await bModel.SelectBuildLabs();
var usedLabs = _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync(); var usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync();
usedLabs.Wait();
return from l in labs return from l in labs
where usedLabs.Result.All(ul => ul.Id.Value != l) where usedLabs.All(ul => ul.Id.Value != l)
select l; select l;
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<string> SelectUnusedVersions() public async Task<IEnumerable<string>> SelectUnusedVersions()
{ {
var versions = new Build().SelectBuildVersions(); var versions = await bModel.SelectBuildVersions();
var usedVersions = _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync(); var usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync();
usedVersions.Wait();
return from v in versions return from v in versions
where usedVersions.Result.All(ul => ul.Id.Value != v.ToString()) where usedVersions.All(ul => ul.Id.Value != v.ToString())
select v.ToString(); select v.ToString();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public IEnumerable<string> SelectUnusedYears() public async Task<IEnumerable<string>> SelectUnusedYears()
{ {
var years = new Build().SelectBuildYears(); var years = await bModel.SelectBuildYears();
var usedYears = _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync(); var usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync();
usedYears.Wait();
return from y in years return from y in years
where usedYears.Result.All(ul => ul.Id.Value != y.ToString()) where usedYears.All(ul => ul.Id.Value != y.ToString())
select y.ToString(); select y.ToString();
} }
[DataObjectMethod(DataObjectMethodType.Insert, true)] [DataObjectMethod(DataObjectMethodType.Insert, true)]
public void Insert(MetaItemModel item) public async Task Insert(MetaItemModel item)
{ {
var task = _metaCollection.InsertOneAsync(item); await _metaCollection
task.Wait(); .InsertOneAsync(item);
} }
[DataObjectMethod(DataObjectMethodType.Update, true)] [DataObjectMethod(DataObjectMethodType.Update, true)]
public void Update(MetaItemModel item) public async Task Update(MetaItemModel item)
{ {
var task = _metaCollection.ReplaceOneAsync(f => f.Id.Type == item.Id.Type && f.Id.Value == item.Id.Value, item); await _metaCollection
task.Wait(); .ReplaceOneAsync(f => f.Id.Type == item.Id.Type && f.Id.Value == item.Id.Value, item);
} }
[DataObjectMethod(DataObjectMethodType.Insert, false)] [DataObjectMethod(DataObjectMethodType.Insert, false)]
public void InsertAll(IEnumerable<MetaItemModel> items) public async Task InsertAll(IEnumerable<MetaItemModel> items)
{ {
var task = _metaCollection.InsertManyAsync(items); await _metaCollection
task.Wait(); .InsertManyAsync(items);
} }
[DataObjectMethod(DataObjectMethodType.Delete, true)] [DataObjectMethod(DataObjectMethodType.Delete, true)]
public void DeleteById(MetaItemKey id) public async Task DeleteById(MetaItemKey id)
{ {
var task = _metaCollection.DeleteOneAsync(f => f.Id.Type == id.Type && f.Id.Value == id.Value); await _metaCollection
task.Wait(); .DeleteOneAsync(f => f.Id.Type == id.Type && f.Id.Value == id.Value);
} }
} }
public struct MetaItemKey public class MetaItemKey
{ {
public string Value { get; set; } public string Value { get; set; }
public MetaType Type { get; set; } public MetaType Type { get; set; }
public MetaItemKey(string id) public MetaItemKey()
{ {
var items = id.Split(':');
Type = (MetaType)Enum.Parse(typeof(MetaType), items[0]);
Value = items[1];
}
public override string ToString() }
{
return $"{Type}:{Value}";
}
}
public enum MetaType public MetaItemKey(string id)
{ {
Lab, var items = id.Split(':');
Version, Type = (MetaType)Enum.Parse(typeof(MetaType), items[0]);
Source, Value = items[1];
Year }
}
public override string ToString()
{
return $"{Type}:{Value}";
}
}
public enum MetaType
{
Lab,
Version,
Source,
Year
}
} }

View File

@ -13,7 +13,7 @@
} }
else else
{ {
string metaDesc = string.Format(BuildFeed.Local.Front.YearMetaGeneric, ViewBag.ViewId); string metaDesc = string.Format(BuildFeed.Local.Front.YearMetaGeneric, ViewBag.ItemId);
<meta name="description" content="@metaDesc" /> <meta name="description" content="@metaDesc" />
<meta property="og:description" content="@metaDesc" /> <meta property="og:description" content="@metaDesc" />
} }

View File

@ -1,142 +1,142 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/slate/bootstrap.min.css" rel="stylesheet" /> <link href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/slate/bootstrap.min.css" rel="stylesheet" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" /> <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="//fonts.googleapis.com/css?family=Hind:300,700,400" rel="stylesheet" type="text/css" /> <link href="//fonts.googleapis.com/css?family=Hind:300,700,400" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="~/favicon.ico" /> <link rel="shortcut icon" href="~/favicon.ico" />
<link rel="icon" href="~/favicon.ico" /> <link rel="icon" href="~/favicon.ico" />
<link rel="canonical" href="@Url.Action()" /> <link rel="canonical" href="@Url.Action()" />
<meta name="application-name" content="@BuildFeed.Local.Common.SiteName" /> <meta name="application-name" content="@BuildFeed.Local.Common.SiteName" />
@Styles.Render("~/content/css") @Styles.Render("~/content/css")
<title>@ViewBag.Title</title> <title>@ViewBag.Title</title>
@RenderSection("head", false) @RenderSection("head", false)
<script type="text/javascript"> <script type="text/javascript">
var appInsights = window.appInsights || function (config) { var appInsights = window.appInsights || function (config) {
function s(config) { t[config] = function () { var i = arguments; t.queue.push(function () { t[config].apply(t, i) }) } } var t = { config: config }, r = document, f = window, e = "script", o = r.createElement(e), i, u; for (o.src = config.url || "//az416426.vo.msecnd.net/scripts/a/ai.0.js", r.getElementsByTagName(e)[0].parentNode.appendChild(o), t.cookie = r.cookie, t.queue = [], i = ["Event", "Exception", "Metric", "PageView", "Trace"]; i.length;) s("track" + i.pop()); return config.disableExceptionTracking || (i = "onerror", s("_" + i), u = f[i], f[i] = function (config, r, f, e, o) { var s = u && u(config, r, f, e, o); return s !== !0 && t["_" + i](config, r, f, e, o), s }), t function s(config) { t[config] = function () { var i = arguments; t.queue.push(function () { t[config].apply(t, i) }) } } var t = { config: config }, r = document, f = window, e = "script", o = r.createElement(e), i, u; for (o.src = config.url || "//az416426.vo.msecnd.net/scripts/a/ai.0.js", r.getElementsByTagName(e)[0].parentNode.appendChild(o), t.cookie = r.cookie, t.queue = [], i = ["Event", "Exception", "Metric", "PageView", "Trace"]; i.length;) s("track" + i.pop()); return config.disableExceptionTracking || (i = "onerror", s("_" + i), u = f[i], f[i] = function (config, r, f, e, o) { var s = u && u(config, r, f, e, o); return s !== !0 && t["_" + i](config, r, f, e, o), s }), t
}({ }({
instrumentationKey: "4632419f-7a2f-4ab5-8374-34384b650f42" instrumentationKey: "4632419f-7a2f-4ab5-8374-34384b650f42"
}); });
window.appInsights = appInsights; window.appInsights = appInsights;
appInsights.trackPageView(); appInsights.trackPageView();
</script> </script>
</head> </head>
<body> <body>
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () { i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments) (i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o), }, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga'); })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-55417692-1', 'auto'); ga('create', 'UA-55417692-1', 'auto');
ga('require', 'displayfeatures'); ga('require', 'displayfeatures');
ga('require', 'linkid', 'linkid.js'); ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview'); ga('send', 'pageview');
</script> </script>
<div class="container"> <div class="container">
<header id="page-header"></header> <header id="page-header"></header>
<nav id="page-navigation" role="navigation"> <nav id="page-navigation" role="navigation">
<div class="navbar navbar-default navbar-fixed-top"> <div class="navbar navbar-default navbar-fixed-top">
<div class="container"> <div class="container">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#page-navigation-collapse"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#page-navigation-collapse">
<span class="sr-only">@BuildFeed.Local.Common.ToggleNavigation</span> <span class="sr-only">@BuildFeed.Local.Common.ToggleNavigation</span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
@Html.ActionLink(BuildFeed.Local.Common.SiteName, "index", new { controller = "front", area = "" }, new { @class = "navbar-brand" }) @Html.ActionLink(BuildFeed.Local.Common.SiteName, "index", new { controller = "front", area = "" }, new { @class = "navbar-brand" })
</div> </div>
<div class="collapse navbar-collapse" id="page-navigation-collapse"> <div class="collapse navbar-collapse" id="page-navigation-collapse">
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
@if (!User.Identity.IsAuthenticated) @if (!User.Identity.IsAuthenticated)
{ {
<li><a href="@Url.Action("login", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogIn"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogIn</a></li> <li><a href="@Url.Action("login", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogIn"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogIn</a></li>
} }
else if (Roles.IsUserInRole("Administrators")) else if (Roles.IsUserInRole("Administrators"))
{ {
<li><a href="@Url.Action("index", new { controller = "base", area = "admin" })" title="@BuildFeed.Local.Common.Admin"><i class="fa fa-fw fa-cogs"></i> @BuildFeed.Local.Common.Admin</a></li> <li><a href="@Url.Action("index", new { controller = "base", area = "admin" })" title="@BuildFeed.Local.Common.Admin"><i class="fa fa-fw fa-cogs"></i> @BuildFeed.Local.Common.Admin</a></li>
<li><a href="@Url.Action("addBuild", new { controller = "front", area = "" })" title="@BuildFeed.Local.Common.AddBuild"><i class="fa fa-fw fa-plus-square"></i> @BuildFeed.Local.Common.AddBuild</a></li> <li><a href="@Url.Action("addBuild", new { controller = "front", area = "" })" title="@BuildFeed.Local.Common.AddBuild"><i class="fa fa-fw fa-plus-square"></i> @BuildFeed.Local.Common.AddBuild</a></li>
<li><a href="@Url.Action("logout", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogOut"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogOut</a></li> <li><a href="@Url.Action("logout", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogOut"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogOut</a></li>
} }
else else
{ {
<li><a href="@Url.Action("addBuild", new { controller = "front", area = "" })" title="@BuildFeed.Local.Common.AddBuild"><i class="fa fa-fw fa-plus-square"></i> @BuildFeed.Local.Common.AddBuild</a></li> <li><a href="@Url.Action("addBuild", new { controller = "front", area = "" })" title="@BuildFeed.Local.Common.AddBuild"><i class="fa fa-fw fa-plus-square"></i> @BuildFeed.Local.Common.AddBuild</a></li>
<li><a href="@Url.Action("logout", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogOut"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogOut</a></li> <li><a href="@Url.Action("logout", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.LogOut"><i class="fa fa-fw fa-user"></i> @BuildFeed.Local.Common.LogOut</a></li>
} }
<li><a href="#" title="Search" id="page-navigation-search" title="@BuildFeed.Local.Common.Search"><i class="fa fa-fw fa-search"></i> @BuildFeed.Local.Common.Search</a></li> <li><a href="#" title="Search" id="page-navigation-search" title="@BuildFeed.Local.Common.Search"><i class="fa fa-fw fa-search"></i> @BuildFeed.Local.Common.Search</a></li>
<li><a href="@Url.Action("stats", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.Statistics"><i class="fa fa-fw fa-line-chart"></i> @BuildFeed.Local.Common.Statistics</a></li> <li><a href="@Url.Action("stats", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.Statistics"><i class="fa fa-fw fa-line-chart"></i> @BuildFeed.Local.Common.Statistics</a></li>
<li><a href="@Url.Action("rss", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.RssFeeds"><i class="fa fa-fw fa-rss"></i> @BuildFeed.Local.Common.RssFeeds</a></li> <li><a href="@Url.Action("rss", new { controller = "support", area = "" })" title="@BuildFeed.Local.Common.RssFeeds"><i class="fa fa-fw fa-rss"></i> @BuildFeed.Local.Common.RssFeeds</a></li>
<li><a href="https://twitter.com/buildfeed" title="@BuildFeed.Local.Common.Twitter" target="_blank"><i class="fa fa-fw fa-twitter"></i> @BuildFeed.Local.Common.Twitter</a></li> <li><a href="https://twitter.com/buildfeed" title="@BuildFeed.Local.Common.Twitter" target="_blank"><i class="fa fa-fw fa-twitter"></i> @BuildFeed.Local.Common.Twitter</a></li>
</ul> </ul>
</div> </div>
</div>
</div> </div>
</nav> </div>
<article id="page-content"> </nav>
<div class="row"> <article id="page-content">
<div class="col-sm-12"> <div class="row">
@RenderBody() <div class="col-sm-12">
</div> @RenderBody()
</div> </div>
</article> </div>
<footer id="page-footer"> </article>
<div class="row"> <footer id="page-footer">
<div class="col-sm-8"> <div class="row">
<p> <div class="col-sm-8">
<a href="@Url.Action("sitemap", new { controller = "support" })">@BuildFeed.Local.Common.Sitemap</a> <p>
</p> <a href="@Url.Action("sitemap", new { controller = "support" })">@BuildFeed.Local.Common.Sitemap</a>
</div> </p>
<div class="col-sm-4 text-right">
<p>
&copy; 2013 - @DateTime.Now.Year.ToString(), @BuildFeed.Local.Common.SiteName<br />
@BuildFeed.Local.Common.DevelopedBy <a href="https://twitter.com/tomhounsell" target="_blank">Thomas Hounsell</a><br />
@BuildFeed.Local.Common.ContributeOn&ensp;<a href="https://github.com/hounsell/BuildFeed" target="_blank"><i class="fa fa-github"></i>&ensp;GitHub</a>
</p>
</div>
</div> </div>
</footer> <div class="col-sm-4 text-right">
</div> <p>
<div class="modal fade" id="search-modal" tabindex="-1" role="dialog" aria-hidden="true"> &copy; 2013 - @DateTime.Now.Year.ToString(), @BuildFeed.Local.Common.SiteName<br />
<div class="modal-dialog modal-lg"> @BuildFeed.Local.Common.DevelopedBy <a href="https://twitter.com/tomhounsell" target="_blank">Thomas Hounsell</a><br />
<div class="modal-content"> @BuildFeed.Local.Common.ContributeOn&ensp;<a href="https://github.com/hounsell/BuildFeed" target="_blank"><i class="fa fa-github"></i>&ensp;GitHub</a>
<div class="modal-header"> </p>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">@BuildFeed.Local.Common.SearchBuildFeed</h4>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
@Html.Label("search-input", BuildFeed.Local.Common.SearchQuery, new { @class = "sr-only" })
@Html.TextBox("search-input", "", new { @class = "form-control", placeholder = BuildFeed.Local.Common.TypeToSearch })
</div>
</div>
</div>
<div class="row" id="search-results"></div>
</div>
</div> </div>
</div> </div>
</div> </footer>
@Scripts.Render("~/bundles/jquery") </div>
<script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> <div class="modal fade" id="search-modal" tabindex="-1" role="dialog" aria-hidden="true">
@Scripts.Render("~/bundles/jsrender") <div class="modal-dialog modal-lg">
<script type="text/javascript" src="~/Scripts/bfs.js"></script> <div class="modal-content">
@RenderSection("scripts", required: false) <div class="modal-header">
<script id="result-template" type="text/x-jsrender"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<div class="col-sm-4"> <h4 class="modal-title">@BuildFeed.Local.Common.SearchBuildFeed</h4>
<a href="{{:Url}}" class="list-group-item" title="{{:Title}}"> </div>
<h4 class="list-group-item-heading">{{:Label}}</h4> <div class="modal-body">
<p class="list-group-item-text">{{:Group}}</p> <div class="container-fluid">
</a> <div class="row">
</div> <div class="col-sm-6 col-sm-offset-3">
</script> @Html.Label("search-input", BuildFeed.Local.Common.SearchQuery, new { @class = "sr-only" })
@Html.TextBox("search-input", "", new { @class = "form-control", placeholder = BuildFeed.Local.Common.TypeToSearch })
</div>
</div>
</div>
<div class="row" id="search-results"></div>
</div>
</div>
</div>
</div>
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
@Scripts.Render("~/bundles/jsrender")
<script type="text/javascript" src="~/Scripts/bfs.js"></script>
@RenderSection("scripts", required: false)
<script id="result-template" type="text/x-jsrender">
<div class="col-sm-4">
<a href="{{:Url}}" class="list-group-item" title="{{:Title}}">
<h4 class="list-group-item-heading">{{:Label}}</h4>
<p class="list-group-item-text">{{:Group}}</p>
</a>
</div>
</script>
</body> </body>
</html> </html>

View File

@ -1,6 +1,6 @@
@model BuildFeed.Models.ViewModel.SitemapData @model BuildFeed.Models.ViewModel.SitemapData
@{ @{
ViewBag.Title = string.Format("{0} | {1}".BuildFeed.Local.Common.Sitemap, BuildFeed.Local.Common.SiteName); ViewBag.Title = string.Format("{0} | {1}", BuildFeed.Local.Common.Sitemap, BuildFeed.Local.Common.SiteName);
} }
<h2>@BuildFeed.Local.Common.Sitemap</h2> <h2>@BuildFeed.Local.Common.Sitemap</h2>

View File

@ -6,14 +6,14 @@
<h2>@BuildFeed.Local.Common.Statistics</h2> <h2>@BuildFeed.Local.Common.Statistics</h2>
<h4>New additions to BuildFeed over the previous year</h4> <h4>@BuildFeed.Local.Support.StatsNewAdditions</h4>
<canvas id="stats-addition" width="960" height="320"></canvas> <canvas id="stats-addition" width="960" height="320"></canvas>
<h4>Builds compiled each quarter</h4> <h4>@BuildFeed.Local.Support.StatsCompiled</h4>
<canvas id="stats-compiled" width="960" height="320"></canvas> <canvas id="stats-compiled" width="960" height="320"></canvas>
<h4>Recorded builds in each lab</h4> <h4>@BuildFeed.Local.Support.StatsLab</h4>
<p>Only labs with 100 or more recorded builds are included.</p> <p>@BuildFeed.Local.Support.StatsLabIncluded</p>
<canvas id="stats-labs" width="960" height="320"></canvas> <canvas id="stats-labs" width="960" height="320"></canvas>
@section scripts @section scripts
@ -29,10 +29,10 @@
Chart.defaults.Line.scaleShowGridLines = false; Chart.defaults.Line.scaleShowGridLines = false;
var additionData = { var additionData = {
labels: [ @Html.Raw(string.Join(", ", Model.AdditionsByMonth.Select(m => m.Month % 4 != 1 ? "\"\"" : string.Format("\"Week {0}, {1}\"", m.Month, m.Year)).ToArray()))], labels: [ @Html.Raw(string.Join(", ", Model.AdditionsByMonth.Select(m => m.Month % 4 != 1 ? "\"\"" : string.Format("\"{0} {1}, {2}\"", BuildFeed.Local.Support.Week, m.Month, m.Year)).ToArray()))],
datasets: [ datasets: [
{ {
label: "Additions to BuildFeed", label: "@BuildFeed.Local.Support.AdditionsToBuildFeed",
fillColor: "#008cba", fillColor: "#008cba",
strokeColor: "#00526e", strokeColor: "#00526e",
pointColor: "#00526e", pointColor: "#00526e",
@ -46,10 +46,10 @@
var compiledData = { var compiledData = {
labels: [ @Html.Raw(string.Join(", ", Model.CompilesByMonth.Select(m => string.Format("\"{0} {1}\"", System.Globalization.DateTimeFormatInfo.InvariantInfo.GetMonthName(m.Month), m.Year)).ToArray()))], labels: [ @Html.Raw(string.Join(", ", Model.CompilesByMonth.Select(m => string.Format("\"{0} {1}\"", System.Globalization.DateTimeFormatInfo.CurrentInfo.GetMonthName(m.Month), m.Year)).ToArray()))],
datasets: [ datasets: [
{ {
label: "Builds compiled", label: "@BuildFeed.Local.Support.BuildsCompiled",
fillColor: "#008cba", fillColor: "#008cba",
strokeColor: "#00526e", strokeColor: "#00526e",
pointColor: "#00526e", pointColor: "#00526e",
@ -65,7 +65,7 @@
labels: [ @Html.Raw(string.Join(", ", Model.BuildsByLab.Select(l => string.Format("\"{0}\"", l.Item1))))], labels: [ @Html.Raw(string.Join(", ", Model.BuildsByLab.Select(l => string.Format("\"{0}\"", l.Item1))))],
datasets: [ datasets: [
{ {
label: "Labs", label: "@BuildFeed.Local.Support.Labs",
fillColor: "#008cba", fillColor: "#008cba",
strokeColor: "#00526e", strokeColor: "#00526e",
pointColor: "#00526e", pointColor: "#00526e",