Lotsa fixes, some Localisation

refactor-intermediate-models
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 BuildFeed.Areas.admin.Models.ViewModel;
using BuildFeed.Models;
using System.Threading.Tasks;
namespace BuildFeed.Areas.admin.Controllers
{
[Authorize(Roles = "Administrators")]
public class metaController : Controller
{
// GET: admin/meta
public ActionResult index()
{
var currentItems = from i in new MetaItem().Select()
group i by i.Id.Type
into b
select b;
[Authorize(Roles = "Administrators")]
public class metaController : Controller
{
private MetaItem mModel;
var pendingLabs = new MetaItem().SelectUnusedLabs();
public metaController() : base()
{
mModel = new MetaItem();
}
return View(new MetaListing
{
CurrentItems = from i in new MetaItem().Select()
group i by i.Id.Type
into b
orderby b.Key.ToString()
select b,
NewItems = from i in (from l in new MetaItem().SelectUnusedLabs()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Lab,
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
}
})
// GET: admin/meta
public async Task<ActionResult> index()
{
var currentItems = from i in await mModel.Select()
group i by i.Id.Type
into b
select b;
var pendingLabs = mModel.SelectUnusedLabs();
return View(new MetaListing
{
CurrentItems = from i in await mModel.Select()
group i by i.Id.Type
into b
into b
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)
{
return View(new MetaItemModel
public ActionResult create(MetaType type, string value)
{
return View(new MetaItemModel
{
Id = new MetaItemKey
{
Id = new MetaItemKey
{
Type = type,
Value = value
}
});
}
[HttpPost]
public ActionResult create(MetaItemModel meta)
{
if (ModelState.IsValid)
{
new MetaItem().Insert(meta);
return RedirectToAction("index");
Type = type,
Value = value
}
});
}
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("create", new MetaItem().SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
}
return View(meta);
}
[HttpPost]
public ActionResult edit(MetaItemModel meta)
{
if (ModelState.IsValid)
{
new MetaItem().Update(meta);
return RedirectToAction("index");
}
public async Task<ActionResult> edit(MetaType type, string value)
{
return View("create", await mModel.SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
}
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>
<DependentUpon>Model.resx</DependentUpon>
</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">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@ -437,6 +442,10 @@
<LastGenOutput>Model.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Local\Support.qps-ploc.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Support.qps-ploc.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Local\Support.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Support.Designer.cs</LastGenOutput>

View File

@ -4,6 +4,7 @@ using BuildFeed.Models.ApiModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Security;
@ -18,22 +19,22 @@ namespace BuildFeed.Controllers
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>();
labs.AddRange(bModel.SelectBuildLabs(6, 4));
labs.AddRange(bModel.SelectBuildLabs(10, 0));
labs.AddRange(await bModel.SelectBuildLabs(6, 4));
labs.AddRange(await bModel.SelectBuildLabs(10, 0));
return labs.GroupBy(l => l).Select(l => l.Key).Where(l => l.All(c => c != '(')).ToArray();
}
[HttpPost]
public bool AddWin10Builds(NewBuild apiModel)
public async Task<bool> AddWin10Builds(NewBuild apiModel)
{
if (apiModel == null)
{
@ -41,7 +42,7 @@ namespace BuildFeed.Controllers
}
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,
MinorVersion = nb.MinorVersion,
@ -59,7 +60,7 @@ namespace BuildFeed.Controllers
}
}
public IEnumerable<SearchResult> GetSearchResult(string query)
public async Task<IEnumerable<SearchResult>> GetSearchResult(string query)
{
if (string.IsNullOrWhiteSpace(query))
{
@ -82,7 +83,7 @@ namespace BuildFeed.Controllers
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)
orderby v.Major descending, v.Minor descending
select new SearchResult()
@ -96,7 +97,7 @@ namespace BuildFeed.Controllers
results.AddRange(versionResults);
var yearResults = from y in bModel.SelectBuildYears()
var yearResults = from y in await bModel.SelectBuildYears()
where y.ToString().Contains(query)
orderby y descending
select new SearchResult()
@ -110,7 +111,7 @@ namespace BuildFeed.Controllers
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,
l.Length ascending
select new SearchResult()
@ -124,7 +125,7 @@ namespace BuildFeed.Controllers
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())
orderby b.FullBuildString.ToLower().IndexOf(query.ToLower(), StringComparison.Ordinal) ascending,
b.BuildTime descending

View File

@ -5,6 +5,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace BuildFeed.Controllers
@ -24,19 +25,19 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#endif
public ActionResult index() { return indexPage(1); }
public async Task<ActionResult> index() { return await indexPage(1); }
[Route("page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#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.PageCount = Math.Ceiling(
Convert.ToDouble(bModel.SelectBuildGroupsCount()) /
Convert.ToDouble(await bModel.SelectBuildGroupsCount()) /
Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount)
@ -51,9 +52,9 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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,
Minor = minor,
@ -70,9 +71,9 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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);
}
@ -81,9 +82,9 @@ namespace BuildFeed.Controllers
[OutputCache(Duration = 600, VaryByParam = "none")]
[CustomContentType(ContentType = "image/png", Order = 2)]
#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))
{
@ -116,13 +117,13 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif
public ActionResult viewLabPage(string lab, int page)
public async Task<ActionResult> viewLabPage(string lab, int page)
{
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{
@ -131,10 +132,10 @@ namespace BuildFeed.Controllers
});
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.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)
{
@ -148,13 +149,13 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif
public ActionResult viewSourcePage(TypeOfSource source, int page)
public async Task<ActionResult> viewSourcePage(TypeOfSource source, int page)
{
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{
@ -163,10 +164,10 @@ namespace BuildFeed.Controllers
});
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.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)
{
@ -180,13 +181,13 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName")]
#endif
public ActionResult viewYearPage(int year, int page)
public async Task<ActionResult> viewYearPage(int year, int page)
{
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
{
@ -195,10 +196,10 @@ namespace BuildFeed.Controllers
});
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.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)
{
@ -212,13 +213,13 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName")]
#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}";
ViewBag.MetaItem = new MetaItem().SelectById(new MetaItemKey
@ -228,10 +229,10 @@ namespace BuildFeed.Controllers
});
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.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)
{
@ -245,7 +246,7 @@ namespace BuildFeed.Controllers
public ActionResult addBuild() { return View("editBuild"); }
[Route("add/"), Authorize, HttpPost]
public ActionResult addBuild(BuildModel build)
public async Task<ActionResult> addBuild(BuildModel build)
{
if (ModelState.IsValid)
{
@ -253,7 +254,7 @@ namespace BuildFeed.Controllers
{
build.Added = DateTime.Now;
build.Modified = DateTime.Now;
new Build().Insert(build);
await bModel.Insert(build);
}
catch
{
@ -268,20 +269,20 @@ namespace BuildFeed.Controllers
}
[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);
}
[Route("edit/{id}/"), Authorize, HttpPost]
public ActionResult editBuild(long id, BuildModel build)
public async Task<ActionResult> editBuild(long id, BuildModel build)
{
if (ModelState.IsValid)
{
try
{
new Build().Update(build);
await bModel.Update(build);
}
catch
{
@ -294,9 +295,9 @@ namespace BuildFeed.Controllers
}
[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");
}
}

View File

@ -10,219 +10,237 @@ using X.Web.RSS.Structure.Validators;
namespace BuildFeed.Controllers
{
public class rssController : Controller
{
[Route("rss/compiled")]
public async Task<ActionResult> index()
{
var builds = new Build().SelectInBuildOrder().Take(20);
public class rssController : Controller
{
private Build bModel;
private const int RSS_SIZE = 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 = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = "BuildFeed RSS - Recently Compiled",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })) },
}).ToList()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })) },
}).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")]
public async Task<ActionResult> added()
{
var builds = new Build().Select().OrderByDescending(b => b.Added).Take(20);
[Route("rss/added")]
public async Task<ActionResult> added()
{
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 = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = "BuildFeed RSS - Recently Added",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
InternalPubDate = new RssDate(build.Added).DateStringISO8601 // bit of a dirty hack to work around problem in X.Web.RSS with the date format.
}).ToList()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
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")]
public async Task<ActionResult> leaked()
{
var builds = new Build().Select().Where(b => b.LeakDate.HasValue).OrderByDescending(b => b.LeakDate.Value).Take(20);
[Route("rss/leaked")]
public async Task<ActionResult> leaked()
{
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 = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = "BuildFeed RSS - Recently Leaked",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
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()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
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")]
public async Task<ActionResult> version()
{
var builds = new Build().SelectInVersionOrder()
.Take(20);
[Route("rss/version")]
public async Task<ActionResult> version()
{
var builds = await bModel.SelectInVersionOrder(RSS_SIZE, 0);
RssDocument rdoc = new RssDocument()
RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{
Channel = new RssChannel()
{
Title = "BuildFeed RSS - Highest Version",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = "BuildFeed RSS - Highest Version",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).ToList()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).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}")]
public async Task<ActionResult> flight(LevelOfFlight id)
{
var builds = new Build().SelectInBuildOrder()
.Where(b => b.FlightLevel == id)
.Take(20);
[Route("rss/flight/{id}")]
public async Task<ActionResult> flight(LevelOfFlight id)
{
var builds = await bModel.SelectFlight(id, RSS_SIZE, 0);
RssDocument rdoc = new RssDocument()
RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{
Channel = new RssChannel()
{
Title = $"BuildFeed RSS - {id} Flight Level",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = $"BuildFeed RSS - {id} Flight Level",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).ToList()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).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}")]
public async Task<ActionResult> lab(string lab)
{
var builds = new Build().SelectInBuildOrder()
.Where(b => b.Lab == lab)
.Take(20);
[Route("rss/lab/{lab}")]
public async Task<ActionResult> lab(string lab)
{
var builds = await bModel.SelectLab(lab, RSS_SIZE, 0);
RssDocument rdoc = new RssDocument()
RssDocument rdoc = new RssDocument()
{
Channel = new RssChannel()
{
Channel = new RssChannel()
{
Title = $"BuildFeed RSS - {lab} Lab",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Title = $"BuildFeed RSS - {lab} Lab",
Description = "",
Generator = "BuildFeed.net RSS Controller",
Link = new RssUrl($"{Request.Url.Scheme}://{Request.Url.Authority}"),
SkipHours = new List<Hour>(),
SkipDays = new List<Day>(),
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).ToList()
}
};
Items = (from build in builds
select new RssItem()
{
Title = build.FullBuildString,
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 })}"
},
}).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 BuildFeed.Models.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
@ -11,135 +12,142 @@ using System.Xml.Linq;
namespace BuildFeed.Controllers
{
public class supportController : Controller
{
[Route("login/")]
public ActionResult login()
{
return View();
}
public class supportController : Controller
{
private Build bModel;
[HttpPost, Route("login/")]
public ActionResult login(LoginUser ru)
{
if (ModelState.IsValid)
public supportController() : base()
{
bModel = new Build();
}
[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)
{
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"];
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.";
return View(ru);
}
ViewData["ErrorMessage"] = "The username and password are not valid.";
return View(ru);
}
[Authorize, Route("password/")]
public ActionResult password()
{
return View();
}
[Authorize, Route("password/")]
public ActionResult password()
{
return View();
}
[HttpPost, Authorize, Route("password/")]
public ActionResult password(ChangePassword cp)
{
if (ModelState.IsValid)
[HttpPost, Authorize, Route("password/")]
public ActionResult password(ChangePassword cp)
{
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)
{
bool success = user.ChangePassword(cp.OldPassword, cp.NewPassword);
if (success)
{
return Redirect("/");
}
}
if (success)
{
return Redirect("/");
}
}
}
ViewData["ErrorMessage"] = "There was an error changing your password.";
return View(cp);
}
ViewData["ErrorMessage"] = "There was an error changing your password.";
return View(cp);
}
[Route("logout/")]
public ActionResult logout()
{
FormsAuthentication.SignOut();
return Redirect("/");
}
[Route("logout/")]
public ActionResult logout()
{
FormsAuthentication.SignOut();
return Redirect("/");
}
[Route("register/")]
public ActionResult register()
{
return View();
}
[Route("register/")]
public ActionResult register()
{
return View();
}
[HttpPost, Route("register/")]
public ActionResult register(RegistrationUser ru)
{
if (ModelState.IsValid)
[HttpPost, Route("register/")]
public ActionResult register(RegistrationUser ru)
{
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;
Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "THIS WILL BE IGNORED", "I WILL BE IGNORED", false, out status);
switch (status)
{
case MembershipCreateStatus.Success:
return RedirectToAction("thanks_register");
case MembershipCreateStatus.InvalidPassword:
ViewData["ErrorMessage"] = "The password is invalid.";
break;
case MembershipCreateStatus.DuplicateEmail:
ViewData["ErrorMessage"] = "A user account with this email address already exists.";
break;
case MembershipCreateStatus.DuplicateUserName:
ViewData["ErrorMessage"] = "A user account with this user name already exists.";
break;
default:
ViewData["ErrorMessage"] = "Unspecified error.";
break;
}
case MembershipCreateStatus.Success:
return RedirectToAction("thanks_register");
case MembershipCreateStatus.InvalidPassword:
ViewData["ErrorMessage"] = "The password is invalid.";
break;
case MembershipCreateStatus.DuplicateEmail:
ViewData["ErrorMessage"] = "A user account with this email address already exists.";
break;
case MembershipCreateStatus.DuplicateUserName:
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/")]
public ActionResult thanks_register()
{
return View();
}
[Route("register/thanks/")]
public ActionResult thanks_register()
{
return View();
}
[Route("rss")]
public ActionResult rss()
{
ViewBag.Labs = new Build().SelectBuildLabs();
return View();
}
[Route("rss")]
public ActionResult rss()
{
ViewBag.Labs = bModel.SelectBuildLabs();
return View();
}
[Route("sitemap/")]
[Route("sitemap/")]
#if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif
public ActionResult sitemap()
{
var builds = new Build().SelectInVersionOrder();
Dictionary<string, SitemapPagedAction[]> actions = new Dictionary<string, SitemapPagedAction[]>
public async Task<ActionResult> sitemap()
{
var builds = await bModel.SelectInVersionOrder();
Dictionary<string, SitemapPagedAction[]> actions = new Dictionary<string, SitemapPagedAction[]>
{
{
"Pages", new[]
@ -243,145 +251,145 @@ namespace BuildFeed.Controllers
SitemapData model = new SitemapData()
{
Builds = (from b in new Build().Select()
group b by new BuildGroup()
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
Build = b.Number,
Revision = b.Revision
} into bg
orderby bg.Key.Major descending,
bg.Key.Minor descending,
bg.Key.Build descending,
bg.Key.Revision descending
select new SitemapDataBuildGroup()
{
Id = bg.Key,
Builds = (from bgb in bg
select new SitemapDataBuild()
{
Id = bgb.Id,
Name = bgb.FullBuildString
}).ToArray()
}).ToArray(),
SitemapData model = new SitemapData()
{
Builds = (from b in await bModel.Select()
group b by new BuildGroup()
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
Build = b.Number,
Revision = b.Revision
} into bg
orderby bg.Key.Major descending,
bg.Key.Minor descending,
bg.Key.Build descending,
bg.Key.Revision descending
select new SitemapDataBuildGroup()
{
Id = bg.Key,
Builds = (from bgb in bg
select new SitemapDataBuild()
{
Id = bgb.Id,
Name = bgb.FullBuildString
}).ToArray()
}).ToArray(),
Actions = actions,
Labs = (from b in builds
group b by b.Lab into lab
select lab.Key).ToArray()
};
Actions = actions,
Labs = (from b in builds
group b by b.Lab into lab
select lab.Key).ToArray()
};
return View(model);
}
return View(model);
}
[Route("xml-sitemap/")]
[Route("xml-sitemap/")]
#if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif
public ActionResult xmlsitemap()
{
XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
List<XElement> xlist = new List<XElement>();
public async Task<ActionResult> xmlsitemap()
{
XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
List<XElement> xlist = new List<XElement>();
// home page
XElement home = new XElement(xn + "url");
home.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + "/"));
home.Add(new XElement(xn + "changefreq", "daily"));
xlist.Add(home);
// home page
XElement home = new XElement(xn + "url");
home.Add(new XElement(xn + "loc", Request.Url.GetLeftPart(UriPartial.Authority) + "/"));
home.Add(new XElement(xn + "changefreq", "daily"));
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 + "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);
url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd")));
}
xlist.Add(url);
}
XDeclaration decl = new XDeclaration("1.0", "utf-8", "");
XElement root = new XElement(xn + "urlset", xlist);
XDeclaration decl = new XDeclaration("1.0", "utf-8", "");
XElement root = new XElement(xn + "urlset", xlist);
XDocument xdoc = new XDocument(decl, root);
XDocument xdoc = new XDocument(decl, root);
Response.ContentType = "application/xml";
xdoc.Save(Response.OutputStream);
Response.ContentType = "application/xml";
xdoc.Save(Response.OutputStream);
return new EmptyResult();
}
return new EmptyResult();
}
[Route("statistics/")]
[Route("statistics/")]
#if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")]
#endif
public ActionResult stats()
{
var builds = new Build().Select().ToArray();
public async Task<ActionResult> stats()
{
var builds = await bModel.Select();
List<MonthCount> additions = new List<MonthCount>();
var rawAdditions = (from b in builds
where b.Added > DateTime.Now.AddYears(-1)
group b by new
{
Year = b.Added.Year,
Week = Convert.ToInt32(Math.Floor(b.Added.DayOfYear / 7m))
} into bm
select new MonthCount()
{
Month = bm.Key.Week,
Year = bm.Key.Year,
Count = bm.Count()
}).ToArray();
List<MonthCount> additions = new List<MonthCount>();
var rawAdditions = (from b in builds
where b.Added > DateTime.Now.AddYears(-1)
group b by new
{
Year = b.Added.Year,
Week = Convert.ToInt32(Math.Floor(b.Added.DayOfYear / 7m))
} into bm
select new MonthCount()
{
Month = bm.Key.Week,
Year = bm.Key.Year,
Count = bm.Count()
}).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);
additions.Add(new MonthCount()
{
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
});
}
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>();
double logScale = 1.0 / Math.E;
var rawCompiles = from b in builds
where b.BuildTime.HasValue
group b by new
{
Year = b.BuildTime.Value.Year,
Month = Convert.ToInt32(Math.Floor((b.BuildTime.Value.Month - 0.1m) / 3m) * 3) + 1
} into bm
select new MonthCount()
{
Month = bm.Key.Month,
Year = bm.Key.Year,
Count = Math.Pow(Convert.ToDouble(bm.Count()), logScale)
};
List<MonthCount> compiles = new List<MonthCount>();
double logScale = 1.0 / Math.E;
var rawCompiles = from b in builds
where b.BuildTime.HasValue
group b by new
{
Year = b.BuildTime.Value.Year,
Month = Convert.ToInt32(Math.Floor((b.BuildTime.Value.Month - 0.1m) / 3m) * 3) + 1
} into bm
select new MonthCount()
{
Month = bm.Key.Month,
Year = bm.Key.Year,
Count = Math.Pow(Convert.ToDouble(bm.Count()), logScale)
};
var rawLabCounts = from bl in (from b in builds
where !string.IsNullOrEmpty(b.Lab)
group b by b.Lab into bl
select bl)
where bl.Count() > 99
orderby bl.Count() descending
select new Tuple<string, int>(bl.Key, bl.Count());
var rawLabCounts = from bl in (from b in builds
where !string.IsNullOrEmpty(b.Lab)
group b by b.Lab into bl
select bl)
where bl.Count() > 99
orderby bl.Count() descending
select new Tuple<string, int>(bl.Key, bl.Count());
StatsPage m = new StatsPage()
{
AdditionsByMonth = additions,
CompilesByMonth = rawCompiles.OrderBy(r => r.Year).ThenBy(r => r.Month),
BuildsByLab = rawLabCounts
};
StatsPage m = new StatsPage()
{
AdditionsByMonth = additions,
CompilesByMonth = rawCompiles.OrderBy(r => r.Year).ThenBy(r => r.Month),
BuildsByLab = rawLabCounts
};
return View(m);
}
}
return View(m);
}
}
}

View File

@ -69,6 +69,24 @@ namespace BuildFeed.Local {
}
}
/// <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>
/// Looks up a localized string similar to Change your password.
/// </summary>
@ -141,6 +159,15 @@ namespace BuildFeed.Local {
}
}
/// <summary>
/// Looks up a localized string similar to Labs.
/// </summary>
public static string Labs {
get {
return ResourceManager.GetString("Labs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Log in.
/// </summary>
@ -204,6 +231,42 @@ namespace BuildFeed.Local {
}
}
/// <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>
/// Looks up a localized string similar to Thank you for registering.
/// </summary>
@ -221,5 +284,14 @@ namespace BuildFeed.Local {
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">
<value>Every account is validated by an Administrator, so be patient and check again later.</value>
</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">
<value>Change your password</value>
</data>
@ -144,6 +150,9 @@
<data name="HighestVersion" xml:space="preserve">
<value>Highest version</value>
</data>
<data name="Labs" xml:space="preserve">
<value>Labs</value>
</data>
<data name="Login" xml:space="preserve">
<value>Log in</value>
</data>
@ -165,10 +174,25 @@
<data name="RememberMe" xml:space="preserve">
<value>Remember me</value>
</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">
<value>Thank you for registering</value>
</data>
<data name="UserName" xml:space="preserve">
<value>Username</value>
</data>
<data name="Week" xml:space="preserve">
<value>Week</value>
</data>
</root>

View File

@ -10,6 +10,7 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
@ -134,17 +135,35 @@ namespace BuildFeed.Models
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public List<BuildModel> Select()
public async Task<List<BuildModel>> Select()
{
var task = _buildCollection.Find(new BsonDocument()).ToListAsync();
task.Wait();
return task.Result;
return await _buildCollection.Find(new BsonDocument()).ToListAsync();
}
[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)]
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()
{
Major = b.MajorVersion,
@ -163,16 +182,12 @@ namespace BuildFeed.Models
.ThenByDescending(b => b.Key.Build)
.ThenByDescending(b => b.Key.Revision)
.Skip(skip)
.Limit(limit);
var task = pipeline.ToListAsync();
task.Wait();
return task.Result;
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public int SelectBuildGroupsCount()
public async Task<int> SelectBuildGroupsCount()
{
var pipeline = _buildCollection.Aggregate()
.Group(b => new BuildGroup()
@ -184,14 +199,11 @@ namespace BuildFeed.Models
},
bg => new BsonDocument());
var task = pipeline.ToListAsync();
task.Wait();
return task.Result.Count();
return (await pipeline.ToListAsync()).Count;
}
[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()
.Match(b => b.MajorVersion == bGroup.Major)
@ -200,60 +212,78 @@ namespace BuildFeed.Models
.Match(b => b.Revision == bGroup.Revision)
.SortByDescending(b => b.BuildTime);
var task = pipeline.ToListAsync();
task.Wait();
return new Tuple<BuildGroup, IEnumerable<BuildModel>>(bGroup, task.Result);
return new Tuple<BuildGroup, List<BuildModel>>(bGroup, await pipeline.ToListAsync());
}
[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();
task.Wait();
return task.Result;
return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync();
}
[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();
task.Wait();
return task.Result;
return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync();
}
[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)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.ToListAsync();
task.Wait();
return task.Result;
}
[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)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.ThenByDescending(b => b.BuildTime)
.ToListAsync();
task.Wait();
return task.Result;
}
[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)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
@ -262,23 +292,12 @@ namespace BuildFeed.Models
.Skip(skip)
.Limit(limit)
.ToListAsync();
task.Wait();
return task.Result;
}
[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()))
.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)
return await _buildCollection.Find(b => b.Lab != null && (b.Lab.ToLower() == lab.ToLower()))
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
@ -287,23 +306,19 @@ namespace BuildFeed.Models
.Skip(skip)
.Limit(limit)
.ToListAsync();
task.Wait();
return task.Result;
}
[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();
task.Wait();
return task.Result;
}
[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)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
@ -312,23 +327,44 @@ namespace BuildFeed.Models
.Skip(skip)
.Limit(limit)
.ToListAsync();
task.Wait();
return task.Result;
}
[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();
task.Wait();
return task.Result;
}
[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)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
@ -337,23 +373,19 @@ namespace BuildFeed.Models
.Skip(skip)
.Limit(limit)
.ToListAsync();
task.Wait();
return task.Result;
}
[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();
task.Wait();
return task.Result;
}
[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()
{
Major = b.MajorVersion,
@ -365,16 +397,14 @@ namespace BuildFeed.Models
.ThenByDescending(b => b.Item1.Minor)
.ToListAsync();
task.Wait();
// 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)]
public IEnumerable<int> SelectBuildYears()
public async Task<List<int>> SelectBuildYears()
{
var task = _buildCollection.Aggregate()
var result = await _buildCollection.Aggregate()
.Match(b => b.BuildTime != null)
.Group(b => ((DateTime)b.BuildTime).Year,
// incoming bullshit hack
@ -382,16 +412,14 @@ namespace BuildFeed.Models
.SortByDescending(b => b.Item1)
.ToListAsync();
task.Wait();
// 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)]
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 != "")
.Match(b => b.Lab.ToLower().Contains(query.ToLower()))
@ -400,16 +428,14 @@ namespace BuildFeed.Models
bg => new Tuple<string>(bg.Key))
.ToListAsync();
task.Wait();
// 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)]
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 != "")
.Group(b => b.Lab.ToLower(),
@ -418,16 +444,14 @@ namespace BuildFeed.Models
.SortBy(b => b.Item1)
.ToListAsync();
task.Wait();
// 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)]
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.MinorVersion == minor)
.Match(b => b.Lab != null)
@ -438,43 +462,37 @@ namespace BuildFeed.Models
.SortBy(b => b.Item1)
.ToListAsync();
task.Wait();
// 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)]
public void Insert(BuildModel item)
public async Task Insert(BuildModel item)
{
item.Id = Guid.NewGuid();
var task = _buildCollection.InsertOneAsync(item);
task.Wait();
await _buildCollection.InsertOneAsync(item);
}
[DataObjectMethod(DataObjectMethodType.Insert, false)]
public void InsertAll(IEnumerable<BuildModel> items)
public async Task InsertAll(IEnumerable<BuildModel> items)
{
var task = _buildCollection.InsertManyAsync(items);
task.Wait();
await _buildCollection.InsertManyAsync(items);
}
[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.Modified = DateTime.Now;
var task = _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item);
task.Wait();
await _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item);
}
[DataObjectMethod(DataObjectMethodType.Delete, true)]
public void DeleteById(Guid id)
public async Task DeleteById(Guid id)
{
var task = _buildCollection.DeleteOneAsync(f => f.Id == id);
task.Wait();
await _buildCollection.DeleteOneAsync(f => f.Id == id);
}
}

View File

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

View File

@ -13,7 +13,7 @@
}
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 property="og:description" content="@metaDesc" />
}

View File

@ -1,142 +1,142 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<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/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 rel="shortcut icon" href="~/favicon.ico" />
<link rel="icon" href="~/favicon.ico" />
<link rel="canonical" href="@Url.Action()" />
<meta name="application-name" content="@BuildFeed.Local.Common.SiteName" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<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/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 rel="shortcut icon" href="~/favicon.ico" />
<link rel="icon" href="~/favicon.ico" />
<link rel="canonical" href="@Url.Action()" />
<meta name="application-name" content="@BuildFeed.Local.Common.SiteName" />
@Styles.Render("~/content/css")
<title>@ViewBag.Title</title>
@RenderSection("head", false)
<script type="text/javascript">
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
}({
instrumentationKey: "4632419f-7a2f-4ab5-8374-34384b650f42"
});
@Styles.Render("~/content/css")
<title>@ViewBag.Title</title>
@RenderSection("head", false)
<script type="text/javascript">
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
}({
instrumentationKey: "4632419f-7a2f-4ab5-8374-34384b650f42"
});
window.appInsights = appInsights;
appInsights.trackPageView();
</script>
window.appInsights = appInsights;
appInsights.trackPageView();
</script>
</head>
<body>
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, 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)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, 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)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-55417692-1', 'auto');
ga('require', 'displayfeatures');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
</script>
<div class="container">
<header id="page-header"></header>
<nav id="page-navigation" role="navigation">
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<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="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink(BuildFeed.Local.Common.SiteName, "index", new { controller = "front", area = "" }, new { @class = "navbar-brand" })
</div>
<div class="collapse navbar-collapse" id="page-navigation-collapse">
<ul class="nav navbar-nav navbar-right">
@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>
}
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("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>
}
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("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="@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="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>
</div>
</div>
ga('create', 'UA-55417692-1', 'auto');
ga('require', 'displayfeatures');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
</script>
<div class="container">
<header id="page-header"></header>
<nav id="page-navigation" role="navigation">
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<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="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink(BuildFeed.Local.Common.SiteName, "index", new { controller = "front", area = "" }, new { @class = "navbar-brand" })
</div>
<div class="collapse navbar-collapse" id="page-navigation-collapse">
<ul class="nav navbar-nav navbar-right">
@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>
}
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("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>
}
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("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="@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="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>
</div>
</div>
</nav>
<article id="page-content">
<div class="row">
<div class="col-sm-12">
@RenderBody()
</div>
</div>
</nav>
<article id="page-content">
<div class="row">
<div class="col-sm-12">
@RenderBody()
</div>
</article>
<footer id="page-footer">
<div class="row">
<div class="col-sm-8">
<p>
<a href="@Url.Action("sitemap", new { controller = "support" })">@BuildFeed.Local.Common.Sitemap</a>
</p>
</div>
<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>
</article>
<footer id="page-footer">
<div class="row">
<div class="col-sm-8">
<p>
<a href="@Url.Action("sitemap", new { controller = "support" })">@BuildFeed.Local.Common.Sitemap</a>
</p>
</div>
</footer>
</div>
<div class="modal fade" id="search-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<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 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>
@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>
</div>
</footer>
</div>
<div class="modal fade" id="search-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<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>
@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>
</html>

View File

@ -1,6 +1,6 @@
@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>

View File

@ -6,14 +6,14 @@
<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>
<h4>Builds compiled each quarter</h4>
<h4>@BuildFeed.Local.Support.StatsCompiled</h4>
<canvas id="stats-compiled" width="960" height="320"></canvas>
<h4>Recorded builds in each lab</h4>
<p>Only labs with 100 or more recorded builds are included.</p>
<h4>@BuildFeed.Local.Support.StatsLab</h4>
<p>@BuildFeed.Local.Support.StatsLabIncluded</p>
<canvas id="stats-labs" width="960" height="320"></canvas>
@section scripts
@ -29,10 +29,10 @@
Chart.defaults.Line.scaleShowGridLines = false;
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: [
{
label: "Additions to BuildFeed",
label: "@BuildFeed.Local.Support.AdditionsToBuildFeed",
fillColor: "#008cba",
strokeColor: "#00526e",
pointColor: "#00526e",
@ -46,10 +46,10 @@
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: [
{
label: "Builds compiled",
label: "@BuildFeed.Local.Support.BuildsCompiled",
fillColor: "#008cba",
strokeColor: "#00526e",
pointColor: "#00526e",
@ -65,7 +65,7 @@
labels: [ @Html.Raw(string.Join(", ", Model.BuildsByLab.Select(l => string.Format("\"{0}\"", l.Item1))))],
datasets: [
{
label: "Labs",
label: "@BuildFeed.Local.Support.Labs",
fillColor: "#008cba",
strokeColor: "#00526e",
pointColor: "#00526e",