diff --git a/BuildFeed.Model/BuildRepository-Family.cs b/BuildFeed.Model/BuildRepository-Family.cs index b2bbf76..4fbce87 100644 --- a/BuildFeed.Model/BuildRepository-Family.cs +++ b/BuildFeed.Model/BuildRepository-Family.cs @@ -11,13 +11,30 @@ namespace BuildFeed.Model { public partial class BuildRepository { - public Task SelectAllFamilies(int limit = -1, int skip = 0) => Task.Run(() => Enum.GetValues(typeof(ProjectFamily)) as ProjectFamily[]); + public Task SelectAllFamilies(int limit = -1, int skip = 0) => Task.Run(() => + { + Array values = Enum.GetValues(typeof(ProjectFamily)); + if (values.Length == 0) + { + return Array.Empty(); + } + + 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 SelectAllFamiliesCount() => Task.Run(() => Enum.GetValues(typeof(ProjectFamily)).LongLength); public async Task> SelectFamily(ProjectFamily family, int limit = -1, int skip = 0) { - IFindFluent 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 SelectFamilyCount(ProjectFamily family) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.Family), family)); + public async Task SelectFamilyCount(ProjectFamily family) + => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.Family), family)); public async Task> SelectFamilyOverviews() { - IAggregateFluent 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 result = await families.ToListAsync(); + var result = await families.ToListAsync(); return (from o in result - select BsonSerializer.Deserialize(o)).ToList(); + select BsonSerializer.Deserialize(o)).ToList(); } } } \ No newline at end of file diff --git a/BuildFeed.Model/MetaItem.cs b/BuildFeed.Model/MetaItem.cs index ecb6184..b973e3b 100644 --- a/BuildFeed.Model/MetaItem.cs +++ b/BuildFeed.Model/MetaItem.cs @@ -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(META_COLLECTION_NAME); + _metaCollection = dbClient.GetDatabase(MongoConfig.Database) + .GetCollection(META_COLLECTION_NAME); _bModel = new BuildRepository(); } [DataObjectMethod(DataObjectMethodType.Select, false)] public async Task> Select() - { - return await _metaCollection.Find(new BsonDocument()).ToListAsync(); - } + => await _metaCollection.Find(new BsonDocument()).ToListAsync(); [DataObjectMethod(DataObjectMethodType.Select, true)] public async Task> SelectByType(MetaType type) @@ -69,43 +68,56 @@ namespace BuildFeed.Model [DataObjectMethod(DataObjectMethodType.Select, false)] public async Task 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> SelectUnusedLabs() { - string[] labs = await _bModel.SelectAllLabs(); + var labs = await _bModel.SelectAllLabs(); - List 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> SelectUnusedVersions() { - BuildVersion[] versions = await _bModel.SelectAllVersions(); + var versions = await _bModel.SelectAllVersions(); - List 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> SelectUnusedYears() { - int[] years = await _bModel.SelectAllYears(); + var years = await _bModel.SelectAllYears(); - List 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> 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 } } \ No newline at end of file diff --git a/BuildFeed/Areas/admin/Controllers/metaController.cs b/BuildFeed/Areas/admin/Controllers/metaController.cs index 16626ec..341e3ec 100644 --- a/BuildFeed/Areas/admin/Controllers/metaController.cs +++ b/BuildFeed/Areas/admin/Controllers/metaController.cs @@ -20,60 +20,64 @@ namespace BuildFeed.Admin.Controllers } [Route("")] - public async Task Index() + public async Task 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 Edit(MetaType type, string value) - { - return View(nameof(Create), - await _mModel.SelectById(new MetaItemKey - { - Type = type, - Value = value - })); - } + public async Task Edit(MetaType type, string value) => View(nameof(Create), + await _mModel.SelectById(new MetaItemKey + { + Type = type, + Value = value + })); [HttpPost] [ValidateAntiForgeryToken] diff --git a/BuildFeed/BuildFeed.csproj b/BuildFeed/BuildFeed.csproj index 15b5fcf..34d2ef9 100644 --- a/BuildFeed/BuildFeed.csproj +++ b/BuildFeed/BuildFeed.csproj @@ -484,6 +484,7 @@ + diff --git a/BuildFeed/Code/DisplayHelpers.cs b/BuildFeed/Code/DisplayHelpers.cs index c66196b..6eff8f1 100644 --- a/BuildFeed/Code/DisplayHelpers.cs +++ b/BuildFeed/Code/DisplayHelpers.cs @@ -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() + .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; diff --git a/BuildFeed/Controllers/frontController.cs b/BuildFeed/Controllers/frontController.cs index c878a84..3ddfa09 100644 --- a/BuildFeed/Controllers/frontController.cs +++ b/BuildFeed/Controllers/frontController.cs @@ -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 Index() { - ViewBag.Versions = await _bModel.SelectAllVersions(); + ViewBag.Versions = await _bModel.SelectAllFamilies(); ViewBag.Years = await _bModel.SelectAllYears(); ViewBag.Sources = await _bModel.SelectAllSources(); - Dictionary 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 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 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 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 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 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 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 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 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 ViewLabPage(string lab, int page) { ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey @@ -255,11 +336,12 @@ namespace BuildFeed.Controllers Value = lab }); - List 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 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 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 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 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 ViewYearPage(int year, int page) { ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey @@ -330,7 +413,7 @@ namespace BuildFeed.Controllers }); ViewBag.ItemId = year.ToString(); - List 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 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 ViewVersionPage(uint major, uint minor, int page) { string valueString = $"{major}.{minor}"; @@ -368,10 +451,11 @@ namespace BuildFeed.Controllers }); ViewBag.ItemId = valueString; - List 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 AddBulk(FormCollection values) { - OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]); + var osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]); var success = new List(); var failed = new List(); 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); } diff --git a/BuildFeed/Views/front/ViewFamily.cshtml b/BuildFeed/Views/front/ViewFamily.cshtml new file mode 100644 index 0000000..3f58e95 --- /dev/null +++ b/BuildFeed/Views/front/ViewFamily.cshtml @@ -0,0 +1,107 @@ +@using BuildFeed.Code +@using BuildFeed.Controllers +@using BuildFeed.Model +@using Humanizer +@model IEnumerable +@{ + 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) + { + + + } + + @if (ViewBag.PageNumber != 1) + { + + } +} + +

@ViewBag.ItemId

+@if (ViewBag.MetaItem != null && !string.IsNullOrWhiteSpace(ViewBag.MetaItem.PageContent)) +{ +

@VariantTerms.Front_About

+ @Html.Raw(ViewBag.MetaItem.PageContent) +} +

@VariantTerms.Front_Share

+
+
+

@VariantTerms.Front_Listing

+
+ @foreach (Build build in Model) + { +
+

+ + @($"{build.MajorVersion}.{build.MinorVersion}.{build.Number}.{build.Revision}") + +

+ @if (!string.IsNullOrEmpty(build.Lab)) + { +

+ @build.Lab

+ } + @if (build.BuildTime.HasValue) + { +

+ + @build.BuildTime.Value.ToLongDateWithoutDay() +

+

+ + @build.BuildTime.Value.ToShortTimeString() +

+ } + @if (build.IsLeaked) + { +

+ + @VariantTerms.Front_Public +

+ } + else + { +

+ + @VariantTerms.Front_Private +

+ } + @if (Roles.IsUserInRole("Editors") || Roles.IsUserInRole("Administrators")) + { +

+ + @VariantTerms.Front_Edit + +   + @if (Roles.IsUserInRole("Administrators")) + { + + @VariantTerms.Front_Delete + + } +

+ } +
+ } +
+
+
+
+
+
+@PaginationHelpers.PaginationBlock((int)ViewBag.PageNumber, (int)ViewBag.PageCount, "ViewFamily", ViewContext.RouteData.Values) \ No newline at end of file diff --git a/BuildFeed/Views/front/index.cshtml b/BuildFeed/Views/front/index.cshtml index 60f07d0..09be71f 100644 --- a/BuildFeed/Views/front/index.cshtml +++ b/BuildFeed/Views/front/index.cshtml @@ -102,15 +102,14 @@