From 881b30c707bf8e49a4913788d3220438767143d8 Mon Sep 17 00:00:00 2001 From: Thomas Hounsell Date: Mon, 9 Nov 2015 16:43:05 +0000 Subject: [PATCH] Some UI Tweaks; Build Model refactoring --- BuildFeed/BuildFeed.csproj | 12 +- BuildFeed/Controllers/apiController.cs | 8 +- BuildFeed/Controllers/supportController.cs | 11 +- BuildFeed/Models/Build.cs | 599 --------------------- BuildFeed/Models/Build/Build-Group.cs | 69 +++ BuildFeed/Models/Build/Build-Lab.cs | 86 +++ BuildFeed/Models/Build/Build-Source.cs | 32 ++ BuildFeed/Models/Build/Build-Version.cs | 79 +++ BuildFeed/Models/Build/Build-Year.cs | 52 ++ BuildFeed/Models/Build/Build.cs | 146 +++++ BuildFeed/Models/Build/BuildGroup.cs | 14 + BuildFeed/Models/Build/BuildModel.cs | 116 ++++ BuildFeed/Models/Build/BuildVersion.cs | 21 + BuildFeed/Models/Build/LevelOfFlight.cs | 26 + BuildFeed/Models/Build/TypeOfSource.cs | 35 ++ BuildFeed/Models/MetaItem.cs | 6 +- BuildFeed/Views/front/viewBuild.cshtml | 2 +- BuildFeed/Views/support/sitemap.cshtml | 1 - BuildFeed/content/style.css | 14 + 19 files changed, 713 insertions(+), 616 deletions(-) delete mode 100644 BuildFeed/Models/Build.cs create mode 100644 BuildFeed/Models/Build/Build-Group.cs create mode 100644 BuildFeed/Models/Build/Build-Lab.cs create mode 100644 BuildFeed/Models/Build/Build-Source.cs create mode 100644 BuildFeed/Models/Build/Build-Version.cs create mode 100644 BuildFeed/Models/Build/Build-Year.cs create mode 100644 BuildFeed/Models/Build/Build.cs create mode 100644 BuildFeed/Models/Build/BuildGroup.cs create mode 100644 BuildFeed/Models/Build/BuildModel.cs create mode 100644 BuildFeed/Models/Build/BuildVersion.cs create mode 100644 BuildFeed/Models/Build/LevelOfFlight.cs create mode 100644 BuildFeed/Models/Build/TypeOfSource.cs diff --git a/BuildFeed/BuildFeed.csproj b/BuildFeed/BuildFeed.csproj index ee99d3f..f32ce3d 100644 --- a/BuildFeed/BuildFeed.csproj +++ b/BuildFeed/BuildFeed.csproj @@ -768,7 +768,17 @@ - + + + + + + + + + + + diff --git a/BuildFeed/Controllers/apiController.cs b/BuildFeed/Controllers/apiController.cs index 1b4ecaf..1fb9f07 100644 --- a/BuildFeed/Controllers/apiController.cs +++ b/BuildFeed/Controllers/apiController.cs @@ -28,8 +28,8 @@ public async Task GetBuilds(int limit = 20, int skip = 0) public async Task> GetWin10Labs() { List labs = new List(); - labs.AddRange(await bModel.SelectBuildLabs(6, 4)); - labs.AddRange(await bModel.SelectBuildLabs(10, 0)); + labs.AddRange(await bModel.SelectLabs(6, 4)); + labs.AddRange(await bModel.SelectLabs(10, 0)); return labs .GroupBy(l => l) @@ -88,7 +88,7 @@ orderby s.Text.ToLower().IndexOf(id.ToLower(), StringComparison.Ordinal) ascendi results.AddRange(sourceResults); - var versionResults = from v in await bModel.SelectBuildVersions() + var versionResults = from v in await bModel.SelectVersions() where $"{v.Major}.{v.Minor}".StartsWith(id) orderby v.Major descending, v.Minor descending select new SearchResult() @@ -102,7 +102,7 @@ orderby s.Text.ToLower().IndexOf(id.ToLower(), StringComparison.Ordinal) ascendi results.AddRange(versionResults); - var yearResults = from y in await bModel.SelectBuildYears() + var yearResults = from y in await bModel.SelectYears() where y.ToString().Contains(id) orderby y descending select new SearchResult() diff --git a/BuildFeed/Controllers/supportController.cs b/BuildFeed/Controllers/supportController.cs index 865288d..c459d11 100644 --- a/BuildFeed/Controllers/supportController.cs +++ b/BuildFeed/Controllers/supportController.cs @@ -137,7 +137,7 @@ public ActionResult thanks_register() [Route("rss")] public async Task rss() { - ViewBag.Labs = await bModel.SelectBuildLabs(); + ViewBag.Labs = await bModel.SelectLabs(); return View(); } @@ -157,8 +157,8 @@ public async Task sitemap() { UrlParams = new RouteValueDictionary(new { - controller = "build", - action = "index", + controller = "front", + action = "indexPage", page = 1 }), Pages = (builds.Count() + (frontController.PAGE_SIZE - 1)) / frontController.PAGE_SIZE @@ -394,9 +394,6 @@ orderby bl.Count() descending } [Route("credits/")] - public ActionResult credits() - { - return View(); - } + public ActionResult credits() => View(); } } \ No newline at end of file diff --git a/BuildFeed/Models/Build.cs b/BuildFeed/Models/Build.cs deleted file mode 100644 index 2feaabe..0000000 --- a/BuildFeed/Models/Build.cs +++ /dev/null @@ -1,599 +0,0 @@ -using BuildFeed.Local; -using BuildFeed.Models.ApiModel; -using BuildFeed.Models.ViewModel.Front; -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System; -using System.Collections.Generic; -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; - -namespace BuildFeed.Models -{ - [DataObject] - public class BuildModel - { - [Key, BsonId] - public Guid Id { get; set; } - - public long? LegacyId { get; set; } - - [@Required] - [Display(ResourceType = typeof(Model), Name = "MajorVersion")] - public byte MajorVersion { get; set; } - - [@Required] - [Display(ResourceType = typeof(Model), Name = "MinorVersion")] - public byte MinorVersion { get; set; } - - [@Required] - [Display(ResourceType = typeof(Model), Name = "Number")] - public ushort Number { get; set; } - - [Display(ResourceType = typeof(Model), Name = "Revision")] - [DisplayFormat(ConvertEmptyStringToNull = true)] - public ushort? Revision { get; set; } - - [Display(ResourceType = typeof(Model), Name = "Lab")] - public string Lab { get; set; } - - [Display(ResourceType = typeof(Model), Name = "BuildTime")] - [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:yyMMdd-HHmm}")] - public DateTime? BuildTime { get; set; } - - - [@Required] - [Display(ResourceType = typeof(Model), Name = "Added")] - public DateTime Added { get; set; } - - [@Required] - [Display(ResourceType = typeof(Model), Name = "Modified")] - public DateTime Modified { get; set; } - - [@Required] - [Display(ResourceType = typeof(Model), Name = "SourceType")] - [EnumDataType(typeof(TypeOfSource))] - public TypeOfSource SourceType { get; set; } - - [Display(ResourceType = typeof(Model), Name = "SourceDetails")] - [AllowHtml] - public string SourceDetails { get; set; } - - [Display(ResourceType = typeof(Model), Name = "LeakDate")] - [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")] - public DateTime? LeakDate { get; set; } - - [Display(ResourceType = typeof(Model), Name = "FlightLevel")] - [EnumDataType(typeof(LevelOfFlight))] - public LevelOfFlight FlightLevel { get; set; } - - public string LabUrl { get; set; } - - public bool IsLeaked - { - get - { - switch (SourceType) - { - case TypeOfSource.PublicRelease: - case TypeOfSource.InternalLeak: - case TypeOfSource.UpdateGDR: - case TypeOfSource.UpdateLDR: - return true; - default: - return false; - } - } - } - - public string FullBuildString - { - get - { - StringBuilder sb = new StringBuilder(); - sb.AppendFormat("{0}.{1}.{2}", MajorVersion, MinorVersion, Number); - - if (Revision.HasValue) - { - sb.AppendFormat(".{0}", Revision); - } - - if (!string.IsNullOrWhiteSpace(Lab)) - { - sb.AppendFormat(".{0}", Lab); - } - - if (BuildTime.HasValue) - { - sb.AppendFormat(".{0:yyMMdd-HHmm}", BuildTime); - } - - return sb.ToString(); - } - } - - public string GenerateLabUrl() => (Lab ?? "").Replace('/', '-').ToLower(); - } - - public class Build - { - private const string _buildCollectionName = "builds"; - - private MongoClient _dbClient; - private IMongoCollection _buildCollection; - - public Build() - { - _dbClient = new MongoClient(new MongoClientSettings() - { - Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port) - }); - - _buildCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection(_buildCollectionName); - } - - [DataObjectMethod(DataObjectMethodType.Select, true)] - public async Task> Select() - { - return await _buildCollection.Find(new BsonDocument()).ToListAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, true)] - public async Task> 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> SelectLatestLeaked(int limit, int skip) - { - return await _buildCollection.Find(b => b.LeakDate != null) - .SortByDescending(b => b.LeakDate) - .Skip(skip) - .Limit(limit) - .ToListAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectBuildGroups(int limit, int skip) - { - return await _buildCollection.Aggregate() - .Group(b => new BuildGroup() - { - Major = b.MajorVersion, - Minor = b.MinorVersion, - Build = b.Number, - Revision = b.Revision - }, - bg => new FrontBuildGroup() - { - Key = bg.Key, - BuildCount = bg.Count(), - LastBuild = bg.Max(b => b.BuildTime) - }) - .SortByDescending(b => b.Key.Major) - .ThenByDescending(b => b.Key.Minor) - .ThenByDescending(b => b.Key.Build) - .ThenByDescending(b => b.Key.Revision) - .Skip(skip) - .Limit(limit) - .ToListAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, true)] - public async Task SelectBuildGroupsCount() - { - var pipeline = _buildCollection.Aggregate() - .Group(b => new BuildGroup() - { - Major = b.MajorVersion, - Minor = b.MinorVersion, - Build = b.Number, - Revision = b.Revision - }, - bg => new BsonDocument()); - - return (await pipeline.ToListAsync()).Count; - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task>> SelectSingleBuildGroup(BuildGroup bGroup) - { - var pipeline = _buildCollection.Aggregate() - .Match(b => b.MajorVersion == bGroup.Major) - .Match(b => b.MinorVersion == bGroup.Minor) - .Match(b => b.Number == bGroup.Build) - .Match(b => b.Revision == bGroup.Revision) - .SortByDescending(b => b.BuildTime); - - return new Tuple>(bGroup, await pipeline.ToListAsync()); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task SelectById(Guid id) - { - return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task SelectByLegacyId(long id) - { - return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectInBuildOrder() - { - 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(); - - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectInBuildOrder(int limit, int skip) - { - 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> 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(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectInVersionOrder(int limit, int skip) - { - 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> 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) - .ThenByDescending(b => b.Number) - .ThenByDescending(b => b.Revision) - .Skip(skip) - .Limit(limit) - .ToListAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectLab(string lab, int skip, int limit) - { - string labUrl = lab.Replace('/', '-').ToLower(); - return await _buildCollection.Find(b => b.Lab != null && b.LabUrl == labUrl) - .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 SelectLabCount(string lab) - { - string labUrl = lab.Replace('/', '-').ToLower(); - return await _buildCollection.Find(b => b.Lab != null && b.LabUrl == labUrl) - .CountAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectSource(TypeOfSource source, int skip, int limit) - { - return await _buildCollection.Find(b => b.SourceType == source) - .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 SelectSourceCount(TypeOfSource source) - { - return await _buildCollection.Find(b => b.SourceType == source) - .CountAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectYear(int year, int skip, int limit) - { - 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 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> 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) - .ThenByDescending(b => b.Number) - .ThenByDescending(b => b.Revision) - .Skip(skip) - .Limit(limit) - .ToListAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task SelectVersionCount(int major, int minor) - { - return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor) - .CountAsync(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectBuildVersions() - { - var result = await _buildCollection.Aggregate() - .Group(b => new BuildVersion() - { - Major = b.MajorVersion, - Minor = b.MinorVersion, - }, - // incoming bullshit hack - bg => new Tuple(bg.Key)) - .SortByDescending(b => b.Item1.Major) - .ThenByDescending(b => b.Item1.Minor) - .ToListAsync(); - - // work ourselves out of aforementioned bullshit hack - return result.Select(b => b.Item1).ToList(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectBuildYears() - { - var result = await _buildCollection.Aggregate() - .Match(b => b.BuildTime != null) - .Group(b => ((DateTime)b.BuildTime).Year, - // incoming bullshit hack - bg => new Tuple(bg.Key)) - .SortByDescending(b => b.Item1) - .ToListAsync(); - - // work ourselves out of aforementioned bullshit hack - return result.Select(b => b.Item1).ToList(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SearchBuildLabs(string query) - { - var result = await _buildCollection.Aggregate() - .Match(b => b.Lab != null) - .Match(b => b.Lab != "") - .Match(b => b.Lab.ToLower().Contains(query.ToLower())) - .Group(b => b.Lab.ToLower(), - // incoming bullshit hack - bg => new Tuple(bg.Key)) - .ToListAsync(); - - // work ourselves out of aforementioned bullshit hack - return result.Select(b => b.Item1).ToList(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectBuildLabs() - { - var result = await _buildCollection.Aggregate() - .Match(b => b.Lab != null) - .Match(b => b.Lab != "") - .Group(b => b.Lab.ToLower(), - // incoming bullshit hack - bg => new Tuple(bg.Key)) - .SortBy(b => b.Item1) - .ToListAsync(); - - // work ourselves out of aforementioned bullshit hack - return result.Select(b => b.Item1).ToList(); - } - - [DataObjectMethod(DataObjectMethodType.Select, false)] - public async Task> SelectBuildLabs(byte major, byte minor) - { - var result = await _buildCollection.Aggregate() - .Match(b => b.MajorVersion == major) - .Match(b => b.MinorVersion == minor) - .Match(b => b.Lab != null) - .Match(b => b.Lab != "") - .Group(b => b.Lab.ToLower(), - // incoming bullshit hack - bg => new Tuple(bg.Key)) - .SortBy(b => b.Item1) - .ToListAsync(); - - // work ourselves out of aforementioned bullshit hack - return result.Select(b => b.Item1).ToList(); - } - - [DataObjectMethod(DataObjectMethodType.Insert, true)] - public async Task Insert(BuildModel item) - { - item.Id = Guid.NewGuid(); - item.LabUrl = item.GenerateLabUrl(); - await _buildCollection.InsertOneAsync(item); - } - - [DataObjectMethod(DataObjectMethodType.Insert, false)] - public async Task InsertAll(IEnumerable items) - { - foreach(var item in items) - { - item.Id = Guid.NewGuid(); - item.LabUrl = item.GenerateLabUrl(); - } - - await _buildCollection.InsertManyAsync(items); - } - - [DataObjectMethod(DataObjectMethodType.Update, true)] - public async Task Update(BuildModel item) - { - BuildModel old = await SelectById(item.Id); - item.Added = old.Added; - item.Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc); - item.LabUrl = item.GenerateLabUrl(); - - await _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item); - } - - [DataObjectMethod(DataObjectMethodType.Delete, true)] - public async Task DeleteById(Guid id) - { - await _buildCollection.DeleteOneAsync(f => f.Id == id); - } - } - - public enum TypeOfSource - { - [Display(ResourceType = typeof(Model), Name = "PublicRelease")] - PublicRelease = 0, - - [Display(ResourceType = typeof(Model), Name = "InternalLeak")] - InternalLeak = 1, - - [Display(ResourceType = typeof(Model), Name = "UpdateGDR")] - UpdateGDR = 2, - - [Display(ResourceType = typeof(Model), Name = "UpdateLDR")] - UpdateLDR = 3, - - [Display(ResourceType = typeof(Model), Name = "AppPackage")] - AppPackage = 4, - - [Display(ResourceType = typeof(Model), Name = "BuildTools")] - BuildTools = 5, - - [Display(ResourceType = typeof(Model), Name = "Documentation")] - Documentation = 6, - - [Display(ResourceType = typeof(Model), Name = "Logging")] - Logging = 7, - - [Display(ResourceType = typeof(Model), Name = "PrivateLeak")] - PrivateLeak = 8 - } - - public enum LevelOfFlight - { - [Display(ResourceType = typeof(Model), Name = "FlightNone")] - None = 0, - - [Display(ResourceType = typeof(Model), Name = "FlightWIS")] - WIS = 1, - - [Display(ResourceType = typeof(Model), Name = "FlightWIF")] - WIF = 2, - - [Display(ResourceType = typeof(Model), Name = "FlightOSG")] - OSG = 3, - - [Display(ResourceType = typeof(Model), Name = "FlightMSIT")] - MSIT = 4, - - [Display(ResourceType = typeof(Model), Name = "FlightCanary")] - Canary = 5 - } - - public class BuildVersion - { - public byte Major { get; set; } - public byte Minor { get; set; } - - public BuildVersion() - { - } - - public BuildVersion(byte major, byte minor) - { - Major = major; - Minor = minor; - } - - public override string ToString() - { - return $"{Major}.{Minor}"; - } - } - - public class BuildGroup - { - public byte Major { get; set; } - public byte Minor { get; set; } - public ushort Build { get; set; } - public ushort? Revision { get; set; } - - public override string ToString() - { - return Revision.HasValue ? - $"{Major}.{Minor}.{Build}.{Revision.Value}" : - $"{Major}.{Minor}.{Build}"; - } - } -} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build-Group.cs b/BuildFeed/Models/Build/Build-Group.cs new file mode 100644 index 0000000..f366288 --- /dev/null +++ b/BuildFeed/Models/Build/Build-Group.cs @@ -0,0 +1,69 @@ +using BuildFeed.Models.ViewModel.Front; +using MongoDB.Bson; +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + public partial class Build + { + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectBuildGroups(int limit, int skip) + { + return await _buildCollection.Aggregate() + .Group(b => new BuildGroup() + { + Major = b.MajorVersion, + Minor = b.MinorVersion, + Build = b.Number, + Revision = b.Revision + }, + bg => new FrontBuildGroup() + { + Key = bg.Key, + BuildCount = bg.Count(), + LastBuild = bg.Max(b => b.BuildTime) + }) + .SortByDescending(b => b.Key.Major) + .ThenByDescending(b => b.Key.Minor) + .ThenByDescending(b => b.Key.Build) + .ThenByDescending(b => b.Key.Revision) + .Skip(skip) + .Limit(limit) + .ToListAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, true)] + public async Task SelectBuildGroupsCount() + { + var pipeline = _buildCollection.Aggregate() + .Group(b => new BuildGroup() + { + Major = b.MajorVersion, + Minor = b.MinorVersion, + Build = b.Number, + Revision = b.Revision + }, + bg => new BsonDocument()); + + return (await pipeline.ToListAsync()).Count; + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task>> SelectSingleBuildGroup(BuildGroup bGroup) + { + var pipeline = _buildCollection.Aggregate() + .Match(b => b.MajorVersion == bGroup.Major) + .Match(b => b.MinorVersion == bGroup.Minor) + .Match(b => b.Number == bGroup.Build) + .Match(b => b.Revision == bGroup.Revision) + .SortByDescending(b => b.BuildTime); + + return new Tuple>(bGroup, await pipeline.ToListAsync()); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build-Lab.cs b/BuildFeed/Models/Build/Build-Lab.cs new file mode 100644 index 0000000..bd05bcc --- /dev/null +++ b/BuildFeed/Models/Build/Build-Lab.cs @@ -0,0 +1,86 @@ +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + public partial class Build + { + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectLab(string lab, int skip, int limit) + { + string labUrl = lab.Replace('/', '-').ToLower(); + return await _buildCollection.Find(b => b.Lab != null && b.LabUrl == labUrl) + .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> SelectLabs() + { + var result = await _buildCollection.Aggregate() + .Match(b => b.Lab != null) + .Match(b => b.Lab != "") + .Group(b => b.Lab.ToLower(), + // incoming bullshit hack + bg => new Tuple(bg.Key)) + .SortBy(b => b.Item1) + .ToListAsync(); + + // work ourselves out of aforementioned bullshit hack + return result.Select(b => b.Item1).ToList(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectLabs(byte major, byte minor) + { + var result = await _buildCollection.Aggregate() + .Match(b => b.MajorVersion == major) + .Match(b => b.MinorVersion == minor) + .Match(b => b.Lab != null) + .Match(b => b.Lab != "") + .Group(b => b.Lab.ToLower(), + // incoming bullshit hack + bg => new Tuple(bg.Key)) + .SortBy(b => b.Item1) + .ToListAsync(); + + // work ourselves out of aforementioned bullshit hack + return result.Select(b => b.Item1).ToList(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task SelectLabCount(string lab) + { + string labUrl = lab.Replace('/', '-').ToLower(); + return await _buildCollection.Find(b => b.Lab != null && b.LabUrl == labUrl) + .CountAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SearchBuildLabs(string query) + { + var result = await _buildCollection.Aggregate() + .Match(b => b.Lab != null) + .Match(b => b.Lab != "") + .Match(b => b.Lab.ToLower().Contains(query.ToLower())) + .Group(b => b.Lab.ToLower(), + // incoming bullshit hack + bg => new Tuple(bg.Key)) + .ToListAsync(); + + // work ourselves out of aforementioned bullshit hack + return result.Select(b => b.Item1).ToList(); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build-Source.cs b/BuildFeed/Models/Build/Build-Source.cs new file mode 100644 index 0000000..eaacf85 --- /dev/null +++ b/BuildFeed/Models/Build/Build-Source.cs @@ -0,0 +1,32 @@ +using MongoDB.Driver; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + public partial class Build + { + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectSource(TypeOfSource source, int skip, int limit) + { + return await _buildCollection.Find(b => b.SourceType == source) + .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 SelectSourceCount(TypeOfSource source) + { + return await _buildCollection.Find(b => b.SourceType == source) + .CountAsync(); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build-Version.cs b/BuildFeed/Models/Build/Build-Version.cs new file mode 100644 index 0000000..51f93dd --- /dev/null +++ b/BuildFeed/Models/Build/Build-Version.cs @@ -0,0 +1,79 @@ +using MongoDB.Bson; +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + public partial class Build + { + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> 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(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectInVersionOrder(int limit, int skip) + { + 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> 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) + .ThenByDescending(b => b.Number) + .ThenByDescending(b => b.Revision) + .Skip(skip) + .Limit(limit) + .ToListAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectVersions() + { + var result = await _buildCollection.Aggregate() + .Group(b => new BuildVersion() + { + Major = b.MajorVersion, + Minor = b.MinorVersion, + }, + // incoming bullshit hack + bg => new Tuple(bg.Key)) + .SortByDescending(b => b.Item1.Major) + .ThenByDescending(b => b.Item1.Minor) + .ToListAsync(); + + // work ourselves out of aforementioned bullshit hack + return result.Select(b => b.Item1).ToList(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task SelectVersionCount(int major, int minor) + { + return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor) + .CountAsync(); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build-Year.cs b/BuildFeed/Models/Build/Build-Year.cs new file mode 100644 index 0000000..aa2dc6f --- /dev/null +++ b/BuildFeed/Models/Build/Build-Year.cs @@ -0,0 +1,52 @@ +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + public partial class Build + { + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectYear(int year, int skip, int limit) + { + 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> SelectYears() + { + var result = await _buildCollection.Aggregate() + .Match(b => b.BuildTime != null) + .Group(b => ((DateTime)b.BuildTime).Year, + // incoming bullshit hack + bg => new Tuple(bg.Key)) + .SortByDescending(b => b.Item1) + .ToListAsync(); + + // work ourselves out of aforementioned bullshit hack + return result.Select(b => b.Item1).ToList(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task 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(); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/Build.cs b/BuildFeed/Models/Build/Build.cs new file mode 100644 index 0000000..a40e13c --- /dev/null +++ b/BuildFeed/Models/Build/Build.cs @@ -0,0 +1,146 @@ +using BuildFeed.Models.ViewModel.Front; +using MongoDB.Bson; +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace BuildFeed.Models +{ + + public partial class Build + { + private const string _buildCollectionName = "builds"; + + private MongoClient _dbClient; + private IMongoCollection _buildCollection; + + public Build() + { + _dbClient = new MongoClient(new MongoClientSettings() + { + Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port) + }); + + _buildCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection(_buildCollectionName); + } + + [DataObjectMethod(DataObjectMethodType.Select, true)] + public async Task> Select() + { + return await _buildCollection.Find(new BsonDocument()).ToListAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, true)] + public async Task> 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> SelectLatestLeaked(int limit, int skip) + { + return await _buildCollection.Find(b => b.LeakDate != null) + .SortByDescending(b => b.LeakDate) + .Skip(skip) + .Limit(limit) + .ToListAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task SelectById(Guid id) + { + return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task SelectByLegacyId(long id) + { + return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectInBuildOrder() + { + 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(); + + } + + [DataObjectMethod(DataObjectMethodType.Select, false)] + public async Task> SelectInBuildOrder(int limit, int skip) + { + 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> 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) + .ThenByDescending(b => b.Number) + .ThenByDescending(b => b.Revision) + .Skip(skip) + .Limit(limit) + .ToListAsync(); + } + + [DataObjectMethod(DataObjectMethodType.Insert, true)] + public async Task Insert(BuildModel item) + { + item.Id = Guid.NewGuid(); + item.LabUrl = item.GenerateLabUrl(); + await _buildCollection.InsertOneAsync(item); + } + + [DataObjectMethod(DataObjectMethodType.Insert, false)] + public async Task InsertAll(IEnumerable items) + { + foreach(var item in items) + { + item.Id = Guid.NewGuid(); + item.LabUrl = item.GenerateLabUrl(); + } + + await _buildCollection.InsertManyAsync(items); + } + + [DataObjectMethod(DataObjectMethodType.Update, true)] + public async Task Update(BuildModel item) + { + BuildModel old = await SelectById(item.Id); + item.Added = old.Added; + item.Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc); + item.LabUrl = item.GenerateLabUrl(); + + await _buildCollection.ReplaceOneAsync(f => f.Id == item.Id, item); + } + + [DataObjectMethod(DataObjectMethodType.Delete, true)] + public async Task DeleteById(Guid id) + { + await _buildCollection.DeleteOneAsync(f => f.Id == id); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/BuildGroup.cs b/BuildFeed/Models/Build/BuildGroup.cs new file mode 100644 index 0000000..4ac74e2 --- /dev/null +++ b/BuildFeed/Models/Build/BuildGroup.cs @@ -0,0 +1,14 @@ +namespace BuildFeed.Models +{ + public class BuildGroup + { + public byte Major { get; set; } + public byte Minor { get; set; } + public ushort Build { get; set; } + public ushort? Revision { get; set; } + + public override string ToString() => Revision.HasValue ? + $"{Major}.{Minor}.{Build}.{Revision.Value}" : + $"{Major}.{Minor}.{Build}"; + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/BuildModel.cs b/BuildFeed/Models/Build/BuildModel.cs new file mode 100644 index 0000000..7944abf --- /dev/null +++ b/BuildFeed/Models/Build/BuildModel.cs @@ -0,0 +1,116 @@ +using BuildFeed.Local; +using MongoDB.Bson.Serialization.Attributes; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text; +using System.Web.Mvc; +using Required = System.ComponentModel.DataAnnotations.RequiredAttribute; + +namespace BuildFeed.Models +{ + [DataObject] + public class BuildModel + { + [Key, BsonId] + public Guid Id { get; set; } + + public long? LegacyId { get; set; } + + [@Required] + [Display(ResourceType = typeof(Model), Name = "MajorVersion")] + public byte MajorVersion { get; set; } + + [@Required] + [Display(ResourceType = typeof(Model), Name = "MinorVersion")] + public byte MinorVersion { get; set; } + + [@Required] + [Display(ResourceType = typeof(Model), Name = "Number")] + public ushort Number { get; set; } + + [Display(ResourceType = typeof(Model), Name = "Revision")] + [DisplayFormat(ConvertEmptyStringToNull = true)] + public ushort? Revision { get; set; } + + [Display(ResourceType = typeof(Model), Name = "Lab")] + public string Lab { get; set; } + + [Display(ResourceType = typeof(Model), Name = "BuildTime")] + [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:yyMMdd-HHmm}")] + public DateTime? BuildTime { get; set; } + + + [@Required] + [Display(ResourceType = typeof(Model), Name = "Added")] + public DateTime Added { get; set; } + + [@Required] + [Display(ResourceType = typeof(Model), Name = "Modified")] + public DateTime Modified { get; set; } + + [@Required] + [Display(ResourceType = typeof(Model), Name = "SourceType")] + [EnumDataType(typeof(TypeOfSource))] + public TypeOfSource SourceType { get; set; } + + [Display(ResourceType = typeof(Model), Name = "SourceDetails")] + [AllowHtml] + public string SourceDetails { get; set; } + + [Display(ResourceType = typeof(Model), Name = "LeakDate")] + [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")] + public DateTime? LeakDate { get; set; } + + [Display(ResourceType = typeof(Model), Name = "FlightLevel")] + [EnumDataType(typeof(LevelOfFlight))] + public LevelOfFlight FlightLevel { get; set; } + + public string LabUrl { get; set; } + + public bool IsLeaked + { + get + { + switch (SourceType) + { + case TypeOfSource.PublicRelease: + case TypeOfSource.InternalLeak: + case TypeOfSource.UpdateGDR: + case TypeOfSource.UpdateLDR: + return true; + default: + return false; + } + } + } + + public string FullBuildString + { + get + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("{0}.{1}.{2}", MajorVersion, MinorVersion, Number); + + if (Revision.HasValue) + { + sb.AppendFormat(".{0}", Revision); + } + + if (!string.IsNullOrWhiteSpace(Lab)) + { + sb.AppendFormat(".{0}", Lab); + } + + if (BuildTime.HasValue) + { + sb.AppendFormat(".{0:yyMMdd-HHmm}", BuildTime); + } + + return sb.ToString(); + } + } + + public string GenerateLabUrl() => (Lab ?? "").Replace('/', '-').ToLower(); + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/BuildVersion.cs b/BuildFeed/Models/Build/BuildVersion.cs new file mode 100644 index 0000000..82c2296 --- /dev/null +++ b/BuildFeed/Models/Build/BuildVersion.cs @@ -0,0 +1,21 @@ +namespace BuildFeed.Models +{ + + public class BuildVersion + { + public byte Major { get; set; } + public byte Minor { get; set; } + + public BuildVersion() + { + } + + public BuildVersion(byte major, byte minor) + { + Major = major; + Minor = minor; + } + + public override string ToString() => $"{Major}.{Minor}"; + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/LevelOfFlight.cs b/BuildFeed/Models/Build/LevelOfFlight.cs new file mode 100644 index 0000000..6a6881f --- /dev/null +++ b/BuildFeed/Models/Build/LevelOfFlight.cs @@ -0,0 +1,26 @@ +using BuildFeed.Local; +using System.ComponentModel.DataAnnotations; + +namespace BuildFeed.Models +{ + public enum LevelOfFlight + { + [Display(ResourceType = typeof(Model), Name = "FlightNone")] + None = 0, + + [Display(ResourceType = typeof(Model), Name = "FlightWIS")] + WIS = 1, + + [Display(ResourceType = typeof(Model), Name = "FlightWIF")] + WIF = 2, + + [Display(ResourceType = typeof(Model), Name = "FlightOSG")] + OSG = 3, + + [Display(ResourceType = typeof(Model), Name = "FlightMSIT")] + MSIT = 4, + + [Display(ResourceType = typeof(Model), Name = "FlightCanary")] + Canary = 5 + } +} \ No newline at end of file diff --git a/BuildFeed/Models/Build/TypeOfSource.cs b/BuildFeed/Models/Build/TypeOfSource.cs new file mode 100644 index 0000000..338cfee --- /dev/null +++ b/BuildFeed/Models/Build/TypeOfSource.cs @@ -0,0 +1,35 @@ +using BuildFeed.Local; +using System.ComponentModel.DataAnnotations; + +namespace BuildFeed.Models +{ + public enum TypeOfSource + { + [Display(ResourceType = typeof(Model), Name = "PublicRelease")] + PublicRelease = 0, + + [Display(ResourceType = typeof(Model), Name = "InternalLeak")] + InternalLeak = 1, + + [Display(ResourceType = typeof(Model), Name = "UpdateGDR")] + UpdateGDR = 2, + + [Display(ResourceType = typeof(Model), Name = "UpdateLDR")] + UpdateLDR = 3, + + [Display(ResourceType = typeof(Model), Name = "AppPackage")] + AppPackage = 4, + + [Display(ResourceType = typeof(Model), Name = "BuildTools")] + BuildTools = 5, + + [Display(ResourceType = typeof(Model), Name = "Documentation")] + Documentation = 6, + + [Display(ResourceType = typeof(Model), Name = "Logging")] + Logging = 7, + + [Display(ResourceType = typeof(Model), Name = "PrivateLeak")] + PrivateLeak = 8 + } +} \ No newline at end of file diff --git a/BuildFeed/Models/MetaItem.cs b/BuildFeed/Models/MetaItem.cs index db09c5d..b615761 100644 --- a/BuildFeed/Models/MetaItem.cs +++ b/BuildFeed/Models/MetaItem.cs @@ -74,7 +74,7 @@ public async Task SelectById(MetaItemKey id) [DataObjectMethod(DataObjectMethodType.Select, false)] public async Task> SelectUnusedLabs() { - var labs = await bModel.SelectBuildLabs(); + var labs = await bModel.SelectLabs(); var usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync(); @@ -86,7 +86,7 @@ where usedLabs.All(ul => ul.Id.Value != l) [DataObjectMethod(DataObjectMethodType.Select, false)] public async Task> SelectUnusedVersions() { - var versions = await bModel.SelectBuildVersions(); + var versions = await bModel.SelectVersions(); var usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync(); @@ -98,7 +98,7 @@ where usedVersions.All(ul => ul.Id.Value != v.ToString()) [DataObjectMethod(DataObjectMethodType.Select, false)] public async Task> SelectUnusedYears() { - var years = await bModel.SelectBuildYears(); + var years = await bModel.SelectYears(); var usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync(); diff --git a/BuildFeed/Views/front/viewBuild.cshtml b/BuildFeed/Views/front/viewBuild.cshtml index 553c8d9..e1ccd70 100644 --- a/BuildFeed/Views/front/viewBuild.cshtml +++ b/BuildFeed/Views/front/viewBuild.cshtml @@ -22,7 +22,7 @@ } -

@Model.FullBuildString

+

@Model.FullBuildString

diff --git a/BuildFeed/Views/support/sitemap.cshtml b/BuildFeed/Views/support/sitemap.cshtml index 337530a..f24edee 100644 --- a/BuildFeed/Views/support/sitemap.cshtml +++ b/BuildFeed/Views/support/sitemap.cshtml @@ -25,7 +25,6 @@ } - @foreach (var item in Model.Actions) { diff --git a/BuildFeed/content/style.css b/BuildFeed/content/style.css index aaa80e7..d38e14c 100644 --- a/BuildFeed/content/style.css +++ b/BuildFeed/content/style.css @@ -15,6 +15,14 @@ h1 color: #000; } +@media(max-width: 480px) +{ + h1 + { + font-size: 40px; + } +} + #page-content { padding-top: 50px; @@ -45,6 +53,12 @@ h1 white-space: nowrap; } +.eager-wrapping +{ + -ms-word-wrap: break-word; + word-wrap: break-word; +} + .label-build-status { padding-bottom: 0;