Some UI Tweaks; Build Model refactoring

refactor-intermediate-models
Thomas Hounsell 2015-11-09 16:43:05 +00:00
parent bdb7aa88af
commit 881b30c707
19 changed files with 713 additions and 616 deletions

View File

@ -768,7 +768,17 @@
</Compile>
<Compile Include="Models\ApiModel\NewBuild.cs" />
<Compile Include="Models\ApiModel\SearchResult.cs" />
<Compile Include="Models\Build.cs" />
<Compile Include="Models\Build\Build-Source.cs" />
<Compile Include="Models\Build\Build-Year.cs" />
<Compile Include="Models\Build\Build-Lab.cs" />
<Compile Include="Models\Build\Build-Version.cs" />
<Compile Include="Models\Build\Build-Group.cs" />
<Compile Include="Models\Build\Build.cs" />
<Compile Include="Models\Build\BuildGroup.cs" />
<Compile Include="Models\Build\BuildModel.cs" />
<Compile Include="Models\Build\BuildVersion.cs" />
<Compile Include="Models\Build\LevelOfFlight.cs" />
<Compile Include="Models\Build\TypeOfSource.cs" />
<Compile Include="Models\MetaItem.cs" />
<Compile Include="Models\ViewModel\Front\FrontBuildGroup.cs" />
<Compile Include="Models\ViewModel\LoginUser.cs" />

View File

@ -28,8 +28,8 @@ namespace BuildFeed.Controllers
public async Task<IEnumerable<string>> GetWin10Labs()
{
List<string> labs = new List<string>();
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 @@ namespace BuildFeed.Controllers
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 @@ namespace BuildFeed.Controllers
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()

View File

@ -137,7 +137,7 @@ namespace BuildFeed.Controllers
[Route("rss")]
public async Task<ActionResult> rss()
{
ViewBag.Labs = await bModel.SelectBuildLabs();
ViewBag.Labs = await bModel.SelectLabs();
return View();
}
@ -157,8 +157,8 @@ namespace BuildFeed.Controllers
{
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 @@ namespace BuildFeed.Controllers
}
[Route("credits/")]
public ActionResult credits()
{
return View();
}
public ActionResult credits() => View();
}
}

View File

@ -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<BuildModel> _buildCollection;
public Build()
{
_dbClient = new MongoClient(new MongoClientSettings()
{
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
});
_buildCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection<BuildModel>(_buildCollectionName);
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> Select()
{
return await _buildCollection.Find(new BsonDocument()).ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatest(int limit, int skip)
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.Added)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatestLeaked(int limit, int skip)
{
return await _buildCollection.Find(b => b.LeakDate != null)
.SortByDescending(b => b.LeakDate)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<FrontBuildGroup>> 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<int> 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<Tuple<BuildGroup, List<BuildModel>>> 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<BuildGroup, List<BuildModel>>(bGroup, await pipeline.ToListAsync());
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<BuildModel> SelectById(Guid id)
{
return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<BuildModel> SelectByLegacyId(long id)
{
return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<List<BuildModel>> 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<List<BuildModel>> SelectInVersionOrder()
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.ThenByDescending(b => b.BuildTime)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<List<BuildModel>> SelectFlight(LevelOfFlight flight, int limit, int skip)
{
return await _buildCollection.Find(b => b.FlightLevel == flight)
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<long> 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<List<BuildModel>> 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<long> SelectSourceCount(TypeOfSource source)
{
return await _buildCollection.Find(b => b.SourceType == source)
.CountAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<long> SelectYearCount(int year)
{
return await _buildCollection.Find(b => b.BuildTime != null &&
(b.BuildTime > new DateTime(year, 1, 1, 0, 0, 0)) &&
(b.BuildTime < new DateTime(year, 12, 31, 23, 59, 59)))
.CountAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> SelectVersion(int major, int minor, int skip, int limit)
{
return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<long> SelectVersionCount(int major, int minor)
{
return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.CountAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildVersion>> SelectBuildVersions()
{
var result = await _buildCollection.Aggregate()
.Group(b => new BuildVersion()
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
},
// incoming bullshit hack
bg => new Tuple<BuildVersion>(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<List<int>> SelectBuildYears()
{
var result = await _buildCollection.Aggregate()
.Match(b => b.BuildTime != null)
.Group(b => ((DateTime)b.BuildTime).Year,
// incoming bullshit hack
bg => new Tuple<int>(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<List<string>> 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<string>(bg.Key))
.ToListAsync();
// work ourselves out of aforementioned bullshit hack
return result.Select(b => b.Item1).ToList();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<string>> 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<string>(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<List<string>> 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<string>(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<BuildModel> 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}";
}
}
}

View File

@ -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<List<FrontBuildGroup>> 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<int> 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<Tuple<BuildGroup, List<BuildModel>>> 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<BuildGroup, List<BuildModel>>(bGroup, await pipeline.ToListAsync());
}
}
}

View File

@ -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<List<BuildModel>> 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<List<string>> 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<string>(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<List<string>> 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<string>(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<long> 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<List<string>> 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<string>(bg.Key))
.ToListAsync();
// work ourselves out of aforementioned bullshit hack
return result.Select(b => b.Item1).ToList();
}
}
}

View File

@ -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<List<BuildModel>> 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<long> SelectSourceCount(TypeOfSource source)
{
return await _buildCollection.Find(b => b.SourceType == source)
.CountAsync();
}
}
}

View File

@ -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<List<BuildModel>> SelectInVersionOrder()
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.ThenByDescending(b => b.BuildTime)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<List<BuildModel>> SelectVersion(int major, int minor, int skip, int limit)
{
return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.ThenByDescending(b => b.Number)
.ThenByDescending(b => b.Revision)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildVersion>> SelectVersions()
{
var result = await _buildCollection.Aggregate()
.Group(b => new BuildVersion()
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
},
// incoming bullshit hack
bg => new Tuple<BuildVersion>(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<long> SelectVersionCount(int major, int minor)
{
return await _buildCollection.Find(b => b.MajorVersion == major && b.MinorVersion == minor)
.CountAsync();
}
}
}

View File

@ -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<List<BuildModel>> 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<List<int>> SelectYears()
{
var result = await _buildCollection.Aggregate()
.Match(b => b.BuildTime != null)
.Group(b => ((DateTime)b.BuildTime).Year,
// incoming bullshit hack
bg => new Tuple<int>(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<long> SelectYearCount(int year)
{
return await _buildCollection.Find(b => b.BuildTime != null &&
(b.BuildTime > new DateTime(year, 1, 1, 0, 0, 0)) &&
(b.BuildTime < new DateTime(year, 12, 31, 23, 59, 59)))
.CountAsync();
}
}
}

View File

@ -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<BuildModel> _buildCollection;
public Build()
{
_dbClient = new MongoClient(new MongoClientSettings()
{
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
});
_buildCollection = _dbClient.GetDatabase(MongoConfig.Database).GetCollection<BuildModel>(_buildCollectionName);
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> Select()
{
return await _buildCollection.Find(new BsonDocument()).ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatest(int limit, int skip)
{
return await _buildCollection.Find(new BsonDocument())
.SortByDescending(b => b.Added)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<BuildModel>> SelectLatestLeaked(int limit, int skip)
{
return await _buildCollection.Find(b => b.LeakDate != null)
.SortByDescending(b => b.LeakDate)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<BuildModel> SelectById(Guid id)
{
return await _buildCollection.Find(f => f.Id == id).SingleOrDefaultAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<BuildModel> SelectByLegacyId(long id)
{
return await _buildCollection.Find(f => f.LegacyId == id).SingleOrDefaultAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<BuildModel>> 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<List<BuildModel>> 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<List<BuildModel>> SelectFlight(LevelOfFlight flight, int limit, int skip)
{
return await _buildCollection.Find(b => b.FlightLevel == flight)
.SortByDescending(b => b.BuildTime)
.ThenByDescending(b => b.MajorVersion)
.ThenByDescending(b => b.MinorVersion)
.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<BuildModel> 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);
}
}
}

View File

@ -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}";
}
}

View File

@ -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();
}
}

View File

@ -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}";
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -74,7 +74,7 @@ namespace BuildFeed.Models
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> 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 @@ namespace BuildFeed.Models
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> 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 @@ namespace BuildFeed.Models
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedYears()
{
var years = await bModel.SelectBuildYears();
var years = await bModel.SelectYears();
var usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync();

View File

@ -22,7 +22,7 @@
<meta name="twitter:description" content="@metaDesc" />
}
<h1 dir="ltr">@Model.FullBuildString</h1>
<h1 dir="ltr" class="eager-wrapping">@Model.FullBuildString</h1>
<div class="row">
<div class="col-sm-6">

View File

@ -25,7 +25,6 @@
</li>
}
</ul>
</li>
@foreach (var item in Model.Actions)
{

View File

@ -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;