Add Family Pages

Swapped out version listing for project family listing on home page
refactor-intermediate-models
BuildFeed Bot 2018-02-05 22:24:29 +00:00
parent d51cbd21f9
commit b5a3e016ee
8 changed files with 428 additions and 185 deletions

View File

@ -11,13 +11,30 @@ namespace BuildFeed.Model
{
public partial class BuildRepository
{
public Task<ProjectFamily[]> SelectAllFamilies(int limit = -1, int skip = 0) => Task.Run(() => Enum.GetValues(typeof(ProjectFamily)) as ProjectFamily[]);
public Task<ProjectFamily[]> SelectAllFamilies(int limit = -1, int skip = 0) => Task.Run(() =>
{
Array values = Enum.GetValues(typeof(ProjectFamily));
if (values.Length == 0)
{
return Array.Empty<ProjectFamily>();
}
var valuesWithoutNone = new ProjectFamily[values.Length - 1];
for (int i = 0, j = values.Length - 1; j > 0; j--, i++)
{
valuesWithoutNone[i] = (ProjectFamily)values.GetValue(j);
}
return valuesWithoutNone;
});
public Task<long> SelectAllFamiliesCount() => Task.Run(() => Enum.GetValues(typeof(ProjectFamily)).LongLength);
public async Task<List<Build>> SelectFamily(ProjectFamily family, int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument(nameof(Build.Family), family)).Sort(sortByOrder).Skip(skip);
var query = _buildCollection.Find(new BsonDocument(nameof(Build.Family), family))
.Sort(sortByOrder)
.Skip(skip);
if (limit > 0)
{
@ -27,11 +44,12 @@ namespace BuildFeed.Model
return await query.ToListAsync();
}
public async Task<long> SelectFamilyCount(ProjectFamily family) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.Family), family));
public async Task<long> SelectFamilyCount(ProjectFamily family)
=> await _buildCollection.CountAsync(new BsonDocument(nameof(Build.Family), family));
public async Task<List<FamilyOverview>> SelectFamilyOverviews()
{
IAggregateFluent<BsonDocument> families = _buildCollection.Aggregate()
var families = _buildCollection.Aggregate()
.Sort(sortByOrder)
.Group(new BsonDocument
{
@ -41,10 +59,10 @@ namespace BuildFeed.Model
})
.Sort(new BsonDocument("_id", -1));
List<BsonDocument> result = await families.ToListAsync();
var result = await families.ToListAsync();
return (from o in result
select BsonSerializer.Deserialize<FamilyOverview>(o)).ToList();
select BsonSerializer.Deserialize<FamilyOverview>(o)).ToList();
}
}
}

View File

@ -37,7 +37,7 @@ namespace BuildFeed.Model
public MetaItem()
{
MongoClientSettings settings = new MongoClientSettings
var settings = new MongoClientSettings
{
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
};
@ -48,17 +48,16 @@ namespace BuildFeed.Model
MongoCredential.CreateCredential(MongoConfig.Database, MongoConfig.Username, MongoConfig.Password);
}
MongoClient dbClient = new MongoClient(settings);
var dbClient = new MongoClient(settings);
_metaCollection = dbClient.GetDatabase(MongoConfig.Database).GetCollection<MetaItemModel>(META_COLLECTION_NAME);
_metaCollection = dbClient.GetDatabase(MongoConfig.Database)
.GetCollection<MetaItemModel>(META_COLLECTION_NAME);
_bModel = new BuildRepository();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<MetaItemModel>> Select()
{
return await _metaCollection.Find(new BsonDocument()).ToListAsync();
}
=> await _metaCollection.Find(new BsonDocument()).ToListAsync();
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<IEnumerable<MetaItemModel>> SelectByType(MetaType type)
@ -69,43 +68,56 @@ namespace BuildFeed.Model
[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();
return await _metaCollection.Find(f => f.Id.Type == id.Type && f.Id.Value == id.Value)
.SingleOrDefaultAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedLabs()
{
string[] labs = await _bModel.SelectAllLabs();
var labs = await _bModel.SelectAllLabs();
List<MetaItemModel> usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync();
var usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync();
return from l in labs
where usedLabs.All(ul => ul.Id.Value != l)
select l;
where usedLabs.All(ul => ul.Id.Value != l)
select l;
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedVersions()
{
BuildVersion[] versions = await _bModel.SelectAllVersions();
var versions = await _bModel.SelectAllVersions();
List<MetaItemModel> usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync();
var usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync();
return from v in versions
where usedVersions.All(ul => ul.Id.Value != v.ToString())
select v.ToString();
where usedVersions.All(ul => ul.Id.Value != v.ToString())
select v.ToString();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedYears()
{
int[] years = await _bModel.SelectAllYears();
var years = await _bModel.SelectAllYears();
List<MetaItemModel> usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync();
var usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync();
return from y in years
where usedYears.All(ul => ul.Id.Value != y.ToString())
select y.ToString();
where usedYears.All(ul => ul.Id.Value != y.ToString())
select y.ToString();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedFamilies()
{
var families = await _bModel.SelectAllFamilies();
var usedFamilies = await _metaCollection.Find(f => f.Id.Type == MetaType.Family).ToListAsync();
return from y in families
where usedFamilies.All(ul => ul.Id.Value != y.ToString())
select y.ToString();
}
[DataObjectMethod(DataObjectMethodType.Insert, true)]
@ -144,15 +156,12 @@ namespace BuildFeed.Model
public MetaItemKey(string id)
{
string[] items = id.Split(':');
var items = id.Split(':');
Type = (MetaType)Enum.Parse(typeof(MetaType), items[0]);
Value = items[1];
}
public override string ToString()
{
return $"{Type}:{Value}";
}
public override string ToString() => $"{Type}:{Value}";
}
public enum MetaType
@ -160,6 +169,7 @@ namespace BuildFeed.Model
Lab,
Version,
Source,
Year
Year,
Family
}
}

View File

@ -20,60 +20,64 @@ namespace BuildFeed.Admin.Controllers
}
[Route("")]
public async Task<ActionResult> Index()
public async Task<ActionResult> Index() => View(new MetaListing
{
return View(new MetaListing
{
CurrentItems = from i in await _mModel.Select()
group i by i.Id.Type
into b
orderby b.Key.ToString()
select b,
CurrentItems = from i in await _mModel.Select()
group i by i.Id.Type
into b
orderby b.Key.ToString()
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
});
}
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
}
})
.Concat(from y in await _mModel.SelectUnusedFamilies()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Family,
Value = y
}
})
group i by i.Id.Type
into b
orderby b.Key.ToString()
select b
});
[Route("create/{type}/{value}")]
public ActionResult Create(MetaType type, string value)
public ActionResult Create(MetaType type, string value) => View(new MetaItemModel
{
return View(new MetaItemModel
Id = new MetaItemKey
{
Id = new MetaItemKey
{
Type = type,
Value = value
}
});
}
Type = type,
Value = value
}
});
[HttpPost]
[ValidateAntiForgeryToken]
@ -90,15 +94,12 @@ namespace BuildFeed.Admin.Controllers
}
[Route("edit/{type}/{value}")]
public async Task<ActionResult> Edit(MetaType type, string value)
{
return View(nameof(Create),
await _mModel.SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
}
public async Task<ActionResult> Edit(MetaType type, string value) => View(nameof(Create),
await _mModel.SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
[HttpPost]
[ValidateAntiForgeryToken]

View File

@ -484,6 +484,7 @@
<Content Include="Views\account\validate-success.cshtml" />
<Content Include="Views\account\validate-failure.cshtml" />
<None Include="tsconfig.json" />
<Content Include="Views\front\ViewFamily.cshtml" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@ -69,6 +69,24 @@ namespace BuildFeed.Code
return result ?? o.ToString();
}
public static string GetDisplayDescriptionForEnum(object o)
{
string result = null;
DisplayAttribute display = o.GetType()
.GetMember(o.ToString())
.First()
.GetCustomAttributes(false)
.OfType<DisplayAttribute>()
.LastOrDefault();
if (display != null)
{
result = display.GetDescription() ?? display.GetName();
}
return result ?? o.ToString();
}
public static string ToLongDateWithoutDay(this DateTime dt)
{
string s = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern;

View File

@ -32,31 +32,32 @@ namespace BuildFeed.Controllers
}
[Route("", Order = 1)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> Index()
{
ViewBag.Versions = await _bModel.SelectAllVersions();
ViewBag.Versions = await _bModel.SelectAllFamilies();
ViewBag.Years = await _bModel.SelectAllYears();
ViewBag.Sources = await _bModel.SelectAllSources();
Dictionary<ProjectFamily, FrontPage> items = await _bModel.SelectFrontPage();
var items = await _bModel.SelectFrontPage();
return View(nameof(Index), items);
}
[Route("page-{page:int:min(1)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> IndexPage(int page)
{
FrontBuildGroup[] buildGroups = await _bModel.SelectAllGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE);
var buildGroups = await _bModel.SelectAllGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await _bModel.SelectAllGroupsCount()) / Convert.ToDouble(PAGE_SIZE));
ViewBag.PageCount =
Math.Ceiling(Convert.ToDouble(await _bModel.SelectAllGroupsCount()) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount)
{
@ -69,13 +70,13 @@ namespace BuildFeed.Controllers
[Route("group/{major}.{minor}.{number}.{revision}/", Order = 1)]
[Route("group/{major}.{minor}.{number}/", Order = 5)]
// for when there is no revision
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewGroup(uint major, uint minor, uint number, uint? revision = null)
{
BuildGroup bg = new BuildGroup
var bg = new BuildGroup
{
Major = major,
Minor = minor,
@ -83,7 +84,7 @@ namespace BuildFeed.Controllers
Revision = revision
};
List<Build> builds = await _bModel.SelectGroup(bg);
var builds = await _bModel.SelectGroup(bg);
return builds.Count == 1
? RedirectToAction(nameof(ViewBuild),
@ -95,10 +96,10 @@ namespace BuildFeed.Controllers
}
[Route("build/{id:guid}/", Name = "Build")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewBuild(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -127,10 +128,10 @@ namespace BuildFeed.Controllers
}
[Route("twitter/{id:guid}/", Name = "Twitter")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[CustomContentType(ContentType = "image/png", Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[CustomContentType(ContentType = "image/png", Order = 2)]
#endif
public async Task<ActionResult> TwitterCard(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -161,11 +162,16 @@ namespace BuildFeed.Controllers
}
int left = 40;
using (GraphicsPath gp = new GraphicsPath())
using (var gp = new GraphicsPath())
{
foreach (char c in "BUILDFEED")
{
gp.AddString(c.ToString(), new FontFamily("Segoe UI Semibold"), 0, 32, new Point(left, 32), StringFormat.GenericTypographic);
gp.AddString(c.ToString(),
new FontFamily("Segoe UI Semibold"),
0,
32,
new Point(left, 32),
StringFormat.GenericTypographic);
RectangleF bounds = gp.GetBounds();
left = Convert.ToInt32(bounds.Width);
@ -175,9 +181,14 @@ namespace BuildFeed.Controllers
gr.FillPath(Brushes.White, gp);
}
using (GraphicsPath gp = new GraphicsPath())
using (var gp = new GraphicsPath())
{
gp.AddString(b.Number.ToString(), new FontFamily("Segoe UI Light"), 0, 260, new Point(32, 114), StringFormat.GenericTypographic);
gp.AddString(b.Number.ToString(),
new FontFamily("Segoe UI Light"),
0,
260,
new Point(32, 114),
StringFormat.GenericTypographic);
RectangleF bounds = gp.GetBounds();
left = Convert.ToInt32(bounds.Width);
@ -185,24 +196,56 @@ namespace BuildFeed.Controllers
if (b.Revision.HasValue)
{
gp.AddString($".{b.Revision}", new FontFamily("Segoe UI Light"), 0, 160, new Point(left, 220), StringFormat.GenericTypographic);
gp.AddString($".{b.Revision}",
new FontFamily("Segoe UI Light"),
0,
160,
new Point(left, 220),
StringFormat.GenericTypographic);
}
gr.DrawPath(new Pen(new SolidBrush(Color.FromArgb(0x24, 0x24, 0x23)), 4), gp);
gr.FillPath(Brushes.White, gp);
}
using (GraphicsPath gp = new GraphicsPath())
using (var gp = new GraphicsPath())
{
gp.AddString($"{MvcExtensions.GetDisplayTextForEnum(b.Family)} (NT {b.MajorVersion}.{b.MinorVersion})", new FontFamily("Segoe UI Light"), 0, 48, new Point(40, 80), StringFormat.GenericTypographic);
gp.AddString(
$"{MvcExtensions.GetDisplayTextForEnum(b.Family)} (NT {b.MajorVersion}.{b.MinorVersion})",
new FontFamily("Segoe UI Light"),
0,
48,
new Point(40, 80),
StringFormat.GenericTypographic);
gp.AddString(char.ConvertFromUtf32(0xf126), new FontFamily("FontAwesome"), 0, 28, new Point(46, 468), StringFormat.GenericTypographic);
gp.AddString(b.Lab, new FontFamily("Segoe UI Light"), 0, 40, new Point(88, 450), StringFormat.GenericTypographic);
gp.AddString(char.ConvertFromUtf32(0xf126),
new FontFamily("FontAwesome"),
0,
28,
new Point(46, 468),
StringFormat.GenericTypographic);
gp.AddString(b.Lab,
new FontFamily("Segoe UI Light"),
0,
40,
new Point(88, 450),
StringFormat.GenericTypographic);
if (b.BuildTime.HasValue)
{
gp.AddString(char.ConvertFromUtf32(0xf017), new FontFamily("FontAwesome"), 0, 28, new Point(40, 538), StringFormat.GenericTypographic);
gp.AddString($"{b.BuildTime.Value.ToShortTimeString()} on {b.BuildTime.Value.ToLongDateString()}", new FontFamily("Segoe UI Light"), 0, 40, new Point(88, 520), StringFormat.GenericTypographic);
gp.AddString(char.ConvertFromUtf32(0xf017),
new FontFamily("FontAwesome"),
0,
28,
new Point(40, 538),
StringFormat.GenericTypographic);
gp.AddString(
$"{b.BuildTime.Value.ToShortTimeString()} on {b.BuildTime.Value.ToLongDateString()}",
new FontFamily("Segoe UI Light"),
0,
40,
new Point(88, 520),
StringFormat.GenericTypographic);
}
gr.FillPath(Brushes.White, gp);
@ -232,21 +275,59 @@ namespace BuildFeed.Controllers
});
}
[Route("family/{family}/", Order = 1, Name = "Family Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewFamily(ProjectFamily family)
{
return await ViewFamilyPage(family, 1);
}
[Route("family/{family}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewFamilyPage(ProjectFamily family, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
{
Type = MetaType.Family,
Value = family.ToString()
});
ViewBag.ItemId = MvcExtensions.GetDisplayDescriptionForEnum(family);
var builds = await _bModel.SelectFamily(family, PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page;
ViewBag.PageCount =
Math.Ceiling(Convert.ToDouble(await _bModel.SelectFamilyCount(family)) / Convert.ToDouble(PAGE_SIZE));
if (ViewBag.PageNumber > ViewBag.PageCount)
{
return new HttpNotFoundResult();
}
return View("viewFamily", builds);
}
[Route("lab/{lab}/", Order = 1, Name = "Lab Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewLab(string lab)
{
return await ViewLabPage(lab, 1);
}
[Route("lab/{lab}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewLabPage(string lab, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -255,11 +336,12 @@ namespace BuildFeed.Controllers
Value = lab
});
List<Build> builds = await _bModel.SelectLab(lab, PAGE_SIZE, (page - 1) * PAGE_SIZE);
var builds = await _bModel.SelectLab(lab, PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.ItemId = builds.FirstOrDefault()?.Lab;
ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await _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)
{
@ -270,20 +352,20 @@ namespace BuildFeed.Controllers
}
[Route("source/{source}/", Order = 1, Name = "Source Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewSource(TypeOfSource source)
{
return await ViewSourcePage(source, 1);
}
[Route("source/{source}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewSourcePage(TypeOfSource source, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -293,10 +375,11 @@ namespace BuildFeed.Controllers
});
ViewBag.ItemId = MvcExtensions.GetDisplayTextForEnum(source);
List<Build> builds = await _bModel.SelectSource(source, PAGE_SIZE, (page - 1) * PAGE_SIZE);
var builds = await _bModel.SelectSource(source, PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await _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)
{
@ -307,20 +390,20 @@ namespace BuildFeed.Controllers
}
[Route("year/{year}/", Order = 1, Name = "Year Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewYear(int year)
{
return await ViewYearPage(year, 1);
}
[Route("year/{year}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewYearPage(int year, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -330,7 +413,7 @@ namespace BuildFeed.Controllers
});
ViewBag.ItemId = year.ToString();
List<Build> builds = await _bModel.SelectYear(year, PAGE_SIZE, (page - 1) * PAGE_SIZE);
var builds = await _bModel.SelectYear(year, PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(await _bModel.SelectYearCount(year) / Convert.ToDouble(PAGE_SIZE));
@ -344,20 +427,20 @@ namespace BuildFeed.Controllers
}
[Route("version/{major}.{minor}/", Order = 1, Name = "Version Root")]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewVersion(uint major, uint minor)
{
return await ViewVersionPage(major, minor, 1);
}
[Route("version/{major}.{minor}/page-{page:int:min(2)}/", Order = 0)]
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
public async Task<ActionResult> ViewVersionPage(uint major, uint minor, int page)
{
string valueString = $"{major}.{minor}";
@ -368,10 +451,11 @@ namespace BuildFeed.Controllers
});
ViewBag.ItemId = valueString;
List<Build> builds = await _bModel.SelectVersion(major, minor, PAGE_SIZE, (page - 1) * PAGE_SIZE);
var builds = await _bModel.SelectVersion(major, minor, PAGE_SIZE, (page - 1) * PAGE_SIZE);
ViewBag.PageNumber = page;
ViewBag.PageCount = Math.Ceiling(Convert.ToDouble(await _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)
{
@ -385,7 +469,7 @@ namespace BuildFeed.Controllers
[Authorize(Roles = "Administrators,Editors")]
public ActionResult AddBuild()
{
Build b = new Build
var b = new Build
{
SourceType = TypeOfSource.PrivateLeak
};
@ -417,7 +501,7 @@ namespace BuildFeed.Controllers
build.RegenerateCachedProperties();
BuildDetails bi = new BuildDetails
var bi = new BuildDetails
{
MajorVersion = build.MajorVersion,
MinorVersion = build.MinorVersion,
@ -449,8 +533,9 @@ namespace BuildFeed.Controllers
return View("EditBuild", build);
}
OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
osc.PushNewBuild(build, $"https://buildfeed.net{Url.Action(nameof(ViewBuild), new { id = build.Id })}?utm_source=notification&utm_campaign=new_build");
var osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
osc.PushNewBuild(build,
$"https://buildfeed.net{Url.Action(nameof(ViewBuild), new { id = build.Id })}?utm_source=notification&utm_campaign=new_build");
return RedirectToAction(nameof(ViewBuild),
new
@ -458,15 +543,13 @@ namespace BuildFeed.Controllers
id = build.Id
});
}
return View("EditBuild", build);
}
[Route("bulk/")]
[Authorize(Roles = "Administrators")]
public ActionResult AddBulk()
{
return View();
}
public ActionResult AddBulk() => View();
[Route("bulk/")]
[ValidateAntiForgeryToken]
@ -474,7 +557,7 @@ namespace BuildFeed.Controllers
[HttpPost]
public async Task<ActionResult> AddBulk(FormCollection values)
{
OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
var osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
var success = new List<Build>();
var failed = new List<string>();
bool notify = bool.Parse(values[nameof(BulkAddition.SendNotifications)].Split(',')[0]);
@ -487,12 +570,13 @@ namespace BuildFeed.Controllers
},
StringSplitOptions.RemoveEmptyEntries))
{
Match m = Regex.Match(line, @"(([\d]{1,2})\.([\d]{1,2})\.)?([\d]{4,5})(\.([\d]{1,5}))?(\.| \()([a-zA-Z][a-zA-Z0-9._\(\)-]+?)\.(\d\d\d\d\d\d-\d\d\d\d)\)?");
Match m = Regex.Match(line,
@"(([\d]{1,2})\.([\d]{1,2})\.)?([\d]{4,5})(\.([\d]{1,5}))?(\.| \()([a-zA-Z][a-zA-Z0-9._\(\)-]+?)\.(\d\d\d\d\d\d-\d\d\d\d)\)?");
if (m.Success)
{
try
{
Build b = new Build
var b = new Build
{
MajorVersion = uint.Parse(m.Groups[2].Value),
MinorVersion = uint.Parse(m.Groups[3].Value),
@ -503,14 +587,17 @@ namespace BuildFeed.Controllers
Lab = m.Groups[8].Value,
BuildTime = string.IsNullOrEmpty(m.Groups[9].Value)
? null
: DateTime.SpecifyKind(DateTime.ParseExact(m.Groups[9].Value, "yyMMdd-HHmm", CultureInfo.CurrentCulture.DateTimeFormat), DateTimeKind.Utc) as DateTime?,
: DateTime.SpecifyKind(DateTime.ParseExact(m.Groups[9].Value,
"yyMMdd-HHmm",
CultureInfo.CurrentCulture.DateTimeFormat),
DateTimeKind.Utc) as DateTime?,
Added = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc),
Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc),
SourceType = TypeOfSource.PrivateLeak
};
b.RegenerateCachedProperties();
BuildDetails bi = new BuildDetails
var bi = new BuildDetails
{
MajorVersion = b.MajorVersion,
MinorVersion = b.MinorVersion,
@ -544,7 +631,8 @@ namespace BuildFeed.Controllers
if (notify)
{
osc.PushNewBuild(b, $"https://buildfeed.net{Url.Action(nameof(ViewBuild), new { id = b.Id })}?utm_source=notification&utm_campaign=new_build");
osc.PushNewBuild(b,
$"https://buildfeed.net{Url.Action(nameof(ViewBuild), new { id = b.Id })}?utm_source=notification&utm_campaign=new_build");
}
success.Add(b);
@ -599,7 +687,7 @@ namespace BuildFeed.Controllers
build.LeakDate = DateTime.SpecifyKind(build.LeakDate.Value, DateTimeKind.Utc);
}
BuildDetails bi = new BuildDetails
var bi = new BuildDetails
{
MajorVersion = build.MajorVersion,
MinorVersion = build.MinorVersion,
@ -640,6 +728,7 @@ namespace BuildFeed.Controllers
id = build.Id
});
}
return View(build);
}

View File

@ -0,0 +1,107 @@
@using BuildFeed.Code
@using BuildFeed.Controllers
@using BuildFeed.Model
@using Humanizer
@model IEnumerable<Build>
@{
ViewBag.Title = string.Format("{0} {1} | {2}", ViewBag.ItemId, ViewBag.PageNumber == 1
? ""
: string.Format(VariantTerms.Common_TitlePage, ViewBag.PageNumber), InvariantTerms.SiteName);
}
@section head
{
@if (ViewBag.MetaItem != null)
{
<meta name="description" content="@ViewBag.MetaItem.MetaDescription" />
<meta property="og:description" content="@ViewBag.MetaItem.MetaDescription" />
}
@if (ViewBag.PageNumber != 1)
{
<meta name="robots" content="noindex, follow" />
}
}
<h1>@ViewBag.ItemId</h1>
@if (ViewBag.MetaItem != null && !string.IsNullOrWhiteSpace(ViewBag.MetaItem.PageContent))
{
<h3>@VariantTerms.Front_About</h3>
@Html.Raw(ViewBag.MetaItem.PageContent)
}
<h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div>
<br />
<h3>@VariantTerms.Front_Listing</h3>
<div class="build-group-listing">
@foreach (Build build in Model)
{
<div class="build-group">
<h3 class="build-group-title" title="@build.AlternateBuildString">
<a href="@Url.Action("ViewBuild", new
{
id = build.Id
})">
@($"{build.MajorVersion}.{build.MinorVersion}.{build.Number}.{build.Revision}")
</a>
</h3>
@if (!string.IsNullOrEmpty(build.Lab))
{
<p class="no-wrapping build-group-p" title="@build.Lab">
<i class="fa fa-code-fork fa-fw"></i> @build.Lab</p>
}
@if (build.BuildTime.HasValue)
{
<p class="build-group-p">
<span title="@build.BuildTime.Value.Humanize()">
<i class="fa fa-calendar fa-fw"></i> @build.BuildTime.Value.ToLongDateWithoutDay()</span>
</p>
<p class="build-group-p">
<span title="@build.BuildTime.Value.Humanize()">
<i class="fa fa-clock-o fa-fw"></i> @build.BuildTime.Value.ToShortTimeString()</span>
</p>
}
@if (build.IsLeaked)
{
<p class="build-group-p">
<span>
<i class="fa fa-unlock-alt fa-fw"></i> @VariantTerms.Front_Public</span>
</p>
}
else
{
<p class="build-group-p">
<span>
<i class="fa fa-lock fa-fw"></i> @VariantTerms.Front_Private</span>
</p>
}
@if (Roles.IsUserInRole("Editors") || Roles.IsUserInRole("Administrators"))
{
<p>
<a href="@Url.Action(nameof(FrontController.EditBuild), new
{
id = build.Id
})" class="button edit-button">
@VariantTerms.Front_Edit
</a>
&nbsp;
@if (Roles.IsUserInRole("Administrators"))
{
<a href="@Url.Action(nameof(FrontController.DeleteBuild), new
{
id = build.Id
})" class="button delete-button">
@VariantTerms.Front_Delete
</a>
}
</p>
}
</div>
}
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
</div>
@PaginationHelpers.PaginationBlock((int)ViewBag.PageNumber, (int)ViewBag.PageCount, "ViewFamily", ViewContext.RouteData.Values)

View File

@ -102,15 +102,14 @@
<div class="group-input-button">
<select id="search-version">
@{
BuildVersion[] versions = ViewBag.Versions;
foreach (BuildVersion version in versions)
ProjectFamily[] versions = ViewBag.Versions;
foreach (ProjectFamily version in versions)
{
<option value="@Url.Action(nameof(FrontController.ViewVersion), "Front", new
<option value="@Url.Action(nameof(FrontController.ViewFamily), "Front", new
{
major = version.Major,
minor = version.Minor
family = version
})">
@version.ToString()
@MvcExtensions.GetDisplayDescriptionForEnum(version)
</option>
}
}