Code style consistency and enforcement

refactor-intermediate-models
Thomas Hounsell 2017-02-23 20:53:49 +00:00
parent c23490ad0f
commit f0409c794d
73 changed files with 2696 additions and 2608 deletions

View File

@ -2,10 +2,10 @@
namespace BuildFeed.Local namespace BuildFeed.Local
{ {
public class InvariantTerms public class InvariantTerms
{ {
public const string DeveloperName = "Thomas Hounsell"; public const string DeveloperName = "Thomas Hounsell";
public const string ProductName = "Windows NT"; public const string ProductName = "Windows NT";
public const string SiteName = "BuildFeed"; public const string SiteName = "BuildFeed";
} }
} }

View File

@ -1,10 +1,10 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("BuildFeed.Local")] [assembly: AssemblyTitle("BuildFeed.Local")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3485b33a-6c3a-4535-9d85-4696914ad504")] [assembly: Guid("3485b33a-6c3a-4535-9d85-4696914ad504")]
// Version information for an assembly consists of the following four values: // Version information for an assembly consists of the following four values:
@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -2,20 +2,20 @@
namespace BuildFeed.Model.Api namespace BuildFeed.Model.Api
{ {
public class NewBuildPost public class NewBuildPost
{ {
public NewBuild[] NewBuilds { get; set; } public NewBuild[] NewBuilds { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string Username { get; set; } public string Username { get; set; }
} }
public class NewBuild public class NewBuild
{ {
public DateTime? BuildTime { get; set; } public DateTime? BuildTime { get; set; }
public string Lab { get; set; } public string Lab { get; set; }
public uint MajorVersion { get; set; } public uint MajorVersion { get; set; }
public uint MinorVersion { get; set; } public uint MinorVersion { get; set; }
public uint Number { get; set; } public uint Number { get; set; }
public uint? Revision { get; set; } public uint? Revision { get; set; }
} }
} }

View File

@ -1,10 +1,10 @@
namespace BuildFeed.Model.Api namespace BuildFeed.Model.Api
{ {
public class SearchResult public class SearchResult
{ {
public string Group { get; set; } public string Group { get; set; }
public string Label { get; set; } public string Label { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Url { get; set; } public string Url { get; set; }
} }
} }

View File

@ -11,205 +11,205 @@ using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
[DataObject] [DataObject]
[BsonIgnoreExtraElements] [BsonIgnoreExtraElements]
public class Build public class Build
{ {
[Key] [Key]
[BsonId] [BsonId]
public Guid Id { get; set; } public Guid Id { get; set; }
public long? LegacyId { get; set; } public long? LegacyId { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MajorVersion))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MajorVersion))]
public uint MajorVersion { get; set; } public uint MajorVersion { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MinorVersion))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MinorVersion))]
public uint MinorVersion { get; set; } public uint MinorVersion { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildNumber))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildNumber))]
public uint Number { get; set; } public uint Number { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Revision))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Revision))]
[DisplayFormat(ConvertEmptyStringToNull = true)] [DisplayFormat(ConvertEmptyStringToNull = true)]
public uint? Revision { get; set; } public uint? Revision { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_LabString))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_LabString))]
public string Lab { get; set; } public string Lab { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildTime))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildTime))]
[DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:yyMMdd-HHmm}")] [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true, DataFormatString = "{0:yyMMdd-HHmm}")]
public DateTime? BuildTime { get; set; } public DateTime? BuildTime { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Added))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Added))]
public DateTime Added { get; set; } public DateTime Added { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Modified))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Modified))]
public DateTime Modified { get; set; } public DateTime Modified { get; set; }
[@Required] [@Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_SourceType))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_SourceType))]
[EnumDataType(typeof(TypeOfSource))] [EnumDataType(typeof(TypeOfSource))]
public TypeOfSource SourceType { get; set; } public TypeOfSource SourceType { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_SourceDetails))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_SourceDetails))]
[AllowHtml] [AllowHtml]
public string SourceDetails { get; set; } public string SourceDetails { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_LeakDate))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_LeakDate))]
[DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true)] [DisplayFormat(ConvertEmptyStringToNull = true, ApplyFormatInEditMode = true)]
public DateTime? LeakDate { get; set; } public DateTime? LeakDate { get; set; }
public string LabUrl { get; set; } public string LabUrl { get; set; }
public bool IsLeaked => SourceType == TypeOfSource.PublicRelease || SourceType == TypeOfSource.InternalLeak || SourceType == TypeOfSource.UpdateGDR || SourceType == TypeOfSource.UpdateLDR; public bool IsLeaked => SourceType == TypeOfSource.PublicRelease || SourceType == TypeOfSource.InternalLeak || SourceType == TypeOfSource.UpdateGDR || SourceType == TypeOfSource.UpdateLDR;
public string FullBuildString { get; set; } public string FullBuildString { get; set; }
public string AlternateBuildString { get; set; } public string AlternateBuildString { get; set; }
public ProjectFamily Family public ProjectFamily Family
{ {
get get
{
if (Number >= 14800)
{ {
return ProjectFamily.Redstone2; if (Number >= 14800)
{
return ProjectFamily.Redstone2;
}
if (Number >= 11000)
{
return ProjectFamily.Redstone;
}
if (Number >= 10500)
{
return ProjectFamily.Threshold2;
}
if (Number >= 9700)
{
return ProjectFamily.Threshold;
}
if (Number >= 9250)
{
return ProjectFamily.Windows81;
}
if (Number >= 7650)
{
return ProjectFamily.Windows8;
}
if (Number >= 6020)
{
return ProjectFamily.Windows7;
}
if (MajorVersion == 6
&& Number >= 5000)
{
return ProjectFamily.WindowsVista;
}
if (MajorVersion == 6)
{
return ProjectFamily.Longhorn;
}
if (MajorVersion == 5
&& Number >= 3000)
{
return ProjectFamily.Server2003;
}
if (MajorVersion == 5
&& Number >= 2205)
{
return ProjectFamily.WindowsXP;
}
if (MajorVersion == 5
&& MinorVersion == 50)
{
return ProjectFamily.Neptune;
}
if (MajorVersion == 5)
{
return ProjectFamily.Windows2000;
}
return ProjectFamily.None;
} }
if (Number >= 11000) }
{
return ProjectFamily.Redstone;
}
if (Number >= 10500)
{
return ProjectFamily.Threshold2;
}
if (Number >= 9700)
{
return ProjectFamily.Threshold;
}
if (Number >= 9250)
{
return ProjectFamily.Windows81;
}
if (Number >= 7650)
{
return ProjectFamily.Windows8;
}
if (Number >= 6020)
{
return ProjectFamily.Windows7;
}
if (MajorVersion == 6
&& Number >= 5000)
{
return ProjectFamily.WindowsVista;
}
if (MajorVersion == 6)
{
return ProjectFamily.Longhorn;
}
if (MajorVersion == 5
&& Number >= 3000)
{
return ProjectFamily.Server2003;
}
if (MajorVersion == 5
&& Number >= 2205)
{
return ProjectFamily.WindowsXP;
}
if (MajorVersion == 5
&& MinorVersion == 50)
{
return ProjectFamily.Neptune;
}
if (MajorVersion == 5)
{
return ProjectFamily.Windows2000;
}
return ProjectFamily.None;
}
}
public string SourceDetailsFiltered public string SourceDetailsFiltered
{ {
get get
{
HtmlDocument hDoc = new HtmlDocument();
hDoc.LoadHtml($"<div>{SourceDetails}</div>");
if (string.IsNullOrWhiteSpace(hDoc.DocumentNode.InnerText))
{ {
return ""; HtmlDocument hDoc = new HtmlDocument();
hDoc.LoadHtml($"<div>{SourceDetails}</div>");
if (string.IsNullOrWhiteSpace(hDoc.DocumentNode.InnerText))
{
return "";
}
if (Uri.IsWellFormedUriString(hDoc.DocumentNode.InnerText, UriKind.Absolute))
{
Uri uri = new Uri(hDoc.DocumentNode.InnerText, UriKind.Absolute);
return $"<a href=\"{uri}\" target=\"_blank\">{VariantTerms.Model_ExternalLink} <i class=\"fa fa-external-link\"></i></a>";
}
return SourceDetails;
}
}
public string GenerateFullBuildString()
{
StringBuilder sb = new StringBuilder();
sb.Append($"{MajorVersion}.{MinorVersion}.{Number}");
if (Revision.HasValue)
{
sb.Append($".{Revision}");
} }
if (Uri.IsWellFormedUriString(hDoc.DocumentNode.InnerText, UriKind.Absolute)) if (!string.IsNullOrWhiteSpace(Lab))
{ {
Uri uri = new Uri(hDoc.DocumentNode.InnerText, UriKind.Absolute); sb.Append($".{Lab}");
return $"<a href=\"{uri}\" target=\"_blank\">{VariantTerms.Model_ExternalLink} <i class=\"fa fa-external-link\"></i></a>";
} }
return SourceDetails;
}
}
public string GenerateFullBuildString()
{
StringBuilder sb = new StringBuilder();
sb.Append($"{MajorVersion}.{MinorVersion}.{Number}");
if (Revision.HasValue)
{
sb.Append($".{Revision}");
}
if (!string.IsNullOrWhiteSpace(Lab))
{
sb.Append($".{Lab}");
}
if (BuildTime.HasValue)
{
sb.Append($".{BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)}");
}
return sb.ToString();
}
public string GenerateAlternateBuildString()
{
StringBuilder sb = new StringBuilder();
sb.Append($"{MajorVersion}.{MinorVersion}.{Number}");
if (Revision.HasValue)
{
sb.Append($".{Revision}");
}
if (!string.IsNullOrWhiteSpace(Lab))
{
sb.Append($" ({Lab}");
if (BuildTime.HasValue) if (BuildTime.HasValue)
{ {
sb.Append($".{BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)}"); sb.Append($".{BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)}");
} }
sb.Append(")"); return sb.ToString();
} }
return sb.ToString(); public string GenerateAlternateBuildString()
} {
StringBuilder sb = new StringBuilder();
sb.Append($"{MajorVersion}.{MinorVersion}.{Number}");
public string GenerateLabUrl() => !string.IsNullOrEmpty(Lab) if (Revision.HasValue)
? Lab.Replace('/', '-').ToLower() {
: ""; sb.Append($".{Revision}");
} }
if (!string.IsNullOrWhiteSpace(Lab))
{
sb.Append($" ({Lab}");
if (BuildTime.HasValue)
{
sb.Append($".{BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)}");
}
sb.Append(")");
}
return sb.ToString();
}
public string GenerateLabUrl() => !string.IsNullOrEmpty(Lab)
? Lab.Replace('/', '-').ToLower()
: "";
}
} }

View File

@ -1,14 +1,14 @@
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public struct BuildGroup public struct BuildGroup
{ {
public uint Major { get; set; } public uint Major { get; set; }
public uint Minor { get; set; } public uint Minor { get; set; }
public uint Build { get; set; } public uint Build { get; set; }
public uint? Revision { get; set; } public uint? Revision { get; set; }
public override string ToString() => Revision.HasValue public override string ToString() => Revision.HasValue
? $"{Major}.{Minor}.{Build}.{Revision.Value}" ? $"{Major}.{Minor}.{Build}.{Revision.Value}"
: $"{Major}.{Minor}.{Build}"; : $"{Major}.{Minor}.{Build}";
} }
} }

View File

@ -7,95 +7,95 @@ using MongoDB.Driver;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public partial class BuildRepository public partial class BuildRepository
{ {
public async Task<FrontBuildGroup[]> SelectAllGroups(int limit = -1, int skip = 0) public async Task<FrontBuildGroup[]> SelectAllGroups(int limit = -1, int skip = 0)
{ {
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument
{ {
new BsonElement("_id", new BsonElement("_id",
new BsonDocument new BsonDocument
{
new BsonElement(nameof(BuildGroup.Major), $"${nameof(Build.MajorVersion)}"),
new BsonElement(nameof(BuildGroup.Minor), $"${nameof(Build.MinorVersion)}"),
new BsonElement(nameof(BuildGroup.Build), $"${nameof(Build.Number)}"),
new BsonElement(nameof(BuildGroup.Revision), $"${nameof(Build.Revision)}")
}),
new BsonElement("date", new BsonDocument("$max", $"${nameof(Build.BuildTime)}")),
new BsonElement("count", new BsonDocument("$sum", 1))
}).Sort(new BsonDocument
{
new BsonElement($"_id.{nameof(BuildGroup.Major)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Minor)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Build)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Revision)}", -1)
}).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
List<BsonDocument> grouping = await query.ToListAsync();
return (from g in grouping
select new FrontBuildGroup
{
Key = new BuildGroup
{ {
Major = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Major)].AsInt32, new BsonElement(nameof(BuildGroup.Major), $"${nameof(Build.MajorVersion)}"),
Minor = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Minor)].AsInt32, new BsonElement(nameof(BuildGroup.Minor), $"${nameof(Build.MinorVersion)}"),
Build = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Build)].AsInt32, new BsonElement(nameof(BuildGroup.Build), $"${nameof(Build.Number)}"),
Revision = (uint?)g["_id"].AsBsonDocument[nameof(BuildGroup.Revision)].AsNullableInt32 new BsonElement(nameof(BuildGroup.Revision), $"${nameof(Build.Revision)}")
}, }),
LastBuild = g["date"].ToNullableUniversalTime(), new BsonElement("date", new BsonDocument("$max", $"${nameof(Build.BuildTime)}")),
BuildCount = g["count"].AsInt32 new BsonElement("count", new BsonDocument("$sum", 1))
}).ToArray(); }).Sort(new BsonDocument
} {
new BsonElement($"_id.{nameof(BuildGroup.Major)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Minor)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Build)}", -1),
new BsonElement($"_id.{nameof(BuildGroup.Revision)}", -1)
}).Skip(skip);
public async Task<long> SelectAllGroupsCount() if (limit > 0)
{ {
List<BsonDocument> grouping = await _buildCollection.Aggregate().Group(new BsonDocument query = query.Limit(limit);
{ }
new BsonElement("_id",
new BsonDocument
{
new BsonElement(nameof(BuildGroup.Major), $"${nameof(Build.MajorVersion)}"),
new BsonElement(nameof(BuildGroup.Minor), $"${nameof(Build.MinorVersion)}"),
new BsonElement(nameof(BuildGroup.Build), $"${nameof(Build.Number)}"),
new BsonElement(nameof(BuildGroup.Revision), $"${nameof(Build.Revision)}")
})
}).ToListAsync();
return grouping.Count;
}
public async Task<List<Build>> SelectGroup(BuildGroup group, int limit = -1, int skip = 0) List<BsonDocument> grouping = await query.ToListAsync();
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument return (from g in grouping
{ select new FrontBuildGroup
{
Key = new BuildGroup
{
Major = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Major)].AsInt32,
Minor = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Minor)].AsInt32,
Build = (uint)g["_id"].AsBsonDocument[nameof(BuildGroup.Build)].AsInt32,
Revision = (uint?)g["_id"].AsBsonDocument[nameof(BuildGroup.Revision)].AsNullableInt32
},
LastBuild = g["date"].ToNullableUniversalTime(),
BuildCount = g["count"].AsInt32
}).ToArray();
}
public async Task<long> SelectAllGroupsCount()
{
List<BsonDocument> grouping = await _buildCollection.Aggregate().Group(new BsonDocument
{
new BsonElement("_id",
new BsonDocument
{
new BsonElement(nameof(BuildGroup.Major), $"${nameof(Build.MajorVersion)}"),
new BsonElement(nameof(BuildGroup.Minor), $"${nameof(Build.MinorVersion)}"),
new BsonElement(nameof(BuildGroup.Build), $"${nameof(Build.Number)}"),
new BsonElement(nameof(BuildGroup.Revision), $"${nameof(Build.Revision)}")
})
}).ToListAsync();
return grouping.Count;
}
public async Task<List<Build>> SelectGroup(BuildGroup group, int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), group.Major),
new BsonElement(nameof(Build.MinorVersion), group.Minor),
new BsonElement(nameof(Build.Number), group.Build),
new BsonElement(nameof(Build.Revision), group.Revision)
}).Sort(new BsonDocument
{
new BsonElement(nameof(Build.BuildTime), 1)
}).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
public async Task<long> SelectGroupCount(BuildGroup group) => await _buildCollection.CountAsync(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), group.Major), new BsonElement(nameof(Build.MajorVersion), group.Major),
new BsonElement(nameof(Build.MinorVersion), group.Minor), new BsonElement(nameof(Build.MinorVersion), group.Minor),
new BsonElement(nameof(Build.Number), group.Build), new BsonElement(nameof(Build.Number), group.Build),
new BsonElement(nameof(Build.Revision), group.Revision) new BsonElement(nameof(Build.Revision), group.Revision)
}).Sort(new BsonDocument });
{ }
new BsonElement(nameof(Build.BuildTime), 1)
}).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
public async Task<long> SelectGroupCount(BuildGroup group) => await _buildCollection.CountAsync(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), @group.Major),
new BsonElement(nameof(Build.MinorVersion), @group.Minor),
new BsonElement(nameof(Build.Number), @group.Build),
new BsonElement(nameof(Build.Revision), @group.Revision)
});
}
} }

View File

@ -7,70 +7,70 @@ using MongoDB.Driver;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public partial class BuildRepository public partial class BuildRepository
{ {
public async Task<string[]> SelectAllLabs(int limit = -1, int skip = 0) public async Task<string[]> SelectAllLabs(int limit = -1, int skip = 0)
{ {
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id", $"${nameof(Build.Lab)}")).Sort(new BsonDocument("_id", 1)).Skip(skip); IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id", $"${nameof(Build.Lab)}")).Sort(new BsonDocument("_id", 1)).Skip(skip);
if (limit > 0) if (limit > 0)
{ {
query = query.Limit(limit); query = query.Limit(limit);
} }
List<BsonDocument> grouping = await query.ToListAsync(); List<BsonDocument> grouping = await query.ToListAsync();
return (from g in grouping return (from g in grouping
where !g["_id"].IsBsonNull where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray(); select g["_id"].AsString).ToArray();
} }
public async Task<string[]> SelectLabsForVersion(int major, int minor) public async Task<string[]> SelectLabsForVersion(int major, int minor)
{ {
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Match(new BsonDocument IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Match(new BsonDocument
{ {
new BsonElement(nameof(Build.MajorVersion), major), new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor) new BsonElement(nameof(Build.MinorVersion), minor)
}).Group(new BsonDocument("_id", $"${nameof(Build.Lab)}")).Sort(new BsonDocument("_id", 1)); }).Group(new BsonDocument("_id", $"${nameof(Build.Lab)}")).Sort(new BsonDocument("_id", 1));
List<BsonDocument> grouping = await query.ToListAsync(); List<BsonDocument> grouping = await query.ToListAsync();
return (from g in grouping return (from g in grouping
where !g["_id"].IsBsonNull where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray(); select g["_id"].AsString).ToArray();
} }
public async Task<List<string>> SearchLabs(string search) public async Task<List<string>> SearchLabs(string search)
{ {
List<Tuple<string>> result = await _buildCollection.Aggregate().Match(b => b.Lab != null).Match(b => b.Lab != "").Match(b => b.Lab.ToLower().Contains(search.ToLower())).Group(b => b.Lab.ToLower(), List<Tuple<string>> result = await _buildCollection.Aggregate().Match(b => b.Lab != null).Match(b => b.Lab != "").Match(b => b.Lab.ToLower().Contains(search.ToLower())).Group(b => b.Lab.ToLower(),
// incoming bullshit hack // incoming bullshit hack
bg => new Tuple<string>(bg.Key)).ToListAsync(); bg => new Tuple<string>(bg.Key)).ToListAsync();
// work ourselves out of aforementioned bullshit hack // work ourselves out of aforementioned bullshit hack
return result.Select(b => b.Item1).ToList(); return result.Select(b => b.Item1).ToList();
} }
public async Task<long> SelectAllLabsCount() public async Task<long> SelectAllLabsCount()
{ {
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id", new BsonDocument(nameof(Build.Lab), $"${nameof(Build.Lab)}"))).Sort(new BsonDocument("_id", 1)); IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id", new BsonDocument(nameof(Build.Lab), $"${nameof(Build.Lab)}"))).Sort(new BsonDocument("_id", 1));
List<BsonDocument> grouping = await query.ToListAsync(); List<BsonDocument> grouping = await query.ToListAsync();
return grouping.Count; return grouping.Count;
} }
public async Task<List<Build>> SelectLab(string lab, int limit = -1, int skip = 0) public async Task<List<Build>> SelectLab(string lab, int limit = -1, int skip = 0)
{ {
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument(nameof(Build.LabUrl), lab)).Sort(sortByCompileDate).Skip(skip); IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument(nameof(Build.LabUrl), lab)).Sort(sortByCompileDate).Skip(skip);
if (limit > 0) if (limit > 0)
{ {
query = query.Limit(limit); query = query.Limit(limit);
} }
return await query.ToListAsync(); return await query.ToListAsync();
} }
public async Task<long> SelectLabCount(string lab) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.LabUrl), lab)); public async Task<long> SelectLabCount(string lab) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.LabUrl), lab));
} }
} }

View File

@ -6,24 +6,24 @@ using MongoDB.Driver;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public partial class BuildRepository public partial class BuildRepository
{ {
public Task<TypeOfSource[]> SelectAllSources(int limit = -1, int skip = 0) => Task.Run(() => Enum.GetValues(typeof(TypeOfSource)) as TypeOfSource[]); public Task<TypeOfSource[]> SelectAllSources(int limit = -1, int skip = 0) => Task.Run(() => Enum.GetValues(typeof(TypeOfSource)) as TypeOfSource[]);
public Task<long> SelectAllSourcesCount() => Task.Run(() => Enum.GetValues(typeof(TypeOfSource)).LongLength); public Task<long> SelectAllSourcesCount() => Task.Run(() => Enum.GetValues(typeof(TypeOfSource)).LongLength);
public async Task<List<Build>> SelectSource(TypeOfSource source, int limit = -1, int skip = 0) public async Task<List<Build>> SelectSource(TypeOfSource source, int limit = -1, int skip = 0)
{ {
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument(nameof(Build.SourceType), source)).Sort(sortByOrder).Skip(skip); IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument(nameof(Build.SourceType), source)).Sort(sortByOrder).Skip(skip);
if (limit > 0) if (limit > 0)
{ {
query = query.Limit(limit); query = query.Limit(limit);
} }
return await query.ToListAsync(); return await query.ToListAsync();
} }
public async Task<long> SelectSourceCount(TypeOfSource source) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.SourceType), source)); public async Task<long> SelectSourceCount(TypeOfSource source) => await _buildCollection.CountAsync(new BsonDocument(nameof(Build.SourceType), source));
} }
} }

View File

@ -6,67 +6,67 @@ using MongoDB.Driver;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public partial class BuildRepository public partial class BuildRepository
{ {
public async Task<BuildVersion[]> SelectAllVersions(int limit = -1, int skip = 0) public async Task<BuildVersion[]> SelectAllVersions(int limit = -1, int skip = 0)
{ {
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id", IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id",
new BsonDocument new BsonDocument
{
new BsonElement(nameof(BuildVersion.Major), $"${nameof(Build.MajorVersion)}"),
new BsonElement(nameof(BuildVersion.Minor), $"${nameof(Build.MinorVersion)}")
})).Sort(new BsonDocument
{ {
new BsonElement(nameof(BuildVersion.Major), $"${nameof(Build.MajorVersion)}"), new BsonElement($"_id.{nameof(BuildVersion.Major)}", -1),
new BsonElement(nameof(BuildVersion.Minor), $"${nameof(Build.MinorVersion)}") new BsonElement($"_id.{nameof(BuildVersion.Minor)}", -1)
})).Sort(new BsonDocument }).Skip(skip);
{
new BsonElement($"_id.{nameof(BuildVersion.Major)}", -1),
new BsonElement($"_id.{nameof(BuildVersion.Minor)}", -1)
}).Skip(skip);
if (limit > 0) if (limit > 0)
{
query = query.Limit(limit);
}
List<BsonDocument> grouping = await query.ToListAsync();
return (from g in grouping
select new BuildVersion
{
Major = (uint)g["_id"].AsBsonDocument[nameof(BuildVersion.Major)].AsInt32,
Minor = (uint)g["_id"].AsBsonDocument[nameof(BuildVersion.Minor)].AsInt32
}).ToArray();
}
public async Task<long> SelectAllVersionsCount()
{
List<BsonDocument> query = await _buildCollection.Aggregate().Group(new BsonDocument("_id",
new BsonDocument
{ {
new BsonElement(nameof(BuildVersion.Major), $"${nameof(Build.MajorVersion)}"), query = query.Limit(limit);
new BsonElement(nameof(BuildVersion.Minor), $"${nameof(Build.MinorVersion)}") }
})).ToListAsync();
return query.Count;
}
public async Task<List<Build>> SelectVersion(uint major, uint minor, int limit = -1, int skip = 0) List<BsonDocument> grouping = await query.ToListAsync();
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument return (from g in grouping
{ select new BuildVersion
{
Major = (uint)g["_id"].AsBsonDocument[nameof(BuildVersion.Major)].AsInt32,
Minor = (uint)g["_id"].AsBsonDocument[nameof(BuildVersion.Minor)].AsInt32
}).ToArray();
}
public async Task<long> SelectAllVersionsCount()
{
List<BsonDocument> query = await _buildCollection.Aggregate().Group(new BsonDocument("_id",
new BsonDocument
{
new BsonElement(nameof(BuildVersion.Major), $"${nameof(Build.MajorVersion)}"),
new BsonElement(nameof(BuildVersion.Minor), $"${nameof(Build.MinorVersion)}")
})).ToListAsync();
return query.Count;
}
public async Task<List<Build>> SelectVersion(uint major, uint minor, int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor)
}).Sort(sortByOrder).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
public async Task<long> SelectVersionCount(uint major, uint minor) => await _buildCollection.CountAsync(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major), new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor) new BsonElement(nameof(Build.MinorVersion), minor)
}).Sort(sortByOrder).Skip(skip); });
}
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
public async Task<long> SelectVersionCount(uint major, uint minor) => await _buildCollection.CountAsync(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor)
});
}
} }

View File

@ -7,54 +7,54 @@ using MongoDB.Driver;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public partial class BuildRepository public partial class BuildRepository
{ {
public async Task<int[]> SelectAllYears(int limit = -1, int skip = 0) public async Task<int[]> SelectAllYears(int limit = -1, int skip = 0)
{ {
IAggregateFluent<BsonDocument> query = IAggregateFluent<BsonDocument> query =
_buildCollection.Aggregate() _buildCollection.Aggregate()
.Match(Builders<Build>.Filter.Ne(b => b.BuildTime, null)) .Match(Builders<Build>.Filter.Ne(b => b.BuildTime, null))
.Group(new BsonDocument("_id", new BsonDocument("$year", $"${nameof(Build.BuildTime)}"))) .Group(new BsonDocument("_id", new BsonDocument("$year", $"${nameof(Build.BuildTime)}")))
.Sort(new BsonDocument("_id", -1)) .Sort(new BsonDocument("_id", -1))
.Skip(skip); .Skip(skip);
if (limit > 0) if (limit > 0)
{ {
query = query.Limit(limit); query = query.Limit(limit);
} }
List<BsonDocument> grouping = await query.ToListAsync(); List<BsonDocument> grouping = await query.ToListAsync();
return (from g in grouping return (from g in grouping
where !g["_id"].IsBsonNull where !g["_id"].IsBsonNull
select g["_id"].AsInt32).ToArray(); select g["_id"].AsInt32).ToArray();
} }
public async Task<long> SelectAllYearsCount() public async Task<long> SelectAllYearsCount()
{ {
List<BsonDocument> query = await _buildCollection.Aggregate().Match(Builders<Build>.Filter.Ne(b => b.BuildTime, null)).Group(new BsonDocument("_id", new BsonDocument("$year", $"${nameof(Build.BuildTime)}"))).ToListAsync(); List<BsonDocument> query = await _buildCollection.Aggregate().Match(Builders<Build>.Filter.Ne(b => b.BuildTime, null)).Group(new BsonDocument("_id", new BsonDocument("$year", $"${nameof(Build.BuildTime)}"))).ToListAsync();
return query.Count; return query.Count;
} }
public async Task<List<Build>> SelectYear(int year, int limit = -1, int skip = 0) public async Task<List<Build>> SelectYear(int year, int limit = -1, int skip = 0)
{ {
IFindFluent<Build, Build> query = IFindFluent<Build, Build> query =
_buildCollection.Find(Builders<Build>.Filter.And(Builders<Build>.Filter.Gte(b => b.BuildTime, new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc)), _buildCollection.Find(Builders<Build>.Filter.And(Builders<Build>.Filter.Gte(b => b.BuildTime, new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
Builders<Build>.Filter.Lte(b => b.BuildTime, new DateTime(year, 12, 31, 23, 59, 59, DateTimeKind.Utc)))).Sort(sortByCompileDate).Skip(skip); Builders<Build>.Filter.Lte(b => b.BuildTime, new DateTime(year, 12, 31, 23, 59, 59, DateTimeKind.Utc)))).Sort(sortByCompileDate).Skip(skip);
if (limit > 0) if (limit > 0)
{ {
query = query.Limit(limit); query = query.Limit(limit);
} }
return await query.ToListAsync(); return await query.ToListAsync();
} }
public async Task<long> SelectYearCount(int year) public async Task<long> SelectYearCount(int year)
=> =>
await await
_buildCollection.CountAsync(Builders<Build>.Filter.And(Builders<Build>.Filter.Gte(b => b.BuildTime, new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc)), _buildCollection.CountAsync(Builders<Build>.Filter.And(Builders<Build>.Filter.Gte(b => b.BuildTime, new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
Builders<Build>.Filter.Lte(b => b.BuildTime, new DateTime(year, 12, 31, 23, 59, 59, DateTimeKind.Utc)))); Builders<Build>.Filter.Lte(b => b.BuildTime, new DateTime(year, 12, 31, 23, 59, 59, DateTimeKind.Utc))));
} }
} }

View File

@ -1,16 +1,16 @@
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public struct BuildVersion public struct BuildVersion
{ {
public uint Major { get; set; } public uint Major { get; set; }
public uint Minor { get; set; } public uint Minor { get; set; }
public BuildVersion(uint major, uint minor) public BuildVersion(uint major, uint minor)
{ {
Major = major; Major = major;
Minor = minor; Minor = minor;
} }
public override string ToString() => $"{Major}.{Minor}"; public override string ToString() => $"{Major}.{Minor}";
} }
} }

View File

@ -12,156 +12,156 @@ using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
[DataObject] [DataObject]
public class MetaItemModel public class MetaItemModel
{ {
[Key] [Key]
[BsonId] [BsonId]
[@Required] [@Required]
public MetaItemKey Id { get; set; } public MetaItemKey Id { get; set; }
[DisplayName("Meta Description")] [DisplayName("Meta Description")]
public string MetaDescription { get; set; } public string MetaDescription { get; set; }
[DisplayName("Page Content")] [DisplayName("Page Content")]
[AllowHtml] [AllowHtml]
public string PageContent { get; set; } public string PageContent { get; set; }
} }
public class MetaItem public class MetaItem
{ {
private const string META_COLLECTION_NAME = "metaitem"; private const string META_COLLECTION_NAME = "metaitem";
private readonly BuildRepository _bModel; private readonly BuildRepository _bModel;
private readonly IMongoCollection<MetaItemModel> _metaCollection; private readonly IMongoCollection<MetaItemModel> _metaCollection;
public MetaItem() public MetaItem()
{ {
MongoClientSettings settings = new MongoClientSettings MongoClientSettings settings = new MongoClientSettings
{
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
};
if (!string.IsNullOrEmpty(MongoConfig.Username) && !string.IsNullOrEmpty(MongoConfig.Password))
{
settings.Credentials = new List<MongoCredential>
{ {
MongoCredential.CreateCredential(MongoConfig.Database, MongoConfig.Username, MongoConfig.Password) Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
}; };
}
MongoClient dbClient = new MongoClient(settings); if (!string.IsNullOrEmpty(MongoConfig.Username) && !string.IsNullOrEmpty(MongoConfig.Password))
{
settings.Credentials = new List<MongoCredential>
{
MongoCredential.CreateCredential(MongoConfig.Database, MongoConfig.Username, MongoConfig.Password)
};
}
_metaCollection = dbClient.GetDatabase(MongoConfig.Database).GetCollection<MetaItemModel>(META_COLLECTION_NAME); MongoClient dbClient = new MongoClient(settings);
_bModel = new BuildRepository();
}
[DataObjectMethod(DataObjectMethodType.Select, false)] _metaCollection = dbClient.GetDatabase(MongoConfig.Database).GetCollection<MetaItemModel>(META_COLLECTION_NAME);
public async Task<IEnumerable<MetaItemModel>> Select() _bModel = new BuildRepository();
{ }
return await _metaCollection.Find(new BsonDocument()).ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, true)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<MetaItemModel>> SelectByType(MetaType type) public async Task<IEnumerable<MetaItemModel>> Select()
{ {
return await _metaCollection.Find(f => f.Id.Type == type).ToListAsync(); return await _metaCollection.Find(new BsonDocument()).ToListAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<MetaItemModel> SelectById(MetaItemKey id) public async Task<IEnumerable<MetaItemModel>> SelectByType(MetaType type)
{ {
return await _metaCollection.Find(f => (f.Id.Type == id.Type) && (f.Id.Value == id.Value)).SingleOrDefaultAsync(); return await _metaCollection.Find(f => f.Id.Type == type).ToListAsync();
} }
[DataObjectMethod(DataObjectMethodType.Select, false)] [DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedLabs() public async Task<MetaItemModel> SelectById(MetaItemKey id)
{ {
string[] labs = await _bModel.SelectAllLabs(); return await _metaCollection.Find(f => f.Id.Type == id.Type && f.Id.Value == id.Value).SingleOrDefaultAsync();
}
List<MetaItemModel> usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync(); [DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedLabs()
{
string[] labs = await _bModel.SelectAllLabs();
return from l in labs List<MetaItemModel> usedLabs = await _metaCollection.Find(f => f.Id.Type == MetaType.Lab).ToListAsync();
where usedLabs.All(ul => ul.Id.Value != l)
select l;
}
[DataObjectMethod(DataObjectMethodType.Select, false)] return from l in labs
public async Task<IEnumerable<string>> SelectUnusedVersions() where usedLabs.All(ul => ul.Id.Value != l)
{ select l;
BuildVersion[] versions = await _bModel.SelectAllVersions(); }
List<MetaItemModel> usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync(); [DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedVersions()
{
BuildVersion[] versions = await _bModel.SelectAllVersions();
return from v in versions List<MetaItemModel> usedVersions = await _metaCollection.Find(f => f.Id.Type == MetaType.Version).ToListAsync();
where usedVersions.All(ul => ul.Id.Value != v.ToString())
select v.ToString();
}
[DataObjectMethod(DataObjectMethodType.Select, false)] return from v in versions
public async Task<IEnumerable<string>> SelectUnusedYears() where usedVersions.All(ul => ul.Id.Value != v.ToString())
{ select v.ToString();
int[] years = await _bModel.SelectAllYears(); }
List<MetaItemModel> usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync(); [DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<IEnumerable<string>> SelectUnusedYears()
{
int[] years = await _bModel.SelectAllYears();
return from y in years List<MetaItemModel> usedYears = await _metaCollection.Find(f => f.Id.Type == MetaType.Year).ToListAsync();
where usedYears.All(ul => ul.Id.Value != y.ToString())
select y.ToString();
}
[DataObjectMethod(DataObjectMethodType.Insert, true)] return from y in years
public async Task Insert(MetaItemModel item) where usedYears.All(ul => ul.Id.Value != y.ToString())
{ select y.ToString();
await _metaCollection.InsertOneAsync(item); }
}
[DataObjectMethod(DataObjectMethodType.Update, true)] [DataObjectMethod(DataObjectMethodType.Insert, true)]
public async Task Update(MetaItemModel item) public async Task Insert(MetaItemModel item)
{ {
await _metaCollection.ReplaceOneAsync(f => (f.Id.Type == item.Id.Type) && (f.Id.Value == item.Id.Value), item); await _metaCollection.InsertOneAsync(item);
} }
[DataObjectMethod(DataObjectMethodType.Insert, false)] [DataObjectMethod(DataObjectMethodType.Update, true)]
public async Task InsertAll(IEnumerable<MetaItemModel> items) public async Task Update(MetaItemModel item)
{ {
await _metaCollection.InsertManyAsync(items); await _metaCollection.ReplaceOneAsync(f => f.Id.Type == item.Id.Type && f.Id.Value == item.Id.Value, item);
} }
[DataObjectMethod(DataObjectMethodType.Delete, true)] [DataObjectMethod(DataObjectMethodType.Insert, false)]
public async Task DeleteById(MetaItemKey id) public async Task InsertAll(IEnumerable<MetaItemModel> items)
{ {
await _metaCollection.DeleteOneAsync(f => (f.Id.Type == id.Type) && (f.Id.Value == id.Value)); await _metaCollection.InsertManyAsync(items);
} }
}
public class MetaItemKey [DataObjectMethod(DataObjectMethodType.Delete, true)]
{ public async Task DeleteById(MetaItemKey id)
public MetaType Type { get; set; } {
public string Value { get; set; } await _metaCollection.DeleteOneAsync(f => f.Id.Type == id.Type && f.Id.Value == id.Value);
}
}
public MetaItemKey() public class MetaItemKey
{ {
} public MetaType Type { get; set; }
public string Value { get; set; }
public MetaItemKey(string id) public MetaItemKey()
{ {
string[] items = id.Split(':'); }
Type = (MetaType)Enum.Parse(typeof(MetaType), items[0]);
Value = items[1];
}
public override string ToString() public MetaItemKey(string id)
{ {
return $"{Type}:{Value}"; string[] items = id.Split(':');
} Type = (MetaType)Enum.Parse(typeof(MetaType), items[0]);
} Value = items[1];
}
public enum MetaType public override string ToString()
{ {
Lab, return $"{Type}:{Value}";
Version, }
Source, }
Year
} public enum MetaType
{
Lab,
Version,
Source,
Year
}
} }

View File

@ -2,40 +2,40 @@
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public static class MongoConfig public static class MongoConfig
{ {
public static string Host { get; } public static string Host { get; }
public static int Port { get; } public static int Port { get; }
public static string Database { get; } public static string Database { get; }
public static string Username { get; } public static string Username { get; }
public static string Password { get; } public static string Password { get; }
static MongoConfig() static MongoConfig()
{ {
Host = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoHost"]) Host = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoHost"])
? ConfigurationManager.AppSettings["data:MongoHost"] ? ConfigurationManager.AppSettings["data:MongoHost"]
: "localhost"; : "localhost";
int _port; int _port;
bool success = int.TryParse(ConfigurationManager.AppSettings["data:MongoPort"], out _port); bool success = int.TryParse(ConfigurationManager.AppSettings["data:MongoPort"], out _port);
if (!success) if (!success)
{ {
_port = 27017; // mongo default port _port = 27017; // mongo default port
} }
Port = _port; Port = _port;
Database = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoDB"]) Database = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoDB"])
? ConfigurationManager.AppSettings["data:MongoDB"] ? ConfigurationManager.AppSettings["data:MongoDB"]
: "MongoAuth"; : "MongoAuth";
Username = ConfigurationManager.AppSettings["data:MongoUser"] ?? ""; Username = ConfigurationManager.AppSettings["data:MongoUser"] ?? "";
Password = ConfigurationManager.AppSettings["data:MongoPass"] ?? ""; Password = ConfigurationManager.AppSettings["data:MongoPass"] ?? "";
} }
public static void SetupIndexes() public static void SetupIndexes()
{ {
BuildRepository b = new BuildRepository(); BuildRepository b = new BuildRepository();
b.SetupIndexes(); b.SetupIndexes();
} }
} }
} }

View File

@ -2,47 +2,47 @@
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public enum ProjectFamily public enum ProjectFamily
{ {
None, None,
[Display(Name = "Windows 2000")] [Display(Name = "Windows 2000")]
Windows2000, Windows2000,
[Display(Name = "Neptune")] [Display(Name = "Neptune")]
Neptune, Neptune,
[Display(Name = "Windows XP")] [Display(Name = "Windows XP")]
WindowsXP, WindowsXP,
[Display(Name = "Server 2003")] [Display(Name = "Server 2003")]
Server2003, Server2003,
[Display(Name = "Longhorn")] [Display(Name = "Longhorn")]
Longhorn, Longhorn,
[Display(Name = "Vista")] [Display(Name = "Vista")]
WindowsVista, WindowsVista,
[Display(Name = "Windows 7")] [Display(Name = "Windows 7")]
Windows7, Windows7,
[Display(Name = "Windows 8")] [Display(Name = "Windows 8")]
Windows8, Windows8,
[Display(Name = "Windows 8.1")] [Display(Name = "Windows 8.1")]
Windows81, Windows81,
[Display(Name = "Threshold")] [Display(Name = "Threshold")]
Threshold, Threshold,
[Display(Name = "Threshold 2")] [Display(Name = "Threshold 2")]
Threshold2, Threshold2,
[Display(Name = "Redstone")] [Display(Name = "Redstone")]
Redstone, Redstone,
[Display(Name = "Redstone 2")] [Display(Name = "Redstone 2")]
Redstone2 Redstone2
} }
} }

View File

@ -1,10 +1,10 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("BuildFeed.Model")] [assembly: AssemblyTitle("BuildFeed.Model")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7e2b4f61-1c11-4471-af80-5480e94c0664")] [assembly: Guid("7e2b4f61-1c11-4471-af80-5480e94c0664")]
// Version information for an assembly consists of the following four values: // Version information for an assembly consists of the following four values:
@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -3,33 +3,33 @@ using BuildFeed.Local;
namespace BuildFeed.Model namespace BuildFeed.Model
{ {
public enum TypeOfSource public enum TypeOfSource
{ {
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_PublicRelease))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_PublicRelease))]
PublicRelease = 0, PublicRelease = 0,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_InternalLeak))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_InternalLeak))]
InternalLeak = 1, InternalLeak = 1,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_UpdateGDR))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_UpdateGDR))]
UpdateGDR = 2, UpdateGDR = 2,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_UpdateLDR))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_UpdateLDR))]
UpdateLDR = 3, UpdateLDR = 3,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_AppPackage))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_AppPackage))]
AppPackage = 4, AppPackage = 4,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_BuildTools))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_BuildTools))]
BuildTools = 5, BuildTools = 5,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_Documentation))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_Documentation))]
Documentation = 6, Documentation = 6,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_Logging))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_Logging))]
Logging = 7, Logging = 7,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_PrivateLeak))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Source_PrivateLeak))]
PrivateLeak = 8 PrivateLeak = 8
} }
} }

View File

@ -3,22 +3,22 @@ using BuildFeed.Local;
namespace BuildFeed.Model.View namespace BuildFeed.Model.View
{ {
public class ChangePassword public class ChangePassword
{ {
[Required] [Required]
[MinLength(8)] [MinLength(8)]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_ConfirmNewPassword))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_ConfirmNewPassword))]
[Compare("NewPassword")] [Compare("NewPassword")]
public string ConfirmNewPassword { get; set; } public string ConfirmNewPassword { get; set; }
[Required] [Required]
[MinLength(8)] [MinLength(8)]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterNewPassword))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterNewPassword))]
public string NewPassword { get; set; } public string NewPassword { get; set; }
[Required] [Required]
[MinLength(8)] [MinLength(8)]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterCurrentPassword))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterCurrentPassword))]
public string OldPassword { get; set; } public string OldPassword { get; set; }
} }
} }

View File

@ -2,10 +2,10 @@
namespace BuildFeed.Model.View namespace BuildFeed.Model.View
{ {
public class FrontBuildGroup public class FrontBuildGroup
{ {
public int BuildCount { get; set; } public int BuildCount { get; set; }
public BuildGroup Key { get; set; } public BuildGroup Key { get; set; }
public DateTime? LastBuild { get; set; } public DateTime? LastBuild { get; set; }
} }
} }

View File

@ -3,17 +3,17 @@ using BuildFeed.Local;
namespace BuildFeed.Model.View namespace BuildFeed.Model.View
{ {
public class LoginUser public class LoginUser
{ {
[Required] [Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_UserName))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_UserName))]
public string UserName { get; set; } public string UserName { get; set; }
[Required] [Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_Password))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_Password))]
public string Password { get; set; } public string Password { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_RememberMe))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_RememberMe))]
public bool RememberMe { get; set; } public bool RememberMe { get; set; }
} }
} }

View File

@ -3,26 +3,26 @@ using BuildFeed.Local;
namespace BuildFeed.Model.View namespace BuildFeed.Model.View
{ {
public class RegistrationUser public class RegistrationUser
{ {
[Required] [Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_UserName))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_UserName))]
public string UserName { get; set; } public string UserName { get; set; }
[Required] [Required]
[EmailAddress] [EmailAddress]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EmailAddress))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EmailAddress))]
public string EmailAddress { get; set; } public string EmailAddress { get; set; }
[Required] [Required]
[MinLength(8)] [MinLength(8)]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterPassword))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_EnterPassword))]
public string Password { get; set; } public string Password { get; set; }
[Required] [Required]
[MinLength(8)] [MinLength(8)]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_ConfirmPassword))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Support_ConfirmPassword))]
[Compare(nameof(Password))] [Compare(nameof(Password))]
public string ConfirmPassword { get; set; } public string ConfirmPassword { get; set; }
} }
} }

View File

@ -4,35 +4,35 @@ using System.Web.Routing;
namespace BuildFeed.Model.View namespace BuildFeed.Model.View
{ {
public class SitemapData public class SitemapData
{ {
public Dictionary<string, SitemapPagedAction[]> Actions { get; set; } public Dictionary<string, SitemapPagedAction[]> Actions { get; set; }
public SitemapDataBuildGroup[] Builds { get; set; } public SitemapDataBuildGroup[] Builds { get; set; }
public string[] Labs { get; set; } public string[] Labs { get; set; }
} }
public class SitemapDataBuildGroup public class SitemapDataBuildGroup
{ {
public SitemapDataBuild[] Builds { get; set; } public SitemapDataBuild[] Builds { get; set; }
public BuildGroup Id { get; set; } public BuildGroup Id { get; set; }
} }
public class SitemapDataBuild public class SitemapDataBuild
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
} }
public class SitemapPagedAction public class SitemapPagedAction
{ {
public string Action => UrlParams["action"].ToString(); public string Action => UrlParams["action"].ToString();
public string Name { get; set; } public string Name { get; set; }
public int Pages { get; set; } public int Pages { get; set; }
public string UniqueId => UrlParams.GetHashCode().ToString("X8").ToLower(); public string UniqueId => UrlParams.GetHashCode().ToString("X8").ToLower();
public RouteValueDictionary UrlParams { get; set; } public RouteValueDictionary UrlParams { get; set; }
} }
} }

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<runtime> <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
</configuration> </configuration>

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net462" /> <package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net462" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net462" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net462" /> <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net462" />
<package id="MongoDB.Bson" version="2.4.1" targetFramework="net462" /> <package id="MongoDB.Bson" version="2.4.1" targetFramework="net462" />
<package id="MongoDB.Driver" version="2.4.1" targetFramework="net462" /> <package id="MongoDB.Driver" version="2.4.1" targetFramework="net462" />
<package id="MongoDB.Driver.Core" version="2.4.1" targetFramework="net462" /> <package id="MongoDB.Driver.Core" version="2.4.1" targetFramework="net462" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" /> <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" />
</packages> </packages>

View File

@ -12,28 +12,48 @@
{ {
RouteValueDictionary rvd = new RouteValueDictionary(rd); RouteValueDictionary rvd = new RouteValueDictionary(rd);
rvd.Remove("page"); rvd.Remove("page");
<li><a href="@MvcIntrinsics.Url.Action(view, rvd)"><i class="fa fa-angle-double-left"></i></a></li> <li>
<li><a href="@MvcIntrinsics.Url.Action(view, rvd)"><i class="fa fa-angle-left"></i></a></li> <a href="@MvcIntrinsics.Url.Action(view, rvd)">
<i class="fa fa-angle-double-left"></i>
</a>
</li>
<li>
<a href="@MvcIntrinsics.Url.Action(view, rvd)">
<i class="fa fa-angle-left"></i>
</a>
</li>
} }
else if (currentPage > 2) else if (currentPage > 2)
{ {
RouteValueDictionary firstRvd = new RouteValueDictionary(rd); RouteValueDictionary firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page"); firstRvd.Remove("page");
<li><a href="@MvcIntrinsics.Url.Action(view, firstRvd)"><i class="fa fa-angle-double-left"></i></a></li> <li>
<a href="@MvcIntrinsics.Url.Action(view, firstRvd)">
<i class="fa fa-angle-double-left"></i>
</a>
</li>
RouteValueDictionary rvd = new RouteValueDictionary(rd) RouteValueDictionary rvd = new RouteValueDictionary(rd)
{ {
["page"] = currentPage - 1 ["page"] = currentPage - 1
}; };
<li><a href="@MvcIntrinsics.Url.Action(multiView, rvd)"><i class="fa fa-angle-left"></i></a></li> <li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-left"></i>
</a>
</li>
} }
else else
{ {
<li class="disabled"> <li class="disabled">
<span><i class="fa fa-angle-double-left"></i></span> <span>
<i class="fa fa-angle-double-left"></i>
</span>
</li> </li>
<li class="disabled"> <li class="disabled">
<span><i class="fa fa-angle-left"></i></span> <span>
<i class="fa fa-angle-left"></i>
</span>
</li> </li>
} }
@ -77,26 +97,38 @@
@if (currentPage < totalPages) @if (currentPage < totalPages)
{ {
RouteValueDictionary rvd = new RouteValueDictionary(rd) RouteValueDictionary rvd = new RouteValueDictionary(rd)
{ {
["page"] = currentPage + 1 ["page"] = currentPage + 1
}; };
<li><a href="@MvcIntrinsics.Url.Action(multiView, rvd)"><i class="fa fa-angle-right"></i></a></li> <li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-right"></i>
</a>
</li>
RouteValueDictionary lastRvd = new RouteValueDictionary(rd) RouteValueDictionary lastRvd = new RouteValueDictionary(rd)
{ {
["page"] = totalPages ["page"] = totalPages
}; };
<li><a href="@MvcIntrinsics.Url.Action(multiView, lastRvd)"><i class="fa fa-angle-double-right"></i></a></li> <li>
<a href="@MvcIntrinsics.Url.Action(multiView, lastRvd)">
<i class="fa fa-angle-double-right"></i>
</a>
</li>
} }
else else
{ {
<li class="disabled"> <li class="disabled">
<span><i class="fa fa-angle-right"></i></span> <span>
<i class="fa fa-angle-right"></i>
</span>
</li> </li>
<li class="disabled"> <li class="disabled">
<span><i class="fa fa-angle-double-right"></i></span> <span>
<i class="fa fa-angle-double-right"></i>
</span>
</li> </li>
} }
</ul> </ul>

View File

@ -4,22 +4,22 @@ using System.Web.Routing;
namespace BuildFeed namespace BuildFeed
{ {
public class RouteConfig public class RouteConfig
{ {
public static void RegisterRoutes(RouteCollection routes) public static void RegisterRoutes(RouteCollection routes)
{ {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.AppendTrailingSlash = true; routes.AppendTrailingSlash = true;
routes.MapHttpRoute("API", routes.MapHttpRoute("API",
"api/{action}/{id}", "api/{action}/{id}",
new new
{ {
controller = "api", controller = "api",
action = "GetBuilds", action = "GetBuilds",
id = UrlParameter.Optional id = UrlParameter.Optional
}); });
routes.MapMvcAttributeRoutes(); routes.MapMvcAttributeRoutes();
} }
} }
} }

View File

@ -5,34 +5,34 @@ using BuildFeed.Controllers;
namespace BuildFeed.Areas.admin.Controllers namespace BuildFeed.Areas.admin.Controllers
{ {
public class baseController : BaseController public class baseController : BaseController
{ {
[Authorize(Roles = "Administrators")] [Authorize(Roles = "Administrators")]
// GET: admin/base // GET: admin/base
public ActionResult index() public ActionResult index()
{ {
return View(); return View();
} }
[Authorize(Users = "hounsell")] [Authorize(Users = "hounsell")]
public ActionResult setup() public ActionResult setup()
{ {
if (!Roles.RoleExists("Administrators")) if (!Roles.RoleExists("Administrators"))
{ {
Roles.CreateRole("Administrators"); Roles.CreateRole("Administrators");
} }
if (!Roles.IsUserInRole("hounsell", "Administrators")) if (!Roles.IsUserInRole("hounsell", "Administrators"))
{ {
Roles.AddUserToRole("hounsell", "Administrators"); Roles.AddUserToRole("hounsell", "Administrators");
} }
return RedirectToAction("index"); return RedirectToAction("index");
} }
[Authorize(Users = "hounsell")] [Authorize(Users = "hounsell")]
public ActionResult exception() public ActionResult exception()
{ {
throw new Exception("This is a test exception"); throw new Exception("This is a test exception");
} }
} }
} }

View File

@ -7,102 +7,102 @@ using BuildFeed.Model;
namespace BuildFeed.Areas.admin.Controllers namespace BuildFeed.Areas.admin.Controllers
{ {
[Authorize(Roles = "Administrators")] [Authorize(Roles = "Administrators")]
public class metaController : BaseController public class metaController : BaseController
{ {
private readonly MetaItem _mModel; private readonly MetaItem _mModel;
public metaController() public metaController()
{ {
_mModel = new MetaItem(); _mModel = new MetaItem();
} }
// GET: admin/meta // GET: admin/meta
public async Task<ActionResult> index() public async Task<ActionResult> index()
{ {
return View(new MetaListing return View(new MetaListing
{ {
CurrentItems = from i in await _mModel.Select() 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 group i by i.Id.Type
into b into b
orderby b.Key.ToString() orderby b.Key.ToString()
select b, select b
NewItems = from i in (from l in await _mModel.SelectUnusedLabs() });
select new MetaItemModel }
{
Id = new MetaItemKey
{
Type = MetaType.Lab,
Value = l
}
}).Concat(from v in await _mModel.SelectUnusedVersions()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Version,
Value = v
}
}).Concat(from y in await _mModel.SelectUnusedYears()
select new MetaItemModel
{
Id = new MetaItemKey
{
Type = MetaType.Year,
Value = y
}
})
group i by i.Id.Type
into b
orderby b.Key.ToString()
select b
});
}
public ActionResult create(MetaType type, string value) public ActionResult create(MetaType type, string value)
{ {
return View(new MetaItemModel return View(new MetaItemModel
{
Id = new MetaItemKey
{ {
Type = type, Id = new MetaItemKey
Value = value {
Type = type,
Value = value
}
});
}
[HttpPost]
public async Task<ActionResult> create(MetaItemModel meta)
{
if (ModelState.IsValid)
{
await _mModel.Insert(meta);
return RedirectToAction("index");
} }
});
}
[HttpPost] return View(meta);
public async Task<ActionResult> create(MetaItemModel meta) }
{
if (ModelState.IsValid)
{
await _mModel.Insert(meta);
return RedirectToAction("index");
}
return View(meta); public async Task<ActionResult> edit(MetaType type, string value)
} {
return View("create",
await _mModel.SelectById(new MetaItemKey
{
Type = type,
Value = value
}));
}
public async Task<ActionResult> edit(MetaType type, string value) [HttpPost]
{ public async Task<ActionResult> edit(MetaItemModel meta)
return View("create", {
await _mModel.SelectById(new MetaItemKey if (ModelState.IsValid)
{ {
Type = type, await _mModel.Update(meta);
Value = value return RedirectToAction("index");
})); }
}
[HttpPost] return View("create", meta);
public async Task<ActionResult> edit(MetaItemModel meta) }
{ }
if (ModelState.IsValid)
{
await _mModel.Update(meta);
return RedirectToAction("index");
}
return View("create", meta);
}
}
} }

View File

@ -8,73 +8,73 @@ using MongoAuth;
namespace BuildFeed.Areas.admin.Controllers namespace BuildFeed.Areas.admin.Controllers
{ {
[Authorize(Roles = "Administrators")] [Authorize(Roles = "Administrators")]
public class usersController : BaseController public class usersController : BaseController
{ {
// GET: admin/users // GET: admin/users
public ActionResult index() => View(Membership.GetAllUsers().Cast<MembershipUser>().OrderByDescending(m => m.IsApproved).ThenBy(m => m.UserName)); public ActionResult index() => View(Membership.GetAllUsers().Cast<MembershipUser>().OrderByDescending(m => m.IsApproved).ThenBy(m => m.UserName));
public ActionResult admins() public ActionResult admins()
{ {
List<MembershipUser> admins = Roles.GetUsersInRole("Administrators").Select(Membership.GetUser).ToList(); List<MembershipUser> admins = Roles.GetUsersInRole("Administrators").Select(Membership.GetUser).ToList();
return View(admins.OrderByDescending(m => m.UserName)); return View(admins.OrderByDescending(m => m.UserName));
} }
public ActionResult promote(string id) public ActionResult promote(string id)
{ {
Roles.AddUserToRole(id, "Administrators"); Roles.AddUserToRole(id, "Administrators");
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult demote(string id) public ActionResult demote(string id)
{ {
Roles.RemoveUserFromRole(id, "Administrators"); Roles.RemoveUserFromRole(id, "Administrators");
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult approve(Guid id) public ActionResult approve(Guid id)
{ {
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider; MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeApproval(id, true); provider?.ChangeApproval(id, true);
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult unapprove(Guid id) public ActionResult unapprove(Guid id)
{ {
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider; MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeApproval(id, false); provider?.ChangeApproval(id, false);
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult @lock(Guid id) public ActionResult @lock(Guid id)
{ {
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider; MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeLockStatus(id, true); provider?.ChangeLockStatus(id, true);
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult unlock(Guid id) public ActionResult unlock(Guid id)
{ {
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider; MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeLockStatus(id, false); provider?.ChangeLockStatus(id, false);
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult cleanup() public ActionResult cleanup()
{ {
MembershipUserCollection users = Membership.GetAllUsers(); MembershipUserCollection users = Membership.GetAllUsers();
foreach (MembershipUser user in users) foreach (MembershipUser user in users)
{
if (!user.IsApproved
&& (user.CreationDate.AddDays(30) < DateTime.Now))
{ {
Membership.DeleteUser(user.UserName); if (!user.IsApproved
&& user.CreationDate.AddDays(30) < DateTime.Now)
{
Membership.DeleteUser(user.UserName);
}
} }
}
return RedirectToAction("index"); return RedirectToAction("index");
} }
} }
} }

View File

@ -4,9 +4,9 @@ using BuildFeed.Model;
namespace BuildFeed.Areas.admin.Models.ViewModel namespace BuildFeed.Areas.admin.Models.ViewModel
{ {
public class MetaListing public class MetaListing
{ {
public IEnumerable<IGrouping<MetaType, MetaItemModel>> CurrentItems { get; set; } public IEnumerable<IGrouping<MetaType, MetaItemModel>> CurrentItems { get; set; }
public IEnumerable<IGrouping<MetaType, MetaItemModel>> NewItems { get; set; } public IEnumerable<IGrouping<MetaType, MetaItemModel>> NewItems { get; set; }
} }
} }

View File

@ -2,28 +2,28 @@
namespace BuildFeed.Areas.admin namespace BuildFeed.Areas.admin
{ {
public class AdminAreaRegistration : AreaRegistration public class AdminAreaRegistration : AreaRegistration
{ {
public override string AreaName => "admin"; public override string AreaName => "admin";
public override void RegisterArea(AreaRegistrationContext context) public override void RegisterArea(AreaRegistrationContext context)
{ {
context.MapRoute("Meta", context.MapRoute("Meta",
"admin/{controller}/{action}/{type}/{value}", "admin/{controller}/{action}/{type}/{value}",
new new
{ {
action = "index", action = "index",
controller = "meta" controller = "meta"
}); });
context.MapRoute("Admin (Default)", context.MapRoute("Admin (Default)",
"admin/{controller}/{action}/{id}", "admin/{controller}/{action}/{id}",
new new
{ {
action = "index", action = "index",
controller = "base", controller = "base",
id = UrlParameter.Optional id = UrlParameter.Optional
}); });
} }
} }
} }

View File

@ -2,14 +2,14 @@
namespace BuildFeed.Code namespace BuildFeed.Code
{ {
// this class is a hacky workaround because Microsoft just don't feel like caching the correct content type // this class is a hacky workaround because Microsoft just don't feel like caching the correct content type
public class CustomContentTypeAttribute : ActionFilterAttribute public class CustomContentTypeAttribute : ActionFilterAttribute
{ {
public string ContentType { get; set; } public string ContentType { get; set; }
public override void OnResultExecuted(ResultExecutedContext filterContext) public override void OnResultExecuted(ResultExecutedContext filterContext)
{ {
filterContext.HttpContext.Response.ContentType = ContentType; filterContext.HttpContext.Response.ContentType = ContentType;
} }
} }
} }

View File

@ -4,23 +4,23 @@ using System.Web.Mvc;
namespace BuildFeed.Code namespace BuildFeed.Code
{ {
public class DateTimeModelBinder : DefaultModelBinder public class DateTimeModelBinder : DefaultModelBinder
{ {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{ {
ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
DateTime retValue; DateTime retValue;
bool success = DateTime.TryParse(value.AttemptedValue, CultureInfo.CurrentUICulture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out retValue); bool success = DateTime.TryParse(value.AttemptedValue, CultureInfo.CurrentUICulture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out retValue);
if (!success) if (!success)
{ {
success = DateTime.TryParseExact(value.AttemptedValue, "yyMMdd-HHmm", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out retValue); success = DateTime.TryParseExact(value.AttemptedValue, "yyMMdd-HHmm", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out retValue);
} }
return success return success
? retValue as DateTime? ? retValue as DateTime?
: null; : null;
} }
} }
} }

View File

@ -8,68 +8,68 @@ using System.Web.Mvc;
namespace BuildFeed.Code namespace BuildFeed.Code
{ {
public static class MvcExtensions public static class MvcExtensions
{ {
public static IHtmlString CheckboxListForEnum<T>(this HtmlHelper html, string id, T currentItem) where T : struct public static IHtmlString CheckboxListForEnum<T>(this HtmlHelper html, string id, T currentItem) where T : struct
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (T enumItem in Enum.GetValues(typeof(T)).Cast<T>()) foreach (T enumItem in Enum.GetValues(typeof(T)).Cast<T>())
{
long enumValue = Convert.ToInt64(enumItem);
long currentValue = Convert.ToInt64(currentItem);
if (enumValue == 0)
{ {
// skip 0-valued bitflags, they're for display only. long enumValue = Convert.ToInt64(enumItem);
continue; long currentValue = Convert.ToInt64(currentItem);
if (enumValue == 0)
{
// skip 0-valued bitflags, they're for display only.
continue;
}
TagBuilder wrapper = new TagBuilder("div");
wrapper.Attributes.Add("class", "checkbox");
TagBuilder label = new TagBuilder("label");
TagBuilder input = new TagBuilder("input");
if ((enumValue & currentValue) != 0)
{
input.MergeAttribute("checked", "checked");
}
input.MergeAttribute("type", "checkbox");
input.MergeAttribute("value", enumValue.ToString());
input.MergeAttribute("name", id);
label.InnerHtml = input.ToString(TagRenderMode.SelfClosing);
label.InnerHtml += GetDisplayTextForEnum(enumItem);
wrapper.InnerHtml = label.ToString(TagRenderMode.Normal);
sb.Append(wrapper.ToString(TagRenderMode.Normal));
} }
TagBuilder wrapper = new TagBuilder("div"); return new HtmlString(sb.ToString());
wrapper.Attributes.Add("class", "checkbox"); }
TagBuilder label = new TagBuilder("label"); public static string GetDisplayTextForEnum(object o)
{
string result = null;
DisplayAttribute display = o.GetType().GetMember(o.ToString()).First().GetCustomAttributes(false).OfType<DisplayAttribute>().LastOrDefault();
TagBuilder input = new TagBuilder("input"); if (display != null)
if ((enumValue & currentValue) != 0)
{ {
input.MergeAttribute("checked", "checked"); result = display.GetName();
} }
input.MergeAttribute("type", "checkbox");
input.MergeAttribute("value", enumValue.ToString());
input.MergeAttribute("name", id);
label.InnerHtml = input.ToString(TagRenderMode.SelfClosing); return result ?? o.ToString();
label.InnerHtml += GetDisplayTextForEnum(enumItem); }
wrapper.InnerHtml = label.ToString(TagRenderMode.Normal); public static string ToLongDateWithoutDay(this DateTime dt)
{
string s = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern;
s = s.Replace("dddd", "").Replace("ddd", "");
s = s.Trim(' ', ',');
sb.Append(wrapper.ToString(TagRenderMode.Normal)); return dt.ToString(s);
} }
}
return new HtmlString(sb.ToString());
}
public static string GetDisplayTextForEnum(object o)
{
string result = null;
DisplayAttribute display = o.GetType().GetMember(o.ToString()).First().GetCustomAttributes(false).OfType<DisplayAttribute>().LastOrDefault();
if (display != null)
{
result = display.GetName();
}
return result ?? o.ToString();
}
public static string ToLongDateWithoutDay(this DateTime dt)
{
string s = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern;
s = s.Replace("dddd", "").Replace("ddd", "");
s = s.Trim(' ', ',');
return dt.ToString(s);
}
}
} }

View File

@ -3,10 +3,10 @@ using System.Web.WebPages;
namespace BuildFeed.Code namespace BuildFeed.Code
{ {
public static class MvcIntrinsics public static class MvcIntrinsics
{ {
public static AjaxHelper Ajax => ((WebViewPage)WebPageContext.Current.Page).Ajax; public static AjaxHelper Ajax => ((WebViewPage)WebPageContext.Current.Page).Ajax;
public static HtmlHelper Html => ((WebViewPage)WebPageContext.Current.Page).Html; public static HtmlHelper Html => ((WebViewPage)WebPageContext.Current.Page).Html;
public static UrlHelper Url => ((WebViewPage)WebPageContext.Current.Page).Url; public static UrlHelper Url => ((WebViewPage)WebPageContext.Current.Page).Url;
} }
} }

View File

@ -4,84 +4,84 @@ using System.Web;
namespace BuildFeed.Code.Options namespace BuildFeed.Code.Options
{ {
public class Locale public class Locale
{ {
private const string LANG_COOKIE_NAME = "bf_lang"; private const string LANG_COOKIE_NAME = "bf_lang";
public static readonly Locale[] AvailableLocales = public static readonly Locale[] AvailableLocales =
{ {
new Locale("ar"), new Locale("ar"),
//new Locale("bn"), //new Locale("bn"),
new Locale("cs"), new Locale("cs"),
new Locale("de"), new Locale("de"),
new Locale("el"), new Locale("el"),
new Locale("en"), new Locale("en"),
new Locale("es"), new Locale("es"),
new Locale("fa"), new Locale("fa"),
new Locale("fi"), new Locale("fi"),
new Locale("fr"), new Locale("fr"),
new Locale("he"), new Locale("he"),
new Locale("hr"), new Locale("hr"),
new Locale("hu"), new Locale("hu"),
new Locale("id"), new Locale("id"),
new Locale("it"), new Locale("it"),
new Locale("ja"), new Locale("ja"),
new Locale("ko"), new Locale("ko"),
new Locale("lt"), new Locale("lt"),
new Locale("nl"), new Locale("nl"),
new Locale("pl"), new Locale("pl"),
new Locale("pt"), new Locale("pt"),
new Locale("pt-br"), new Locale("pt-br"),
//new Locale("qps-ploc"), //new Locale("qps-ploc"),
new Locale("ro"), new Locale("ro"),
new Locale("ru"), new Locale("ru"),
new Locale("sk"), new Locale("sk"),
new Locale("sl"), new Locale("sl"),
new Locale("sv"), new Locale("sv"),
new Locale("tr"), new Locale("tr"),
new Locale("uk"), new Locale("uk"),
new Locale("vi"), new Locale("vi"),
new Locale("zh-hans"), new Locale("zh-hans"),
new Locale("zh-hant") new Locale("zh-hant")
}; };
public string DisplayName => Info.NativeName; public string DisplayName => Info.NativeName;
public CultureInfo Info { get; set; } public CultureInfo Info { get; set; }
public string LocaleId { get; set; } public string LocaleId { get; set; }
public Locale(string localeId) public Locale(string localeId)
{ {
LocaleId = localeId; LocaleId = localeId;
Info = CultureInfo.GetCultureInfo(localeId); Info = CultureInfo.GetCultureInfo(localeId);
} }
public static CultureInfo DetectCulture(HttpContextBase context) public static CultureInfo DetectCulture(HttpContextBase context)
{ {
string langCookie = context.Request.Cookies[LANG_COOKIE_NAME]?.Value; string langCookie = context.Request.Cookies[LANG_COOKIE_NAME]?.Value;
if (!string.IsNullOrEmpty(langCookie)) if (!string.IsNullOrEmpty(langCookie))
{
try
{ {
CultureInfo ci = (CultureInfo)CultureInfo.GetCultureInfo(langCookie).Clone(); try
{
CultureInfo ci = (CultureInfo)CultureInfo.GetCultureInfo(langCookie).Clone();
// Get Gregorian Calendar in locale if available // Get Gregorian Calendar in locale if available
Calendar gc = ci.OptionalCalendars.FirstOrDefault(c => c is GregorianCalendar && (((GregorianCalendar)c).CalendarType == GregorianCalendarTypes.Localized)); Calendar gc = ci.OptionalCalendars.FirstOrDefault(c => c is GregorianCalendar && ((GregorianCalendar)c).CalendarType == GregorianCalendarTypes.Localized);
if (gc != null) if (gc != null)
{ {
ci.DateTimeFormat.Calendar = gc; ci.DateTimeFormat.Calendar = gc;
} }
return ci; return ci;
}
catch (CultureNotFoundException)
{
}
} }
catch (CultureNotFoundException) return CultureInfo.CurrentCulture;
{ }
} }
}
return CultureInfo.CurrentCulture;
}
}
} }

View File

@ -6,43 +6,43 @@ using BuildFeed.Local;
namespace BuildFeed.Code.Options namespace BuildFeed.Code.Options
{ {
public class Theme public class Theme
{ {
private const string THEME_COOKIE_NAME = "bf_theme"; private const string THEME_COOKIE_NAME = "bf_theme";
public static Theme[] AvailableThemes = (from st in Enum.GetValues(typeof(SiteTheme)).Cast<SiteTheme>() public static Theme[] AvailableThemes = (from st in Enum.GetValues(typeof(SiteTheme)).Cast<SiteTheme>()
select new Theme(st)).ToArray(); select new Theme(st)).ToArray();
private readonly SiteTheme _siteTheme; private readonly SiteTheme _siteTheme;
public string CookieValue => _siteTheme.ToString(); public string CookieValue => _siteTheme.ToString();
public string CssPath => $"~/res/css/{_siteTheme.ToString().ToLower()}.css"; public string CssPath => $"~/res/css/{_siteTheme.ToString().ToLower()}.css";
public string DisplayName => MvcExtensions.GetDisplayTextForEnum(_siteTheme); public string DisplayName => MvcExtensions.GetDisplayTextForEnum(_siteTheme);
public Theme(SiteTheme st) public Theme(SiteTheme st)
{ {
_siteTheme = st; _siteTheme = st;
} }
public static SiteTheme DetectTheme(HttpContextBase context) public static SiteTheme DetectTheme(HttpContextBase context)
{ {
string themeCookie = context.Request.Cookies[THEME_COOKIE_NAME]?.Value; string themeCookie = context.Request.Cookies[THEME_COOKIE_NAME]?.Value;
SiteTheme theme = SiteTheme.Dark; SiteTheme theme = SiteTheme.Dark;
if (!string.IsNullOrEmpty(themeCookie)) if (!string.IsNullOrEmpty(themeCookie))
{ {
Enum.TryParse(themeCookie, out theme); Enum.TryParse(themeCookie, out theme);
} }
return theme; return theme;
} }
} }
public enum SiteTheme public enum SiteTheme
{ {
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeDark))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeDark))]
Dark = 0, Dark = 0,
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeLight))] [Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Common_ThemeLight))]
Light Light
} }
} }

View File

@ -5,20 +5,20 @@ using BuildFeed.Code.Options;
namespace BuildFeed.Code namespace BuildFeed.Code
{ {
public class OutputCachePushAttribute : ActionFilterAttribute public class OutputCachePushAttribute : ActionFilterAttribute
{ {
public override void OnResultExecuted(ResultExecutedContext filterContext) public override void OnResultExecuted(ResultExecutedContext filterContext)
{ {
bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft; bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
Theme theme = new Theme(Theme.DetectTheme(filterContext.HttpContext)); Theme theme = new Theme(Theme.DetectTheme(filterContext.HttpContext));
filterContext.HttpContext.Response.PushPromise("/res/css/default.css"); filterContext.HttpContext.Response.PushPromise("/res/css/default.css");
filterContext.HttpContext.Response.PushPromise(VirtualPathUtility.ToAbsolute(theme.CssPath)); filterContext.HttpContext.Response.PushPromise(VirtualPathUtility.ToAbsolute(theme.CssPath));
if (isRtl) if (isRtl)
{ {
filterContext.HttpContext.Response.PushPromise("/res/css/rtl.css"); filterContext.HttpContext.Response.PushPromise("/res/css/rtl.css");
} }
filterContext.HttpContext.Response.PushPromise("/res/ts/bfs.js"); filterContext.HttpContext.Response.PushPromise("/res/ts/bfs.js");
} }
} }
} }

View File

@ -5,17 +5,17 @@ using BuildFeed.Code.Options;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
public class BaseController : Controller public class BaseController : Controller
{ {
protected override void Initialize(RequestContext requestContext) protected override void Initialize(RequestContext requestContext)
{ {
CultureInfo ci = Locale.DetectCulture(requestContext.HttpContext); CultureInfo ci = Locale.DetectCulture(requestContext.HttpContext);
CultureInfo.CurrentCulture = ci; CultureInfo.CurrentCulture = ci;
CultureInfo.CurrentUICulture = ci; CultureInfo.CurrentUICulture = ci;
ViewBag.Theme = new Theme(Theme.DetectTheme(requestContext.HttpContext)); ViewBag.Theme = new Theme(Theme.DetectTheme(requestContext.HttpContext));
base.Initialize(requestContext); base.Initialize(requestContext);
} }
} }
} }

View File

@ -11,8 +11,6 @@ using BuildFeed.Model;
using BuildFeed.Model.Api; using BuildFeed.Model.Api;
using BuildFeed.Model.View; using BuildFeed.Model.View;
using OneSignal.CSharp.SDK; using OneSignal.CSharp.SDK;
using OneSignal.CSharp.SDK.Resources;
using OneSignal.CSharp.SDK.Resources.Notifications;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
@ -94,7 +92,8 @@ namespace BuildFeed.Controllers
await _bModel.Insert(build); await _bModel.Insert(build);
OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]); OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
osc.PushNewBuild(build, $"https://buildfeed.net{Url.Route("Build", new { controller = "Front", action = nameof(FrontController.ViewBuild), id = build.Id, area = "", httproute = "" })}?utm_source=notification&utm_campaign=new_build"); osc.PushNewBuild(build,
$"https://buildfeed.net{Url.Route("Build", new { controller = "Front", action = nameof(FrontController.ViewBuild), id = build.Id, area = "", httproute = "" })}?utm_source=notification&utm_campaign=new_build");
} }
return true; return true;
} }

View File

@ -15,8 +15,6 @@ using BuildFeed.Code;
using BuildFeed.Model; using BuildFeed.Model;
using BuildFeed.Model.View; using BuildFeed.Model.View;
using OneSignal.CSharp.SDK; using OneSignal.CSharp.SDK;
using OneSignal.CSharp.SDK.Resources;
using OneSignal.CSharp.SDK.Resources.Notifications;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {

View File

@ -9,167 +9,167 @@ using WilderMinds.RssSyndication;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
public class RssController : BaseController public class RssController : BaseController
{ {
private const int RSS_SIZE = 25; private const int RSS_SIZE = 25;
private readonly BuildRepository _bModel; private readonly BuildRepository _bModel;
public RssController() public RssController()
{ {
_bModel = new BuildRepository(); _bModel = new BuildRepository();
} }
[Route("rss/compiled")] [Route("rss/compiled")]
public async Task<ActionResult> Index() public async Task<ActionResult> Index()
{ {
List<Build> builds = await _bModel.SelectBuildsByCompileDate(RSS_SIZE); List<Build> builds = await _bModel.SelectBuildsByCompileDate(RSS_SIZE);
Feed feed = new Feed Feed feed = new Feed
{ {
Title = "BuildFeed RSS - Recently Compiled", Title = "BuildFeed RSS - Recently Compiled",
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Items = (from build in builds Items = (from build in builds
select new Item select new Item
{ {
Title = build.AlternateBuildString, Title = build.AlternateBuildString,
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"),
Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}", Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}",
Categories = Categories =
{ {
build.Family.ToString() build.Family.ToString()
}, },
PublishDate = DateTime.SpecifyKind(build.BuildTime.GetValueOrDefault(), DateTimeKind.Utc) PublishDate = DateTime.SpecifyKind(build.BuildTime.GetValueOrDefault(), DateTimeKind.Utc)
}).ToList() }).ToList()
}; };
return new ContentResult return new ContentResult
{ {
Content = feed.Serialize(), Content = feed.Serialize(),
ContentType = "application/rss+xml", ContentType = "application/rss+xml",
ContentEncoding = Encoding.UTF8 ContentEncoding = Encoding.UTF8
}; };
} }
[Route("rss/added")] [Route("rss/added")]
public async Task<ActionResult> Added() public async Task<ActionResult> Added()
{ {
List<Build> builds = await _bModel.SelectBuildsByAddedDate(RSS_SIZE); List<Build> builds = await _bModel.SelectBuildsByAddedDate(RSS_SIZE);
Feed feed = new Feed Feed feed = new Feed
{ {
Title = "BuildFeed RSS - Recently Added", Title = "BuildFeed RSS - Recently Added",
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Items = (from build in builds Items = (from build in builds
select new Item select new Item
{ {
Title = build.AlternateBuildString, Title = build.AlternateBuildString,
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"),
Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}", Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}",
Categories = Categories =
{ {
build.Family.ToString() build.Family.ToString()
}, },
PublishDate = DateTime.SpecifyKind(build.Added, DateTimeKind.Utc) PublishDate = DateTime.SpecifyKind(build.Added, DateTimeKind.Utc)
}).ToList() }).ToList()
}; };
return new ContentResult return new ContentResult
{ {
Content = feed.Serialize(), Content = feed.Serialize(),
ContentType = "application/rss+xml", ContentType = "application/rss+xml",
ContentEncoding = Encoding.UTF8 ContentEncoding = Encoding.UTF8
}; };
} }
[Route("rss/leaked")] [Route("rss/leaked")]
public async Task<ActionResult> Leaked() public async Task<ActionResult> Leaked()
{ {
List<Build> builds = await _bModel.SelectBuildsByLeakedDate(RSS_SIZE); List<Build> builds = await _bModel.SelectBuildsByLeakedDate(RSS_SIZE);
Feed feed = new Feed Feed feed = new Feed
{ {
Title = "BuildFeed RSS - Recently Leaked", Title = "BuildFeed RSS - Recently Leaked",
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Items = (from build in builds Items = (from build in builds
select new Item select new Item
{ {
Title = build.AlternateBuildString, Title = build.AlternateBuildString,
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"),
Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}", Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}",
Categories = Categories =
{ {
build.Family.ToString() build.Family.ToString()
}, },
PublishDate = DateTime.SpecifyKind(build.LeakDate.GetValueOrDefault(), DateTimeKind.Utc) PublishDate = DateTime.SpecifyKind(build.LeakDate.GetValueOrDefault(), DateTimeKind.Utc)
}).ToList() }).ToList()
}; };
return new ContentResult return new ContentResult
{ {
Content = feed.Serialize(), Content = feed.Serialize(),
ContentType = "application/rss+xml", ContentType = "application/rss+xml",
ContentEncoding = Encoding.UTF8 ContentEncoding = Encoding.UTF8
}; };
} }
[Route("rss/version")] [Route("rss/version")]
public async Task<ActionResult> Version() public async Task<ActionResult> Version()
{ {
List<Build> builds = await _bModel.SelectBuildsByOrder(RSS_SIZE); List<Build> builds = await _bModel.SelectBuildsByOrder(RSS_SIZE);
Feed feed = new Feed Feed feed = new Feed
{ {
Title = "BuildFeed RSS - Highest Version", Title = "BuildFeed RSS - Highest Version",
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Items = (from build in builds Items = (from build in builds
select new Item select new Item
{ {
Title = build.AlternateBuildString, Title = build.AlternateBuildString,
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"),
Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}", Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}",
Categories = Categories =
{ {
build.Family.ToString() build.Family.ToString()
} }
}).ToList() }).ToList()
}; };
return new ContentResult return new ContentResult
{ {
Content = feed.Serialize(), Content = feed.Serialize(),
ContentType = "application/rss+xml", ContentType = "application/rss+xml",
ContentEncoding = Encoding.UTF8 ContentEncoding = Encoding.UTF8
}; };
} }
[Route("rss/lab/{lab}")] [Route("rss/lab/{lab}")]
public async Task<ActionResult> Lab(string lab) public async Task<ActionResult> Lab(string lab)
{ {
List<Build> builds = await _bModel.SelectLab(lab, RSS_SIZE); List<Build> builds = await _bModel.SelectLab(lab, RSS_SIZE);
Feed feed = new Feed Feed feed = new Feed
{ {
Title = $"BuildFeed RSS - {lab} Lab", Title = $"BuildFeed RSS - {lab} Lab",
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}"),
Items = (from build in builds Items = (from build in builds
select new Item select new Item
{ {
Title = build.AlternateBuildString, Title = build.AlternateBuildString,
Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"), Link = new Uri($"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}"),
Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}", Permalink = $"{Request.Url.Scheme}://{Request.Url.Authority}{Url.Action(nameof(FrontController.ViewBuild), new { controller = "Front", id = build.Id })}",
Categories = Categories =
{ {
build.Family.ToString() build.Family.ToString()
} }
}).ToList() }).ToList()
}; };
return new ContentResult return new ContentResult
{ {
Content = feed.Serialize(), Content = feed.Serialize(),
ContentType = "application/rss+xml", ContentType = "application/rss+xml",
ContentEncoding = Encoding.UTF8 ContentEncoding = Encoding.UTF8
}; };
} }
} }
} }

View File

@ -14,320 +14,320 @@ using BuildFeed.Model.View;
namespace BuildFeed.Controllers namespace BuildFeed.Controllers
{ {
public class SupportController : BaseController public class SupportController : BaseController
{ {
private readonly BuildRepository _bModel; private readonly BuildRepository _bModel;
public SupportController() public SupportController()
{ {
_bModel = new BuildRepository(); _bModel = new BuildRepository();
} }
[Route("login/")] [Route("login/")]
public ActionResult Login() => View(); public ActionResult Login() => View();
[HttpPost] [HttpPost]
[Route("login/")] [Route("login/")]
public ActionResult Login(LoginUser ru) public ActionResult Login(LoginUser ru)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{
bool isAuthenticated = Membership.ValidateUser(ru.UserName, ru.Password);
if (isAuthenticated)
{ {
int expiryLength = ru.RememberMe bool isAuthenticated = Membership.ValidateUser(ru.UserName, ru.Password);
? 129600
: 60;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength); if (isAuthenticated)
string encryptedTicket = FormsAuthentication.Encrypt(ticket); {
HttpCookie cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) int expiryLength = ru.RememberMe
{ ? 129600
Expires = DateTime.Now.AddMinutes(expiryLength), : 60;
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookieTicket);
string returnUrl = string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]) FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength);
? "/" string encryptedTicket = FormsAuthentication.Encrypt(ticket);
: Request.QueryString["ReturnUrl"]; HttpCookie cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
Expires = DateTime.Now.AddMinutes(expiryLength),
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookieTicket);
return Redirect(returnUrl); string returnUrl = string.IsNullOrEmpty(Request.QueryString["ReturnUrl"])
? "/"
: Request.QueryString["ReturnUrl"];
return Redirect(returnUrl);
}
} }
}
ViewData["ErrorMessage"] = "The username and password are not valid."; ViewData["ErrorMessage"] = "The username and password are not valid.";
return View(ru); return View(ru);
} }
[Authorize] [Authorize]
[Route("password/")] [Route("password/")]
public ActionResult Password() => View(); public ActionResult Password() => View();
[HttpPost] [HttpPost]
[Authorize] [Authorize]
[Route("password/")] [Route("password/")]
public ActionResult Password(ChangePassword cp) public ActionResult Password(ChangePassword cp)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{
MembershipUser user = Membership.GetUser();
if (user != null)
{ {
bool success = user.ChangePassword(cp.OldPassword, cp.NewPassword); MembershipUser user = Membership.GetUser();
if (success) if (user != null)
{ {
return Redirect("/"); bool success = user.ChangePassword(cp.OldPassword, cp.NewPassword);
}
if (success)
{
return Redirect("/");
}
}
} }
}
ViewData["ErrorMessage"] = "There was an error changing your password."; ViewData["ErrorMessage"] = "There was an error changing your password.";
return View(cp); return View(cp);
} }
[Route("logout/")] [Route("logout/")]
public ActionResult Logout() public ActionResult Logout()
{ {
FormsAuthentication.SignOut(); FormsAuthentication.SignOut();
return Redirect("/"); return Redirect("/");
} }
[Route("register/")] [Route("register/")]
public ActionResult Register() => View(); public ActionResult Register() => View();
[HttpPost] [HttpPost]
[Route("register/")] [Route("register/")]
public ActionResult Register(RegistrationUser ru) public ActionResult Register(RegistrationUser ru)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{
MembershipCreateStatus status;
Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "THIS WILL BE IGNORED", "I WILL BE IGNORED", false, out status);
switch (status)
{ {
case MembershipCreateStatus.Success: MembershipCreateStatus status;
return RedirectToAction("thanks_register"); Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "THIS WILL BE IGNORED", "I WILL BE IGNORED", false, out status);
case MembershipCreateStatus.InvalidPassword:
ViewData["ErrorMessage"] = "The password is invalid."; switch (status)
break; {
case MembershipCreateStatus.DuplicateEmail: case MembershipCreateStatus.Success:
ViewData["ErrorMessage"] = "A user account with this email address already exists."; return RedirectToAction("thanks_register");
break; case MembershipCreateStatus.InvalidPassword:
case MembershipCreateStatus.DuplicateUserName: ViewData["ErrorMessage"] = "The password is invalid.";
ViewData["ErrorMessage"] = "A user account with this user name already exists."; break;
break; case MembershipCreateStatus.DuplicateEmail:
default: ViewData["ErrorMessage"] = "A user account with this email address already exists.";
ViewData["ErrorMessage"] = "Unspecified error."; break;
break; case MembershipCreateStatus.DuplicateUserName:
ViewData["ErrorMessage"] = "A user account with this user name already exists.";
break;
default:
ViewData["ErrorMessage"] = "Unspecified error.";
break;
}
} }
}
return View(ru); return View(ru);
} }
[Route("register/thanks/")] [Route("register/thanks/")]
public ActionResult thanks_register() => View(); public ActionResult thanks_register() => View();
[Route("rss")] [Route("rss")]
public async Task<ActionResult> Rss() public async Task<ActionResult> Rss()
{ {
ViewBag.Labs = await _bModel.SelectAllLabs(); ViewBag.Labs = await _bModel.SelectAllLabs();
return View(); return View();
} }
[Route("sitemap/")] [Route("sitemap/")]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")] [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
#endif #endif
public async Task<ActionResult> Sitemap() public async Task<ActionResult> Sitemap()
{ {
List<Build> builds = await _bModel.SelectBuildsByOrder(); List<Build> builds = await _bModel.SelectBuildsByOrder();
var actions = new Dictionary<string, SitemapPagedAction[]> var actions = new Dictionary<string, SitemapPagedAction[]>
{
{ {
"Pages", new[] {
{ "Pages", new[]
new SitemapPagedAction {
{ new SitemapPagedAction
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "Index",
page = 1
}),
Pages = (builds.Count + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}
}
},
{
"Versions", (from b in builds
group b by new BuildVersion
{
Major = b.MajorVersion,
Minor = b.MinorVersion
}
into bv
orderby bv.Key.Major descending, bv.Key.Minor descending
select new SitemapPagedAction
{
Name = $"{InvariantTerms.ProductName} {bv.Key.Major}.{bv.Key.Minor}",
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "ViewVersion",
major = bv.Key.Major,
minor = bv.Key.Minor,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
},
{
"Labs", (from b in builds
where !string.IsNullOrEmpty(b.Lab)
group b by b.Lab
into bv
orderby bv.Key
select new SitemapPagedAction
{ {
Name = bv.Key,
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "ViewLab",
lab = bv.Key,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
},
{
"Years", (from b in builds
where b.BuildTime.HasValue
group b by b.BuildTime.Value.Year
into bv
orderby bv.Key descending
select new SitemapPagedAction
{
Name = bv.Key.ToString(),
UrlParams = new RouteValueDictionary(new UrlParams = new RouteValueDictionary(new
{ {
controller = "Front", controller = "Front",
action = "ViewYear", action = "Index",
year = bv.Key, page = 1
page = 1
}), }),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE Pages = (builds.Count + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray() }
}, }
{ },
"Sources", (from b in builds {
group b by b.SourceType "Versions", (from b in builds
into bv group b by new BuildVersion
orderby bv.Key {
select new SitemapPagedAction Major = b.MajorVersion,
{ Minor = b.MinorVersion
Name = MvcExtensions.GetDisplayTextForEnum(bv.Key), }
UrlParams = new RouteValueDictionary(new into bv
orderby bv.Key.Major descending, bv.Key.Minor descending
select new SitemapPagedAction
{
Name = $"{InvariantTerms.ProductName} {bv.Key.Major}.{bv.Key.Minor}",
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "ViewVersion",
major = bv.Key.Major,
minor = bv.Key.Minor,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
},
{
"Labs", (from b in builds
where !string.IsNullOrEmpty(b.Lab)
group b by b.Lab
into bv
orderby bv.Key
select new SitemapPagedAction
{
Name = bv.Key,
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "ViewLab",
lab = bv.Key,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
},
{
"Years", (from b in builds
where b.BuildTime.HasValue
group b by b.BuildTime.Value.Year
into bv
orderby bv.Key descending
select new SitemapPagedAction
{ {
controller = "Front", Name = bv.Key.ToString(),
action = "ViewSource", UrlParams = new RouteValueDictionary(new
source = bv.Key, {
page = 1 controller = "Front",
}), action = "ViewYear",
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE year = bv.Key,
}).ToArray() page = 1
} }),
}; Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
},
{
"Sources", (from b in builds
group b by b.SourceType
into bv
orderby bv.Key
select new SitemapPagedAction
{
Name = MvcExtensions.GetDisplayTextForEnum(bv.Key),
UrlParams = new RouteValueDictionary(new
{
controller = "Front",
action = "ViewSource",
source = bv.Key,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
}
};
SitemapData model = new SitemapData SitemapData model = new SitemapData
{ {
Builds = (from b in builds Builds = (from b in builds
group b by new group b by new
{ {
Major = b.MajorVersion, Major = b.MajorVersion,
Minor = b.MinorVersion, Minor = b.MinorVersion,
Build = b.Number, Build = b.Number,
b.Revision b.Revision
} }
into bg into bg
orderby bg.Key.Major descending, bg.Key.Minor descending, bg.Key.Build descending, bg.Key.Revision descending orderby bg.Key.Major descending, bg.Key.Minor descending, bg.Key.Build descending, bg.Key.Revision descending
select new SitemapDataBuildGroup select new SitemapDataBuildGroup
{ {
Id = new BuildGroup Id = new BuildGroup
{ {
Major = bg.Key.Major, Major = bg.Key.Major,
Minor = bg.Key.Minor, Minor = bg.Key.Minor,
Build = bg.Key.Build, Build = bg.Key.Build,
Revision = bg.Key.Revision Revision = bg.Key.Revision
}, },
Builds = (from bgb in bg Builds = (from bgb in bg
select new SitemapDataBuild select new SitemapDataBuild
{ {
Id = bgb.Id, Id = bgb.Id,
Name = bgb.FullBuildString Name = bgb.FullBuildString
}).ToArray() }).ToArray()
}).ToArray(), }).ToArray(),
Actions = actions, Actions = actions,
Labs = (from b in builds Labs = (from b in builds
group b by b.Lab group b by b.Lab
into lab into lab
select lab.Key).ToArray() select lab.Key).ToArray()
}; };
return View(model); return View(model);
} }
[Route("xml-sitemap/")] [Route("xml-sitemap/")]
#if !DEBUG #if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")] [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
#endif #endif
public async Task<ActionResult> XmlSitemap() public async Task<ActionResult> XmlSitemap()
{ {
XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9"); XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
var xlist = new List<XElement>(); var xlist = new List<XElement>();
// home page // home page
XElement home = new XElement(xn + "url"); XElement home = new XElement(xn + "url");
home.Add(new XElement(xn + "loc", Request.Url?.GetLeftPart(UriPartial.Authority) + "/")); home.Add(new XElement(xn + "loc", Request.Url?.GetLeftPart(UriPartial.Authority) + "/"));
home.Add(new XElement(xn + "changefreq", "daily")); home.Add(new XElement(xn + "changefreq", "daily"));
xlist.Add(home); xlist.Add(home);
foreach (Build b in await _bModel.Select()) foreach (Build b in await _bModel.Select())
{
XElement url = new XElement(xn + "url");
url.Add(new XElement(xn + "loc",
Request.Url?.GetLeftPart(UriPartial.Authority) + Url.Action("ViewBuild",
"Front",
new
{
id = b.Id
})));
if (b.Modified != DateTime.MinValue)
{ {
url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd"))); XElement url = new XElement(xn + "url");
url.Add(new XElement(xn + "loc",
Request.Url?.GetLeftPart(UriPartial.Authority) + Url.Action("ViewBuild",
"Front",
new
{
id = b.Id
})));
if (b.Modified != DateTime.MinValue)
{
url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd")));
}
xlist.Add(url);
} }
xlist.Add(url);
}
XDeclaration decl = new XDeclaration("1.0", "utf-8", ""); XDeclaration decl = new XDeclaration("1.0", "utf-8", "");
XElement root = new XElement(xn + "urlset", xlist); XElement root = new XElement(xn + "urlset", xlist);
XDocument xdoc = new XDocument(decl, root); XDocument xdoc = new XDocument(decl, root);
Response.ContentType = "application/xml"; Response.ContentType = "application/xml";
xdoc.Save(Response.OutputStream); xdoc.Save(Response.OutputStream);
return new EmptyResult(); return new EmptyResult();
} }
[Route("credits/")] [Route("credits/")]
public ActionResult Credits() => View(); public ActionResult Credits() => View();
} }
} }

View File

@ -10,52 +10,52 @@ using BuildFeed.Model;
namespace BuildFeed namespace BuildFeed
{ {
public class MvcApplication : HttpApplication public class MvcApplication : HttpApplication
{ {
protected void Application_Start() protected void Application_Start()
{ {
// Disable ASP.NET MVC version header // Disable ASP.NET MVC version header
MvcHandler.DisableMvcResponseHeader = true; MvcHandler.DisableMvcResponseHeader = true;
// Don't bother looking for the legacy aspx view engine. // Don't bother looking for the legacy aspx view engine.
ViewEngines.Engines.Clear(); ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine()); ViewEngines.Engines.Add(new RazorViewEngine());
AreaRegistration.RegisterAllAreas(); AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); RouteConfig.RegisterRoutes(RouteTable.Routes);
DateTimeModelBinder db = new DateTimeModelBinder(); DateTimeModelBinder db = new DateTimeModelBinder();
ModelBinders.Binders.Add(typeof(DateTime), db); ModelBinders.Binders.Add(typeof(DateTime), db);
ModelBinders.Binders.Add(typeof(DateTime?), db); ModelBinders.Binders.Add(typeof(DateTime?), db);
MongoConfig.SetupIndexes(); MongoConfig.SetupIndexes();
} }
public override string GetVaryByCustomString(HttpContext context, string custom) public override string GetVaryByCustomString(HttpContext context, string custom)
{ {
string[] parts = custom.Split(';'); string[] parts = custom.Split(';');
List<string> varyParts = new List<string>(); var varyParts = new List<string>();
HttpContextWrapper contextWrapper = new HttpContextWrapper(context); HttpContextWrapper contextWrapper = new HttpContextWrapper(context);
foreach (string part in parts) foreach (string part in parts)
{
switch (part)
{ {
case "userName": switch (part)
varyParts.Add($"user:{context.User.Identity.Name}"); {
break; case "userName":
case "lang": varyParts.Add($"user:{context.User.Identity.Name}");
varyParts.Add($"lang:{Locale.DetectCulture(contextWrapper).LCID}"); break;
break; case "lang":
case "theme": varyParts.Add($"lang:{Locale.DetectCulture(contextWrapper).LCID}");
varyParts.Add($"theme:{Theme.DetectTheme(contextWrapper)}"); break;
break; case "theme":
varyParts.Add($"theme:{Theme.DetectTheme(contextWrapper)}");
break;
}
} }
}
return string.Join(";", varyParts.OrderBy(s => s)); return string.Join(";", varyParts.OrderBy(s => s));
} }
} }
} }

View File

@ -1 +1 @@
importScripts('https://cdn.onesignal.com/sdks/OneSignalSDK.js'); importScripts("https://cdn.onesignal.com/sdks/OneSignalSDK.js");

View File

@ -1 +1 @@
importScripts('https://cdn.onesignal.com/sdks/OneSignalSDK.js'); importScripts("https://cdn.onesignal.com/sdks/OneSignalSDK.js");

View File

@ -1,10 +1,10 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("BuildFeed")] [assembly: AssemblyTitle("BuildFeed")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6c5846cb-43ac-4818-a9b5-a6cd1d6983a3")] [assembly: Guid("6c5846cb-43ac-4818-a9b5-a6cd1d6983a3")]
// Version information for an assembly consists of the following four values: // Version information for an assembly consists of the following four values:
@ -31,5 +33,6 @@ using System.Runtime.InteropServices;
// //
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,3 +1,3 @@
@{ @{
Layout = "~/Views/shared/_default.cshtml"; Layout = "~/Views/shared/_default.cshtml";
} }

View File

@ -3,58 +3,58 @@
@model BuildFeed.Model.View.BulkAddition @model BuildFeed.Model.View.BulkAddition
@{ @{
ViewBag.Title = $"{VariantTerms.Common_AddBulk} | {InvariantTerms.SiteName}"; ViewBag.Title = $"{VariantTerms.Common_AddBulk} | {InvariantTerms.SiteName}";
} }
<h1>@VariantTerms.Common_AddBulk</h1> <h1>@VariantTerms.Common_AddBulk</h1>
@if (ViewBag.Results != null) @if (ViewBag.Results != null)
{ {
<p>@VariantTerms.Bulk_Success</p> <p>@VariantTerms.Bulk_Success</p>
<ul> <ul>
@foreach (Build b in ViewBag.Results) @foreach (Build b in ViewBag.Results)
{ {
<li> <li>
<a href="@Url.Action(nameof(FrontController.ViewBuild), new <a href="@Url.Action(nameof(FrontController.ViewBuild), new
{ {
id = b.Id id = b.Id
})" target="_blank"> })" target="_blank">
@b.AlternateBuildString</a> @b.AlternateBuildString</a>
</li> </li>
} }
</ul> </ul>
} }
<p>@VariantTerms.Bulk_Instructions</p> <p>@VariantTerms.Bulk_Instructions</p>
@using (Html.BeginForm()) @using (Html.BeginForm())
{ {
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<div class="form-group"> <div class="form-group">
<label for="@Html.IdFor(m => m.Builds)">@VariantTerms.Bulk_Builds</label> <label for="@Html.IdFor(m => m.Builds)">@VariantTerms.Bulk_Builds</label>
<div> <div>
@Html.TextAreaFor(m => m.Builds, new @Html.TextAreaFor(m => m.Builds, new
{ {
rows = 10 rows = 10
}) })
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label></label> <label></label>
<div> <div>
<label> <label>
@Html.CheckBoxFor(m => m.SendNotifications) @Html.CheckBoxFor(m => m.SendNotifications)
@VariantTerms.Bulk_SendNotifications @VariantTerms.Bulk_SendNotifications
</label> </label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label></label> <label></label>
<div> <div>
<input type="submit" value="@VariantTerms.Bulk_AddBuilds" class="button" /> <input type="submit" value="@VariantTerms.Bulk_AddBuilds" class="button" />
</div> </div>
</div> </div>
} }

View File

@ -35,11 +35,13 @@
DateTime maxDate = group.LastBuild.Value; DateTime maxDate = group.LastBuild.Value;
if (maxDate.AddDays(28) > DateTime.Now) if (maxDate.AddDays(28) > DateTime.Now)
{ {
<span title="@maxDate.ToLongDateWithoutDay()"><i class="fa fa-calendar fa-fw"></i> @maxDate.Humanize()</span> <span title="@maxDate.ToLongDateWithoutDay()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.Humanize()</span>
} }
else else
{ {
<span title="@maxDate.Humanize()"><i class="fa fa-calendar fa-fw"></i> @maxDate.ToLongDateWithoutDay()</span> <span title="@maxDate.Humanize()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.ToLongDateWithoutDay()</span>
} }
} }
</p> </p>

View File

@ -2,187 +2,187 @@
@using BuildFeed.Model @using BuildFeed.Model
@model BuildFeed.Model.Build @model BuildFeed.Model.Build
@{ @{
ViewBag.Title = (string)ViewContext.RouteData.Values["action"] == nameof(FrontController.AddBuild) ViewBag.Title = (string)ViewContext.RouteData.Values["action"] == nameof(FrontController.AddBuild)
? $"{VariantTerms.Common_AddBuild} | {InvariantTerms.SiteName}" ? $"{VariantTerms.Common_AddBuild} | {InvariantTerms.SiteName}"
: $"{VariantTerms.Front_EditBuild} {Model.FullBuildString} | {InvariantTerms.SiteName}"; : $"{VariantTerms.Front_EditBuild} {Model.FullBuildString} | {InvariantTerms.SiteName}";
Html.EnableClientValidation(); Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript(); Html.EnableUnobtrusiveJavaScript();
} }
@if ((string)ViewContext.RouteData.Values["action"] == nameof(FrontController.AddBuild)) @if ((string)ViewContext.RouteData.Values["action"] == nameof(FrontController.AddBuild))
{ {
<h1>@VariantTerms.Common_AddBuild</h1> <h1>@VariantTerms.Common_AddBuild</h1>
} }
else else
{ {
<h1 class="eager-wrapping">@VariantTerms.Front_EditBuild @Model.AlternateBuildString</h1> <h1 class="eager-wrapping">@VariantTerms.Front_EditBuild @Model.AlternateBuildString</h1>
} }
<div class="form-group"> <div class="form-group">
<label for="quickpaste">@VariantTerms.Front_QuickPaste</label> <label for="quickpaste">@VariantTerms.Front_QuickPaste</label>
<div> <div>
<input id="quickpaste" type="text" /> <input id="quickpaste" type="text" />
</div> </div>
</div> </div>
@using (Html.BeginForm()) @using (Html.BeginForm())
{ {
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
@Html.ValidationSummary(true) @Html.ValidationSummary(true)
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.MajorVersion) @Html.LabelFor(model => model.MajorVersion)
<div> <div>
@Html.TextBoxFor(model => model.MajorVersion) @Html.TextBoxFor(model => model.MajorVersion)
@Html.ValidationMessageFor(model => model.MajorVersion) @Html.ValidationMessageFor(model => model.MajorVersion)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.MinorVersion) @Html.LabelFor(model => model.MinorVersion)
<div> <div>
@Html.TextBoxFor(model => model.MinorVersion) @Html.TextBoxFor(model => model.MinorVersion)
@Html.ValidationMessageFor(model => model.MinorVersion) @Html.ValidationMessageFor(model => model.MinorVersion)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.Number) @Html.LabelFor(model => model.Number)
<div> <div>
@Html.TextBoxFor(model => model.Number) @Html.TextBoxFor(model => model.Number)
@Html.ValidationMessageFor(model => model.Number) @Html.ValidationMessageFor(model => model.Number)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.Revision) @Html.LabelFor(model => model.Revision)
<div> <div>
@Html.TextBoxFor(model => model.Revision) @Html.TextBoxFor(model => model.Revision)
@Html.ValidationMessageFor(model => model.Revision) @Html.ValidationMessageFor(model => model.Revision)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.Lab) @Html.LabelFor(model => model.Lab)
<div> <div>
@Html.TextBoxFor(model => model.Lab) @Html.TextBoxFor(model => model.Lab)
@Html.ValidationMessageFor(model => model.Lab) @Html.ValidationMessageFor(model => model.Lab)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.BuildTime) @Html.LabelFor(model => model.BuildTime)
<div> <div>
@Html.TextBoxFor(model => model.BuildTime, "{0:yyMMdd-HHmm}") @Html.TextBoxFor(model => model.BuildTime, "{0:yyMMdd-HHmm}")
@Html.ValidationMessageFor(model => model.BuildTime) @Html.ValidationMessageFor(model => model.BuildTime)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.SourceType) @Html.LabelFor(model => model.SourceType)
<div> <div>
@Html.DropDownListFor(model => model.SourceType, EnumHelper.GetSelectList(typeof(TypeOfSource))) @Html.DropDownListFor(model => model.SourceType, EnumHelper.GetSelectList(typeof(TypeOfSource)))
@Html.ValidationMessageFor(model => model.SourceType) @Html.ValidationMessageFor(model => model.SourceType)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.LeakDate) @Html.LabelFor(model => model.LeakDate)
<div> <div>
<div class="group-input-button"> <div class="group-input-button">
@Html.TextBoxFor(model => model.LeakDate, "{0:dd/MM/yyyy}") @Html.TextBoxFor(model => model.LeakDate, "{0:dd/MM/yyyy}")
<button onclick="$('#@Html.IdFor(model => model.LeakDate)').val('@DateTime.Now.ToShortDateString()');return false;">@VariantTerms.Front_Today</button> <button onclick="$('#@Html.IdFor(model => model.LeakDate)').val('@DateTime.Now.ToShortDateString()');return false;">@VariantTerms.Front_Today</button>
</div> </div>
@Html.ValidationMessageFor(model => model.LeakDate) @Html.ValidationMessageFor(model => model.LeakDate)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.SourceDetails) @Html.LabelFor(model => model.SourceDetails)
<div class="wide-group"> <div class="wide-group">
@Html.TextAreaFor(model => model.SourceDetails) @Html.TextAreaFor(model => model.SourceDetails)
@Html.ValidationMessageFor(model => model.SourceDetails) @Html.ValidationMessageFor(model => model.SourceDetails)
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label></label> <label></label>
<div> <div>
<input type="submit" value="@((string)ViewContext.RouteData.Values["action"] == "addBuild" <input type="submit" value="@((string)ViewContext.RouteData.Values["action"] == "addBuild"
? VariantTerms.Common_AddBuild ? VariantTerms.Common_AddBuild
: VariantTerms.Front_EditBuild)" class="btn btn-primary" /> : VariantTerms.Front_EditBuild)" class="btn btn-primary" />
&ensp; &ensp;
<a href="/" onclick="window.history.back();return false;" class="button"> <a href="/" onclick="window.history.back();return false;" class="button">
@VariantTerms.Front_ReturnToListing @VariantTerms.Front_ReturnToListing
</a> </a>
</div> </div>
</div> </div>
} }
@section Scripts @section Scripts
{ {
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" type="text/javascript"></script>
<script src="~/Scripts/trumbowyg/trumbowyg.min.js" type="text/javascript"></script> <script src="~/Scripts/trumbowyg/trumbowyg.min.js" type="text/javascript"></script>
<link href="~/Scripts/trumbowyg/ui/trumbowyg.min.css" rel="stylesheet" type="text/css" /> <link href="~/Scripts/trumbowyg/ui/trumbowyg.min.css" rel="stylesheet" type="text/css" />
<script src="~/Scripts/jquery.validate.js" type="text/javascript"></script> <script src="~/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
jQuery(function($) jQuery(function($)
{ {
$.validator.addMethod('date', $.validator.addMethod('date',
function(value, element) function(value, element)
{ {
if (this.optional(element)) if (this.optional(element))
{ {
return true; return true;
} }
var ok = true; var ok = true;
try try
{ {
new Date(Date.parse(value, "yyMMdd-HHmm")); new Date(Date.parse(value, "yyMMdd-HHmm"));
} }
catch (err) catch (err)
{ {
ok = false; ok = false;
} }
return ok; return ok;
}); });
}); });
$(function() $(function()
{ {
$("#@Html.IdFor(model => model.SourceDetails)")
.trumbowyg({
autogrow: true,
btns: [
['strong', 'em'],
'|', 'link',
'|', 'btnGrp-lists',
'|', 'btnGrp-justify',
'|', 'viewHTML',
'|'
]
});
$("#@Html.IdFor(model => model.SourceDetails)") $(".trumbowyg").addClass("trumbowyg-black");
.trumbowyg({
autogrow: true,
btns: [
[ 'strong', 'em' ],
'|', 'link',
'|', 'btnGrp-lists',
'|', 'btnGrp-justify',
'|', 'viewHTML',
'|'
]
});
$(".trumbowyg").addClass("trumbowyg-black"); $("#quickpaste")
.change(function()
{
var regex = /(([\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)\)?/;
var result = regex.exec($("#quickpaste").val());
$("#quickpaste") $("#MajorVersion").val(result[2]);
.change(function() { $("#MinorVersion").val(result[3]);
var regex = /(([\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)\)?/; $("#Number").val(result[4]);
var result = regex.exec($("#quickpaste").val()); $("#Revision").val(result[6]);
$("#Lab").val(result[8]);
$("#MajorVersion").val(result[2]); $("#BuildTime").val(result[9]);
$("#MinorVersion").val(result[3]); });
$("#Number").val(result[4]); });
$("#Revision").val(result[6]); </script>
$("#Lab").val(result[8]);
$("#BuildTime").val(result[9]);
});
});
</script>
} }

View File

@ -1,78 +1,78 @@
@model BuildFeed.Model.View.FrontPage @model BuildFeed.Model.View.FrontPage
@{ @{
ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker"; ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker";
} }
@section Head @section Head
{ {
<meta name="description" content="Learn what Dona Sarkar won&apos;t tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker." /> <meta name="description" content="Learn what Dona Sarkar won&apos;t tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker." />
} }
<h1>@string.Format(VariantTerms.Front_HomeH1, InvariantTerms.SiteName)</h1> <h1>@string.Format(VariantTerms.Front_HomeH1, InvariantTerms.SiteName)</h1>
<h3>@VariantTerms.Front_LatestBuilds</h3> <h3>@VariantTerms.Front_LatestBuilds</h3>
<div class="latest-flex"> <div class="latest-flex">
@if (Model.CurrentCanary != null) @if (Model.CurrentCanary != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentCanary.Id Model.CurrentCanary.Id
})" class="latest-flex-item latest-flex-red"> })" class="latest-flex-item latest-flex-red">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3>
<div class="latest-flex-detail"> <div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentCanary.MajorVersion).@(Model.CurrentCanary.MinorVersion).@(Model.CurrentCanary.Number).@(Model.CurrentCanary.Revision)</p> <p class="latest-flex-build">@(Model.CurrentCanary.MajorVersion).@(Model.CurrentCanary.MinorVersion).@(Model.CurrentCanary.Number).@(Model.CurrentCanary.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentCanary.Lab</p> <p class="latest-flex-lab">@Model.CurrentCanary.Lab</p>
<p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
@if (Model.CurrentInsider != null) @if (Model.CurrentInsider != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentInsider.Id Model.CurrentInsider.Id
})" class="latest-flex-item latest-flex-yellow"> })" class="latest-flex-item latest-flex-yellow">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3>
<div class="latest-flex-detail"> <div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentInsider.MajorVersion).@(Model.CurrentInsider.MinorVersion).@(Model.CurrentInsider.Number).@(Model.CurrentInsider.Revision)</p> <p class="latest-flex-build">@(Model.CurrentInsider.MajorVersion).@(Model.CurrentInsider.MinorVersion).@(Model.CurrentInsider.Number).@(Model.CurrentInsider.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentInsider.Lab</p> <p class="latest-flex-lab">@Model.CurrentInsider.Lab</p>
<p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
@if (Model.CurrentRelease != null) @if (Model.CurrentRelease != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentRelease.Id Model.CurrentRelease.Id
})" class="latest-flex-item latest-flex-blue"> })" class="latest-flex-item latest-flex-blue">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3>
<div class="latest-flex-detail"> <div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentRelease.MajorVersion).@(Model.CurrentRelease.MinorVersion).@(Model.CurrentRelease.Number).@(Model.CurrentRelease.Revision)</p> <p class="latest-flex-build">@(Model.CurrentRelease.MajorVersion).@(Model.CurrentRelease.MinorVersion).@(Model.CurrentRelease.Number).@(Model.CurrentRelease.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentRelease.Lab</p> <p class="latest-flex-lab">@Model.CurrentRelease.Lab</p>
<p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
@if (Model.CurrentXbox != null) @if (Model.CurrentXbox != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentXbox.Id Model.CurrentXbox.Id
})" class="latest-flex-item latest-flex-green"> })" class="latest-flex-item latest-flex-green">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentXbox</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentXbox</h3>
<div class="latest-flex-detail"> <div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentXbox.MajorVersion).@(Model.CurrentXbox.MinorVersion).@(Model.CurrentXbox.Number).@(Model.CurrentXbox.Revision)</p> <p class="latest-flex-build">@(Model.CurrentXbox.MajorVersion).@(Model.CurrentXbox.MinorVersion).@(Model.CurrentXbox.Number).@(Model.CurrentXbox.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentXbox.Lab</p> <p class="latest-flex-lab">@Model.CurrentXbox.Lab</p>
<p class="latest-flex-time">@(Model.CurrentXbox.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentXbox.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
</div> </div>
<a href="@Url.Action("IndexPage", new <a href="@Url.Action("IndexPage", new
{ {
Page = 1 Page = 1
})" class="latest-full"> })" class="latest-full">
@VariantTerms.Front_FullBuildListing @VariantTerms.Front_FullBuildListing
</a> </a>
<h3>@VariantTerms.Front_Share</h3> <h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div> <div class="addthis_sharing_toolbox"></div>

View File

@ -4,132 +4,132 @@
@model BuildFeed.Model.Build @model BuildFeed.Model.Build
@{ @{
ViewBag.Title = $"{Model.FullBuildString} | {InvariantTerms.SiteName}"; ViewBag.Title = $"{Model.FullBuildString} | {InvariantTerms.SiteName}";
} }
@section head @section head
{ {
<meta property="og:title" content="@Model.FullBuildString" /> <meta property="og:title" content="@Model.FullBuildString" />
<meta property="og:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new <meta property="og:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
{ {
id = Model.Id id = Model.Id
})"> })">
<meta name="twitter:card" content="summary_large_image"> <meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@Model.FullBuildString | @InvariantTerms.SiteName"> <meta name="twitter:title" content="@Model.FullBuildString | @InvariantTerms.SiteName">
<meta name="twitter:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new <meta name="twitter:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
{ {
id = Model.Id id = Model.Id
})"> })">
@{ @{
string metaDesc = Model.BuildTime.HasValue string metaDesc = Model.BuildTime.HasValue
? string.Format(VariantTerms.Meta_BuildDate, Model.Number, Model.Lab, Model.BuildTime.Value.ToLongDateWithoutDay()) ? string.Format(VariantTerms.Meta_BuildDate, Model.Number, Model.Lab, Model.BuildTime.Value.ToLongDateWithoutDay())
: string.Format(VariantTerms.Meta_BuildNoDate, Model.Number, Model.Lab); : string.Format(VariantTerms.Meta_BuildNoDate, Model.Number, Model.Lab);
} }
<meta name="description" content="@metaDesc" /> <meta name="description" content="@metaDesc" />
<meta property="og:description" content="@metaDesc" /> <meta property="og:description" content="@metaDesc" />
<meta name="twitter:description" content="@metaDesc" /> <meta name="twitter:description" content="@metaDesc" />
} }
<h1 dir="ltr" class="eager-wrapping">@Model.AlternateBuildString</h1> <h1 dir="ltr" class="eager-wrapping">@Model.AlternateBuildString</h1>
<h3>@VariantTerms.Front_Details</h3> <h3>@VariantTerms.Front_Details</h3>
<div class="build-details-flex"> <div class="build-details-flex">
<div class="build-details-flex-item"> <div class="build-details-flex-item">
@Html.LabelFor(model => model.MajorVersion) @Html.LabelFor(model => model.MajorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MajorVersion)</p> <p class="build-details-flex-value">@Html.DisplayFor(model => model.MajorVersion)</p>
</div> </div>
<div class="build-details-flex-item"> <div class="build-details-flex-item">
@Html.LabelFor(model => model.MinorVersion) @Html.LabelFor(model => model.MinorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MinorVersion)</p> <p class="build-details-flex-value">@Html.DisplayFor(model => model.MinorVersion)</p>
</div> </div>
<div class="build-details-flex-item"> <div class="build-details-flex-item">
@Html.LabelFor(model => model.Number) @Html.LabelFor(model => model.Number)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.Number)</p> <p class="build-details-flex-value">@Html.DisplayFor(model => model.Number)</p>
</div> </div>
<div class="build-details-flex-item"> <div class="build-details-flex-item">
@Html.LabelFor(model => model.Revision) @Html.LabelFor(model => model.Revision)
<p class="build-details-flex-value"> <p class="build-details-flex-value">
@if (Model.Revision.HasValue) @if (Model.Revision.HasValue)
{ {
@Html.DisplayFor(model => model.Revision) @Html.DisplayFor(model => model.Revision)
} }
else else
{ {
@("-") @("-")
} }
</p> </p>
</div> </div>
</div> </div>
<div class="build-details-flex"> <div class="build-details-flex">
<div class="build-details-flex-item"> <div class="build-details-flex-item">
@Html.LabelFor(model => model.Lab) @Html.LabelFor(model => model.Lab)
<p class="build-details-flex-value"> <p class="build-details-flex-value">
@if (string.IsNullOrEmpty(Model.Lab)) @if (string.IsNullOrEmpty(Model.Lab))
{ {
<em>@VariantTerms.Front_NoLabString</em> <em>@VariantTerms.Front_NoLabString</em>
} }
else else
{ {
@Model.Lab<br /> @Model.Lab<br />
<a href="@Url.Action(nameof(FrontController.ViewLab), new <a href="@Url.Action(nameof(FrontController.ViewLab), new
{
lab = Model.LabUrl
})" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromLab, Model.Lab)
</a>
}
</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.BuildTime)
<p class="build-details-flex-value">
@if (Model.BuildTime.HasValue)
{
<time datetime="@Model.BuildTime.Value.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture.DateTimeFormat)" title="@Model.BuildTime.Value.ToString("h:mm tt on dddd, d MMMM yyyy")">@Model.BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)</time>
<br />
<a href="@Url.Action(nameof(FrontController.ViewYear), new
{
year = Model.BuildTime.Value.Year
})" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromYear, Model.BuildTime.Value.Year)
</a>
}
</p>
</div>
</div>
<div class="build-details-flex">
<div class="build-details-flex-item">
@Html.LabelFor(model => model.SourceType)
<div class="build-details-flex-value">
@Html.DisplayFor(model => model.SourceType, "Enumeration")<br />
<a href="@Url.Action("ViewSource", new
{ {
source = Model.SourceType lab = Model.LabUrl
})" class="more-link"> })" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp; <i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromSource, MvcExtensions.GetDisplayTextForEnum(Model.SourceType)) @string.Format(VariantTerms.Front_MoreFromLab, Model.Lab)
</a> </a>
</div> }
</div> </p>
<div class="build-details-flex-item"> </div>
@if (Model.LeakDate.HasValue) <div class="build-details-flex-item">
{ @Html.LabelFor(model => model.BuildTime)
@Html.LabelFor(model => model.LeakDate) <p class="build-details-flex-value">
<div class="build-details-flex-value"> @if (Model.BuildTime.HasValue)
<time datetime="@Model.LeakDate.Value.ToString("yyyy-MM-dd")" title="@Model.LeakDate.Value.ToLongDateString()">@Model.LeakDate.Value.ToShortDateString()</time> {
</div> <time datetime="@Model.BuildTime.Value.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture.DateTimeFormat)" title="@Model.BuildTime.Value.ToString("h:mm tt on dddd, d MMMM yyyy")">@Model.BuildTime.Value.ToString("yyMMdd-HHmm", CultureInfo.InvariantCulture.DateTimeFormat)</time>
} <br />
</div> <a href="@Url.Action(nameof(FrontController.ViewYear), new
{
year = Model.BuildTime.Value.Year
})" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromYear, Model.BuildTime.Value.Year)
</a>
}
</p>
</div>
</div>
<div class="build-details-flex">
<div class="build-details-flex-item">
@Html.LabelFor(model => model.SourceType)
<div class="build-details-flex-value">
@Html.DisplayFor(model => model.SourceType, "Enumeration")<br />
<a href="@Url.Action("ViewSource", new
{
source = Model.SourceType
})" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromSource, MvcExtensions.GetDisplayTextForEnum(Model.SourceType))
</a>
</div>
</div>
<div class="build-details-flex-item">
@if (Model.LeakDate.HasValue)
{
@Html.LabelFor(model => model.LeakDate)
<div class="build-details-flex-value">
<time datetime="@Model.LeakDate.Value.ToString("yyyy-MM-dd")" title="@Model.LeakDate.Value.ToLongDateString()">@Model.LeakDate.Value.ToShortDateString()</time>
</div>
}
</div>
</div> </div>
<br /> <br />
@if (!string.IsNullOrWhiteSpace(Model.SourceDetailsFiltered)) @if (!string.IsNullOrWhiteSpace(Model.SourceDetailsFiltered))
{ {
<h3>@Html.DisplayNameFor(model => model.SourceDetails)</h3> <h3>@Html.DisplayNameFor(model => model.SourceDetails)</h3>
<div class="build-details-flex-value">@Html.Raw(Model.SourceDetailsFiltered)</div> <div class="build-details-flex-value">@Html.Raw(Model.SourceDetailsFiltered)</div>
<br /> <br />
} }
<h3>@VariantTerms.Front_Share</h3> <h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div> <div class="addthis_sharing_toolbox"></div>
@ -137,57 +137,57 @@
@if (User.Identity.IsAuthenticated) @if (User.Identity.IsAuthenticated)
{ {
<h3>@VariantTerms.Front_EditorActions</h3> <h3>@VariantTerms.Front_EditorActions</h3>
<p class="build-details-flex-value"> <p class="build-details-flex-value">
@Html.ActionLink(VariantTerms.Front_Edit, nameof(FrontController.EditBuild), new @Html.ActionLink(VariantTerms.Front_Edit, nameof(FrontController.EditBuild), new
{ {
id = Model.Id id = Model.Id
}, new }, new
{ {
@class = "button edit-button" @class = "button edit-button"
}) })
@if (Roles.IsUserInRole("Administrators")) @if (Roles.IsUserInRole("Administrators"))
{ {
@Html.ActionLink(VariantTerms.Front_Delete, nameof(FrontController.DeleteBuild), new @Html.ActionLink(VariantTerms.Front_Delete, nameof(FrontController.DeleteBuild), new
{ {
id = Model.Id id = Model.Id
}, new }, new
{ {
@class = "button delete-button" @class = "button delete-button"
}) })
} }
</p> </p>
} }
<section class="build-details-comments"> <section class="build-details-comments">
<h3>@VariantTerms.Front_Comments</h3> <h3>@VariantTerms.Front_Comments</h3>
<div id="disqus_thread"></div> <div id="disqus_thread"></div>
<script type="text/javascript"> <script type="text/javascript">
var disqus_shortname = 'buildfeed'; var disqus_shortname = 'buildfeed';
var disqus_url = 'https://buildfeed.net/actions/info/@((object)Model.LegacyId ?? Model.Id)/'; var disqus_url = 'https://buildfeed.net/actions/info/@((object)Model.LegacyId ?? Model.Id)/';
(function() (function()
{ {
var dsq = document.createElement('script'); var dsq = document.createElement('script');
dsq.type = 'text/javascript'; dsq.type = 'text/javascript';
dsq.async = true; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]) (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])
.appendChild(dsq); .appendChild(dsq);
})(); })();
</script> </script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</section> </section>
<p> <p>
<a href="@Url.Action("ViewGroup", new <a href="@Url.Action("ViewGroup", new
{ {
major = Model.MajorVersion, major = Model.MajorVersion,
minor = Model.MinorVersion, minor = Model.MinorVersion,
number = Model.Number, number = Model.Number,
revision = Model.Revision revision = Model.Revision
})" class="button"> })" class="button">
@VariantTerms.Front_ReturnToOverview @VariantTerms.Front_ReturnToOverview
</a> </a>
&ensp; &ensp;
<a href="@Url.Action("Index")" class="button">@VariantTerms.Front_ReturnToListing</a> <a href="@Url.Action("Index")" class="button">@VariantTerms.Front_ReturnToListing</a>
</p> </p>

View File

@ -4,77 +4,77 @@
@using Humanizer @using Humanizer
@model Tuple<BuildFeed.Model.BuildGroup, List<BuildFeed.Model.Build>> @model Tuple<BuildFeed.Model.BuildGroup, List<BuildFeed.Model.Build>>
@{ @{
ViewBag.Title = $"{Model.Item1} | {InvariantTerms.SiteName}"; ViewBag.Title = $"{Model.Item1} | {InvariantTerms.SiteName}";
} }
<h1>@Model.Item1.ToString()</h1> <h1>@Model.Item1.ToString()</h1>
<h3>@VariantTerms.Front_Listing</h3> <h3>@VariantTerms.Front_Listing</h3>
<div class="build-group-listing"> <div class="build-group-listing">
@foreach (Build build in Model.Item2) @foreach (Build build in Model.Item2)
{ {
<div class="build-group"> <div class="build-group">
<h3 class="build-group-title no-wrapping" title="@build.AlternateBuildString"> <h3 class="build-group-title no-wrapping" title="@build.AlternateBuildString">
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
id = build.Id id = build.Id
})"> })">
@(string.IsNullOrEmpty(build.Lab) @(string.IsNullOrEmpty(build.Lab)
? "{Unknown}" ? "{Unknown}"
: build.Lab) : build.Lab)
</a> </a>
</h3> </h3>
@if (build.BuildTime.HasValue) @if (build.BuildTime.HasValue)
{ {
<p class="build-group-p"> <p class="build-group-p">
<span title="@build.BuildTime.Value.Humanize()"> <span title="@build.BuildTime.Value.Humanize()">
<i class="fa fa-calendar fa-fw"></i> @build.BuildTime.Value.ToLongDateWithoutDay()</span> <i class="fa fa-calendar fa-fw"></i> @build.BuildTime.Value.ToLongDateWithoutDay()</span>
</p> </p>
<p class="build-group-p"> <p class="build-group-p">
<span title="@build.BuildTime.Value.Humanize()"> <span title="@build.BuildTime.Value.Humanize()">
<i class="fa fa-clock-o fa-fw"></i> @build.BuildTime.Value.ToShortTimeString()</span> <i class="fa fa-clock-o fa-fw"></i> @build.BuildTime.Value.ToShortTimeString()</span>
</p> </p>
} }
@if (build.IsLeaked) @if (build.IsLeaked)
{ {
<p class="build-group-p"> <p class="build-group-p">
<span> <span>
<i class="fa fa-unlock-alt fa-fw"></i> @VariantTerms.Front_Public</span> <i class="fa fa-unlock-alt fa-fw"></i> @VariantTerms.Front_Public</span>
</p> </p>
} }
else else
{ {
<p class="build-group-p"> <p class="build-group-p">
<span> <span>
<i class="fa fa-lock fa-fw"></i> @VariantTerms.Front_Private</span> <i class="fa fa-lock fa-fw"></i> @VariantTerms.Front_Private</span>
</p> </p>
} }
@if (User.Identity.IsAuthenticated) @if (User.Identity.IsAuthenticated)
{ {
<p> <p>
<a href="@Url.Action(nameof(FrontController.EditBuild), new <a href="@Url.Action(nameof(FrontController.EditBuild), new
{ {
id = build.Id id = build.Id
})" class="button edit-button"> })" class="button edit-button">
@VariantTerms.Front_Edit @VariantTerms.Front_Edit
</a> </a>
&nbsp; &nbsp;
@if (Roles.IsUserInRole("Administrators")) @if (Roles.IsUserInRole("Administrators"))
{ {
<a href="@Url.Action(nameof(FrontController.DeleteBuild), new <a href="@Url.Action(nameof(FrontController.DeleteBuild), new
{ {
id = build.Id id = build.Id
})" class="button delete-button"> })" class="button delete-button">
@VariantTerms.Front_Delete @VariantTerms.Front_Delete
</a> </a>
} }
</p> </p>
} }
</div> </div>
} }
<div class="build-group-empty"></div> <div class="build-group-empty"></div>
<div class="build-group-empty"></div> <div class="build-group-empty"></div>
<div class="build-group-empty"></div> <div class="build-group-empty"></div>
<div class="build-group-empty"></div> <div class="build-group-empty"></div>
<div class="build-group-empty"></div> <div class="build-group-empty"></div>
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

@ -272,7 +272,7 @@
</div> </div>
<div id="menu-open-overlay"></div> <div id="menu-open-overlay"></div>
<script type="text/javascript" t src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.0-rc.70/jsrender.min.js" integrity="sha256-3UBtL0tzgKVuJU8ZZiWLXEWGEjXEr6Z023rpauMnBUE=" crossorigin="anonymous"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.0-rc.70/jsrender.min.js" integrity="sha256-3UBtL0tzgKVuJU8ZZiWLXEWGEjXEr6Z023rpauMnBUE=" crossorigin="anonymous"></script>
<script type="text/javascript" src="/res/ts/bfs.js"></script> <script type="text/javascript" src="/res/ts/bfs.js"></script>
@RenderSection("scripts", false) @RenderSection("scripts", false)
<script id="result-template" type="text/x-jsrender"> <script id="result-template" type="text/x-jsrender">

View File

@ -149,7 +149,7 @@
</div> </div>
</div> </div>
</footer> </footer>
<script type="text/javascript"t src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.0-rc.70/jsrender.min.js" integrity="sha256-3UBtL0tzgKVuJU8ZZiWLXEWGEjXEr6Z023rpauMnBUE=" crossorigin="anonymous"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.0-rc.70/jsrender.min.js" integrity="sha256-3UBtL0tzgKVuJU8ZZiWLXEWGEjXEr6Z023rpauMnBUE=" crossorigin="anonymous"></script>
<script type="text/javascript" src="~/res/ts/bfs.js"></script> <script type="text/javascript" src="~/res/ts/bfs.js"></script>
@RenderSection("scripts", false) @RenderSection("scripts", false)
</body> </body>

View File

@ -21,11 +21,17 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.OldPassword, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.OldPassword, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.PasswordFor(model => model.OldPassword, new { @class = "form-control" }) @Html.PasswordFor(model => model.OldPassword, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.OldPassword) @Html.ValidationMessageFor(model => model.OldPassword)
@ -33,11 +39,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.NewPassword, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.NewPassword, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.PasswordFor(model => model.NewPassword, new { @class = "form-control" }) @Html.PasswordFor(model => model.NewPassword, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.NewPassword) @Html.ValidationMessageFor(model => model.NewPassword)
@ -45,11 +57,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.ConfirmNewPassword, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.ConfirmNewPassword, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.PasswordFor(model => model.ConfirmNewPassword, new { @class = "form-control" }) @Html.PasswordFor(model => model.ConfirmNewPassword, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.ConfirmNewPassword) @Html.ValidationMessageFor(model => model.ConfirmNewPassword)

View File

@ -21,11 +21,17 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.UserName, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.TextBoxFor(model => model.UserName, new { @class = "form-control" }) @Html.TextBoxFor(model => model.UserName, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName)
@ -33,11 +39,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.Password, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.PasswordFor(model => model.Password, new { @class = "form-control" }) @Html.PasswordFor(model => model.Password, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.Password) @Html.ValidationMessageFor(model => model.Password)
@ -45,11 +57,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.ConfirmPassword, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.ConfirmPassword, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.PasswordFor(model => model.ConfirmPassword, new { @class = "form-control" }) @Html.PasswordFor(model => model.ConfirmPassword, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.ConfirmPassword) @Html.ValidationMessageFor(model => model.ConfirmPassword)
@ -57,11 +75,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
@Html.LabelFor(model => model.EmailAddress, new { @class = "control-label col-md-2" }) @Html.LabelFor(model => model.EmailAddress, new
{
@class = "control-label col-md-2"
})
<div class="col-md-10"> <div class="col-md-10">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
@Html.TextBoxFor(model => model.EmailAddress, new { @class = "form-control" }) @Html.TextBoxFor(model => model.EmailAddress, new
{
@class = "form-control"
})
</div> </div>
</div> </div>
@Html.ValidationMessageFor(model => model.EmailAddress) @Html.ValidationMessageFor(model => model.EmailAddress)

View File

@ -1,5 +1,5 @@
@using BuildFeed.Model.View @using BuildFeed.Model.View
@model SitemapData @model BuildFeed.Model.View.SitemapData
@{ @{
ViewBag.Title = $"{VariantTerms.Common_Sitemap} | {InvariantTerms.SiteName}"; ViewBag.Title = $"{VariantTerms.Common_Sitemap} | {InvariantTerms.SiteName}";
} }

View File

@ -1,6 +1,5 @@
 @{
@{ ViewBag.Title = $"{VariantTerms.Support_ThanksRegister} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{VariantTerms.Support_ThanksRegister} | {BuildFeed.Local.InvariantTerms.SiteName}";
} }
<h1>@VariantTerms.Support_ThanksRegister</h1> <h1>@VariantTerms.Support_ThanksRegister</h1>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<staticContent> <staticContent>

View File

@ -1,16 +1,16 @@
{ {
"name": "BuildFeed", "name": "BuildFeed",
"short_name": "BuildFeed", "short_name": "BuildFeed",
"background_color": "#373736", "background_color": "#373736",
"theme_color": "#373736", "theme_color": "#373736",
"description": "Learn what Dona Sarkar won't tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker.", "description": "Learn what Dona Sarkar won't tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker.",
"icons": [ "icons": [
{ {
"src": "https://buildfeed.net/content/tile/notify.png", "src": "https://buildfeed.net/content/tile/notify.png",
"sizes": "2048x2048" "sizes": "2048x2048"
} }
], ],
"start_url": "https://buildfeed.net/", "start_url": "https://buildfeed.net/",
"display": "standalone", "display": "standalone",
"gcm_sender_id": "482941778795" "gcm_sender_id": "482941778795"
} }

View File

@ -1,82 +1,83 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="google.analytics.TypeScript.DefinitelyTyped" version="0.3.8" targetFramework="net462" /> <package id="google.analytics.TypeScript.DefinitelyTyped" version="0.3.8" targetFramework="net462" />
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net462" /> <package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net462" />
<package id="Humanizer" version="2.1.0" targetFramework="net462" /> <package id="Humanizer" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.af" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.af" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.ar" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.ar" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.bg" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.bg" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.bn-BD" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.bn-BD" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.cs" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.cs" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.da" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.da" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.de" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.de" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.el" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.el" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.es" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.es" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.fa" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.fa" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.fi-FI" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.fi-FI" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.fr" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.fr" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.fr-BE" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.fr-BE" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.he" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.he" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.hr" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.hr" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.hu" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.hu" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.id" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.id" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.it" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.it" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.ja" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.ja" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.nb" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.nb" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.nb-NO" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.nb-NO" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.nl" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.nl" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.pl" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.pl" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.pt" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.pt" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.ro" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.ro" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.ru" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.ru" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.sk" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.sk" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.sl" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.sl" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.sr" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.sr" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.sr-Latn" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.sr-Latn" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.sv" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.sv" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.tr" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.tr" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.uk" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.uk" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.uz-Cyrl-UZ" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.uz-Cyrl-UZ" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.uz-Latn-UZ" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.uz-Latn-UZ" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.vi" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.vi" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.zh-CN" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.zh-CN" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.zh-Hans" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.zh-Hans" version="2.1.0" targetFramework="net462" />
<package id="Humanizer.Core.zh-Hant" version="2.1.0" targetFramework="net462" /> <package id="Humanizer.Core.zh-Hant" version="2.1.0" targetFramework="net462" />
<package id="jQuery" version="3.1.1" targetFramework="net462" /> <package id="jQuery" version="3.1.1" targetFramework="net462" />
<package id="jquery.TypeScript.DefinitelyTyped" version="3.1.2" targetFramework="net462" /> <package id="jquery.TypeScript.DefinitelyTyped" version="3.1.2" targetFramework="net462" />
<package id="jQuery.Validation" version="1.16.0" targetFramework="net462" /> <package id="jQuery.Validation" version="1.16.0" targetFramework="net462" />
<package id="jsrender.TypeScript.DefinitelyTyped" version="0.1.8" targetFramework="net461" /> <package id="jsrender.TypeScript.DefinitelyTyped" version="0.1.8" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.0.7" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.0.7" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.Web" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.Web" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.WindowsServer" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.2.0" targetFramework="net462" /> <package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.2.0" targetFramework="net462" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net462" />
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net462" /> <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net462" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.3" targetFramework="net462" /> <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.3" targetFramework="net462" />
<package id="Microsoft.CSharp" version="4.3.0" targetFramework="net462" /> <package id="Microsoft.CSharp" version="4.3.0" targetFramework="net462" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net462" /> <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net462" />
<package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net462" developmentDependency="true" /> <package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net462" developmentDependency="true" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net462" /> <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net462" />
<package id="MongoDB.Bson" version="2.4.2" targetFramework="net462" /> <package id="MongoDB.Bson" version="2.4.2" targetFramework="net462" />
<package id="MongoDB.Driver" version="2.4.2" targetFramework="net462" /> <package id="MongoDB.Driver" version="2.4.2" targetFramework="net462" />
<package id="MongoDB.Driver.Core" version="2.4.2" targetFramework="net462" /> <package id="MongoDB.Driver.Core" version="2.4.2" targetFramework="net462" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net462" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net462" />
<package id="OneSignal.CSharp.SDK" version="0.9" targetFramework="net462" /> <package id="OneSignal.CSharp.SDK" version="0.9" targetFramework="net462" />
<package id="RestSharp" version="105.2.3" targetFramework="net462" /> <package id="RestSharp" version="105.2.3" targetFramework="net462" />
<package id="System.Collections" version="4.3.0" targetFramework="net462" /> <package id="System.Collections" version="4.3.0" targetFramework="net462" />
<package id="System.Linq" version="4.3.0" targetFramework="net462" /> <package id="System.Linq" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime" version="4.3.0" targetFramework="net462" /> <package id="System.Runtime" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" /> <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" />
<package id="System.Threading" version="4.3.0" targetFramework="net462" /> <package id="System.Threading" version="4.3.0" targetFramework="net462" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net462" /> <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net462" />
<package id="WilderMinds.RssSyndication" version="1.0.4" targetFramework="net462" /> <package id="WilderMinds.RssSyndication" version="1.0.4" targetFramework="net462" />
</packages> </packages>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<staticContent> <staticContent>

View File

@ -1 +1 @@
{"version":3,"sources":["dark.scss","dark.css"],"names":[],"mappings":"AAAA,KAEI,iBAAA,QACA,MAAA,QAGJ,EAEI,MAAA,KCAJ,eDGA,KAGI,MAAA,QAGJ,eAEI,oBAAA,QAGJ,cAEI,iBAAA,QACA,MAAA,QAHJ,iBAOQ,oBAAA,KAIR,iBAEI,iBAAA,QACA,MAAA,QACA,oBAAA,QAJJ,wBAQQ,MAAA,QARR,6CAiBgB,MAAA,QAjBhB,kDCJE,mDD2Bc,iBAAA,QAMhB,eAEI,iBAAA,QACA,aAAA,QACA,WAAA,EAAA,IAAA,KAAA,gBC5BF,wBADA,uBDyBF,uBAUQ,iBAAA,QAIR,QAEI,WAAA,EAAA,IAAA,KAAA,gBAAA,MAFJ,WAAA,WAMQ,MAAA,QCnCN,kCD6BF,0BC9BE,oBD2CM,MAAA,QAIR,0BAIQ,WAAA,QACA,MAAA,kBC1CR,yCADA,wCDsCA,wCAYQ,WAAA,QACA,MAAA,kBAIR,oCAEI,iBAAA,QAFJ,uCAMQ,MAAA,QCnDN,2ED6CF,0EAYQ,iBAAA,QACA,MAAA,QACA,aAAA","file":"dark.css","sourcesContent":["body\r\n{\r\n background-color: #f6f5f3;\r\n color: #373736;\r\n}\r\n\r\na\r\n{\r\n color: #fff;\r\n}\r\n\r\nh1 > a,\r\n#page-footer a\r\n{\r\n color: #373736;\r\n}\r\n\r\ntable thead th\r\n{\r\n border-bottom-color: #f6f5f3;\r\n}\r\n\r\n#page-content\r\n{\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n\r\n h3\r\n {\r\n border-bottom-color: #ccc;\r\n }\r\n}\r\n\r\n#page-navigation\r\n{\r\n background-color: #242423;\r\n color: #f6f5f3;\r\n border-bottom-color: #f6f5f3;\r\n\r\n button\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n #page-navigation-links\r\n {\r\n > li\r\n {\r\n a\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n &.open > a,\r\n > a:hover\r\n {\r\n background-color: #373736;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.dropdown-menu\r\n{\r\n background-color: #242423;\r\n border-color: #f6f5f3;\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15);\r\n\r\n a:hover,\r\n a:focus,\r\n a:active\r\n {\r\n background-color: #373736;\r\n }\r\n}\r\n\r\narticle\r\n{\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15) inset;\r\n\r\n h1, h3\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n .build-group > h3 > a,\r\n a.more-link,\r\n .build-details-comments a\r\n {\r\n color: #d6d5d3;\r\n }\r\n}\r\n\r\nul.pagination\r\n{\r\n > li.active > a\r\n {\r\n background: #f6f5f3;\r\n color: #242423 !important;\r\n }\r\n\r\n > li:hover:not(.disabled) > a,\r\n > li:focus:not(.disabled) > a,\r\n > li:active:not(.disabled) > a\r\n {\r\n background: #d6d5d3;\r\n color: #373736 !important;\r\n }\r\n}\r\n\r\n#modal-search-overlay #modal-search\r\n{\r\n background-color: #242423;\r\n\r\n h3\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n > #modal-search-box > #modal-search-input,\r\n > #modal-search-box > #modal-search-button\r\n {\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n border-color: #d6d5d3;\r\n }\r\n}\r\n","body{background-color:#f6f5f3;color:#373736}a{color:#fff}#page-footer a,h1>a{color:#373736}table thead th{border-bottom-color:#f6f5f3}#page-content{background-color:#373736;color:#f6f5f3}#page-content h3{border-bottom-color:#ccc}#page-navigation{background-color:#242423;color:#f6f5f3;border-bottom-color:#f6f5f3}#page-navigation button{color:#f6f5f3}#page-navigation #page-navigation-links>li a{color:#f6f5f3}#page-navigation #page-navigation-links>li.open>a,#page-navigation #page-navigation-links>li>a:hover{background-color:#373736}.dropdown-menu{background-color:#242423;border-color:#f6f5f3;box-shadow:0 5px 10px rgba(0,0,0,.15)}.dropdown-menu a:active,.dropdown-menu a:focus,.dropdown-menu a:hover{background-color:#373736}article{box-shadow:0 5px 10px rgba(0,0,0,.15) inset}article h1,article h3{color:#f6f5f3}article .build-details-comments a,article .build-group>h3>a,article a.more-link{color:#d6d5d3}ul.pagination>li.active>a{background:#f6f5f3;color:#242423!important}ul.pagination>li:active:not(.disabled)>a,ul.pagination>li:focus:not(.disabled)>a,ul.pagination>li:hover:not(.disabled)>a{background:#d6d5d3;color:#373736!important}#modal-search-overlay #modal-search{background-color:#242423}#modal-search-overlay #modal-search h3{color:#f6f5f3}#modal-search-overlay #modal-search>#modal-search-box>#modal-search-button,#modal-search-overlay #modal-search>#modal-search-box>#modal-search-input{background-color:#373736;color:#f6f5f3;border-color:#d6d5d3}\n/*# sourceMappingURL=dark.css.map */\n"]} {"version":3,"sources":["dark.scss","dark.css"],"names":[],"mappings":"AAAA,KAEI,iBAAA,QACA,MAAA,QAGJ,EAEI,MAAA,KCAJ,eDGA,KAGI,MAAA,QAGJ,eAEI,oBAAA,QAGJ,cAEI,iBAAA,QACA,MAAA,QAHJ,iBAOQ,oBAAA,KAIR,iBAEI,iBAAA,QACA,MAAA,QACA,oBAAA,QAJJ,wBAQQ,MAAA,QARR,6CAiBgB,MAAA,QAjBhB,kDCJE,mDD2Bc,iBAAA,QAMhB,eAEI,iBAAA,QACA,aAAA,QACA,WAAA,EAAA,IAAA,KAAA,gBC5BF,wBADA,uBDyBF,uBAUQ,iBAAA,QAIR,QAEI,WAAA,EAAA,IAAA,KAAA,gBAAA,MAFJ,WAAA,WAMQ,MAAA,QCnCN,kCD6BF,0BC9BE,oBD2CM,MAAA,QAIR,0BAIQ,WAAA,QACA,MAAA,kBC1CR,yCADA,wCDsCA,wCAYQ,WAAA,QACA,MAAA,kBAIR,oCAEI,iBAAA,QAFJ,uCAMQ,MAAA,QCnDN,2ED6CF,0EAYQ,iBAAA,QACA,MAAA,QACA,aAAA","file":"dark.css","sourcesContent":["body\r\n{\r\n background-color: #f6f5f3;\r\n color: #373736;\r\n}\r\n\r\na\r\n{\r\n color: #fff;\r\n}\r\n\r\nh1 > a,\r\n#page-footer a\r\n{\r\n color: #373736;\r\n}\r\n\r\ntable thead th\r\n{\r\n border-bottom-color: #f6f5f3;\r\n}\r\n\r\n#page-content\r\n{\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n\r\n h3\r\n {\r\n border-bottom-color: #ccc;\r\n }\r\n}\r\n\r\n#page-navigation\r\n{\r\n background-color: #242423;\r\n color: #f6f5f3;\r\n border-bottom-color: #f6f5f3;\r\n\r\n button\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n #page-navigation-links\r\n {\r\n > li\r\n {\r\n a\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n &.open > a,\r\n > a:hover\r\n {\r\n background-color: #373736;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.dropdown-menu\r\n{\r\n background-color: #242423;\r\n border-color: #f6f5f3;\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15);\r\n\r\n a:hover,\r\n a:focus,\r\n a:active\r\n {\r\n background-color: #373736;\r\n }\r\n}\r\n\r\narticle\r\n{\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15) inset;\r\n\r\n h1, h3\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n .build-group > h3 > a,\r\n a.more-link,\r\n .build-details-comments a\r\n {\r\n color: #d6d5d3;\r\n }\r\n}\r\n\r\nul.pagination\r\n{\r\n > li.active > a\r\n {\r\n background: #f6f5f3;\r\n color: #242423 !important;\r\n }\r\n\r\n > li:hover:not(.disabled) > a,\r\n > li:focus:not(.disabled) > a,\r\n > li:active:not(.disabled) > a\r\n {\r\n background: #d6d5d3;\r\n color: #373736 !important;\r\n }\r\n}\r\n\r\n#modal-search-overlay #modal-search\r\n{\r\n background-color: #242423;\r\n\r\n h3\r\n {\r\n color: #f6f5f3;\r\n }\r\n\r\n > #modal-search-box > #modal-search-input,\r\n > #modal-search-box > #modal-search-button\r\n {\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n border-color: #d6d5d3;\r\n }\r\n}\r\n","body\n{\n background-color: #f6f5f3;\n color: #373736\n}\n\na\n{\n color: #fff\n}\n\n#page-footer a, h1 > a\n{\n color: #373736\n}\n\ntable thead th\n{\n border-bottom-color: #f6f5f3\n}\n\n#page-content\n{\n background-color: #373736;\n color: #f6f5f3\n}\n\n#page-content h3\n{\n border-bottom-color: #ccc\n}\n\n#page-navigation\n{\n background-color: #242423;\n border-bottom-color: #f6f5f3;\n color: #f6f5f3;\n}\n\n#page-navigation button\n{\n color: #f6f5f3\n}\n\n#page-navigation #page-navigation-links > li a\n{\n color: #f6f5f3\n}\n\n#page-navigation #page-navigation-links > li.open > a, #page-navigation #page-navigation-links > li > a:hover\n{\n background-color: #373736\n}\n\n.dropdown-menu\n{\n background-color: #242423;\n border-color: #f6f5f3;\n box-shadow: 0 5px 10px rgba(0, 0, 0, .15)\n}\n\n.dropdown-menu a:active, .dropdown-menu a:focus, .dropdown-menu a:hover\n{\n background-color: #373736\n}\n\narticle\n{\n box-shadow: 0 5px 10px rgba(0, 0, 0, .15) inset\n}\n\narticle h1, article h3\n{\n color: #f6f5f3\n}\n\narticle .build-details-comments a, article .build-group > h3 > a, article a.more-link\n{\n color: #d6d5d3\n}\n\nul.pagination > li.active > a\n{\n background: #f6f5f3;\n color: #242423 !important\n}\n\nul.pagination > li:active:not(.disabled) > a, ul.pagination > li:focus:not(.disabled) > a, ul.pagination > li:hover:not(.disabled) > a\n{\n background: #d6d5d3;\n color: #373736 !important\n}\n\n#modal-search-overlay #modal-search\n{\n background-color: #242423\n}\n\n#modal-search-overlay #modal-search h3\n{\n color: #f6f5f3\n}\n\n#modal-search-overlay #modal-search > #modal-search-box > #modal-search-button, #modal-search-overlay #modal-search > #modal-search-box > #modal-search-input\n{\n background-color: #373736;\n border-color: #d6d5d3;\n color: #f6f5f3;\n}\n/*# sourceMappingURL=dark.css.map */"]}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"version":3,"sources":["light.scss","light.css"],"names":[],"mappings":"AAAA,KAEG,iBAAA,QACA,MAAA,QAGH,EAEG,MAAA,KCAH,eDGA,KAGG,MAAA,QAGH,eAEG,oBAAA,QAGH,cAEG,iBAAA,QACA,MAAA,QAHH,iBAOM,oBAAA,KAIN,iBAEG,iBAAA,QACA,MAAA,QACA,oBAAA,QAJH,wBAQM,MAAA,QARN,6CAiBY,MAAA,QAjBZ,kDCJE,mDD2BU,iBAAA,QAMZ,eAEG,iBAAA,QACA,aAAA,QACA,WAAA,EAAA,IAAA,KAAA,gBC5BD,wBADA,uBDyBF,uBAUM,iBAAA,QAIN,QAEG,WAAA,KAFH,WAAA,WAMM,MAAA,QCnCJ,kCD6BF,0BC9BE,oBD2CI,MAAA,QAIN,0BAIM,WAAA,QACA,MAAA,kBC1CN,yCADA,wCDsCA,wCAYM,WAAA,QACA,MAAA,kBAIN,oCAEG,iBAAA,QAFH,uCAMM,MAAA,QCnDJ,2ED6CF,0EAYM,iBAAA,KACA,MAAA,QACA,aAAA","file":"light.css","sourcesContent":["body\r\n{\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n}\r\n\r\na\r\n{\r\n color: #000;\r\n}\r\n\r\nh1 > a,\r\n#page-footer a\r\n{\r\n color: #f6f5f3;\r\n}\r\n\r\ntable thead th\r\n{\r\n border-bottom-color: #373736;\r\n}\r\n\r\n#page-content\r\n{\r\n background-color: #f6f5f3;\r\n color: #373736;\r\n\r\n h3\r\n {\r\n border-bottom-color: #ccc;\r\n }\r\n}\r\n\r\n#page-navigation\r\n{\r\n background-color: #e6e5e3;\r\n color: #373736;\r\n border-bottom-color: #373736;\r\n\r\n button\r\n {\r\n color: #373736;\r\n }\r\n\r\n #page-navigation-links\r\n {\r\n > li\r\n {\r\n a\r\n {\r\n color: #373736;\r\n }\r\n\r\n &.open > a,\r\n > a:hover\r\n {\r\n background-color: #f6f5f3;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.dropdown-menu\r\n{\r\n background-color: #e6e5e3;\r\n border-color: #373736;\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15);\r\n\r\n a:hover,\r\n a:focus,\r\n a:active\r\n {\r\n background-color: #f6f5f3;\r\n }\r\n}\r\n\r\narticle\r\n{\r\n box-shadow: none;\r\n\r\n h1, h3\r\n {\r\n color: #242423;\r\n }\r\n\r\n .build-group > h3 > a,\r\n a.more-link,\r\n .build-details-comments a\r\n {\r\n color: #242423;\r\n }\r\n}\r\n\r\nul.pagination\r\n{\r\n > li.active > a\r\n {\r\n background: #373736;\r\n color: #e6e5e3 !important;\r\n }\r\n\r\n > li:hover:not(.disabled) > a,\r\n > li:focus:not(.disabled) > a,\r\n > li:active:not(.disabled) > a\r\n {\r\n background: #242423;\r\n color: #f6f5f3 !important;\r\n }\r\n}\r\n\r\n#modal-search-overlay #modal-search\r\n{\r\n background-color: #f6f5f3;\r\n\r\n h3\r\n {\r\n color: #373736;\r\n }\r\n\r\n > #modal-search-box > #modal-search-input,\r\n > #modal-search-box > #modal-search-button\r\n {\r\n background-color: #fff;\r\n color: #373736;\r\n border-color: #242423;\r\n }\r\n}\r\n","body{background-color:#373736;color:#f6f5f3}a{color:#000}#page-footer a,h1>a{color:#f6f5f3}table thead th{border-bottom-color:#373736}#page-content{background-color:#f6f5f3;color:#373736}#page-content h3{border-bottom-color:#ccc}#page-navigation{background-color:#e6e5e3;color:#373736;border-bottom-color:#373736}#page-navigation button{color:#373736}#page-navigation #page-navigation-links>li a{color:#373736}#page-navigation #page-navigation-links>li.open>a,#page-navigation #page-navigation-links>li>a:hover{background-color:#f6f5f3}.dropdown-menu{background-color:#e6e5e3;border-color:#373736;box-shadow:0 5px 10px rgba(0,0,0,.15)}.dropdown-menu a:active,.dropdown-menu a:focus,.dropdown-menu a:hover{background-color:#f6f5f3}article{box-shadow:none}article h1,article h3{color:#242423}article .build-details-comments a,article .build-group>h3>a,article a.more-link{color:#242423}ul.pagination>li.active>a{background:#373736;color:#e6e5e3!important}ul.pagination>li:active:not(.disabled)>a,ul.pagination>li:focus:not(.disabled)>a,ul.pagination>li:hover:not(.disabled)>a{background:#242423;color:#f6f5f3!important}#modal-search-overlay #modal-search{background-color:#f6f5f3}#modal-search-overlay #modal-search h3{color:#373736}#modal-search-overlay #modal-search>#modal-search-box>#modal-search-button,#modal-search-overlay #modal-search>#modal-search-box>#modal-search-input{background-color:#fff;color:#373736;border-color:#242423}\n/*# sourceMappingURL=light.css.map */\n"]} {"version":3,"sources":["light.scss","light.css"],"names":[],"mappings":"AAAA,KAEG,iBAAA,QACA,MAAA,QAGH,EAEG,MAAA,KCAH,eDGA,KAGG,MAAA,QAGH,eAEG,oBAAA,QAGH,cAEG,iBAAA,QACA,MAAA,QAHH,iBAOM,oBAAA,KAIN,iBAEG,iBAAA,QACA,MAAA,QACA,oBAAA,QAJH,wBAQM,MAAA,QARN,6CAiBY,MAAA,QAjBZ,kDCJE,mDD2BU,iBAAA,QAMZ,eAEG,iBAAA,QACA,aAAA,QACA,WAAA,EAAA,IAAA,KAAA,gBC5BD,wBADA,uBDyBF,uBAUM,iBAAA,QAIN,QAEG,WAAA,KAFH,WAAA,WAMM,MAAA,QCnCJ,kCD6BF,0BC9BE,oBD2CI,MAAA,QAIN,0BAIM,WAAA,QACA,MAAA,kBC1CN,yCADA,wCDsCA,wCAYM,WAAA,QACA,MAAA,kBAIN,oCAEG,iBAAA,QAFH,uCAMM,MAAA,QCnDJ,2ED6CF,0EAYM,iBAAA,KACA,MAAA,QACA,aAAA","file":"light.css","sourcesContent":["body\r\n{\r\n background-color: #373736;\r\n color: #f6f5f3;\r\n}\r\n\r\na\r\n{\r\n color: #000;\r\n}\r\n\r\nh1 > a,\r\n#page-footer a\r\n{\r\n color: #f6f5f3;\r\n}\r\n\r\ntable thead th\r\n{\r\n border-bottom-color: #373736;\r\n}\r\n\r\n#page-content\r\n{\r\n background-color: #f6f5f3;\r\n color: #373736;\r\n\r\n h3\r\n {\r\n border-bottom-color: #ccc;\r\n }\r\n}\r\n\r\n#page-navigation\r\n{\r\n background-color: #e6e5e3;\r\n color: #373736;\r\n border-bottom-color: #373736;\r\n\r\n button\r\n {\r\n color: #373736;\r\n }\r\n\r\n #page-navigation-links\r\n {\r\n > li\r\n {\r\n a\r\n {\r\n color: #373736;\r\n }\r\n\r\n &.open > a,\r\n > a:hover\r\n {\r\n background-color: #f6f5f3;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.dropdown-menu\r\n{\r\n background-color: #e6e5e3;\r\n border-color: #373736;\r\n box-shadow: 0 5px 10px rgba(0,0,0,0.15);\r\n\r\n a:hover,\r\n a:focus,\r\n a:active\r\n {\r\n background-color: #f6f5f3;\r\n }\r\n}\r\n\r\narticle\r\n{\r\n box-shadow: none;\r\n\r\n h1, h3\r\n {\r\n color: #242423;\r\n }\r\n\r\n .build-group > h3 > a,\r\n a.more-link,\r\n .build-details-comments a\r\n {\r\n color: #242423;\r\n }\r\n}\r\n\r\nul.pagination\r\n{\r\n > li.active > a\r\n {\r\n background: #373736;\r\n color: #e6e5e3 !important;\r\n }\r\n\r\n > li:hover:not(.disabled) > a,\r\n > li:focus:not(.disabled) > a,\r\n > li:active:not(.disabled) > a\r\n {\r\n background: #242423;\r\n color: #f6f5f3 !important;\r\n }\r\n}\r\n\r\n#modal-search-overlay #modal-search\r\n{\r\n background-color: #f6f5f3;\r\n\r\n h3\r\n {\r\n color: #373736;\r\n }\r\n\r\n > #modal-search-box > #modal-search-input,\r\n > #modal-search-box > #modal-search-button\r\n {\r\n background-color: #fff;\r\n color: #373736;\r\n border-color: #242423;\r\n }\r\n}\r\n","body\n{\n background-color: #373736;\n color: #f6f5f3\n}\n\na\n{\n color: #000\n}\n\n#page-footer a, h1 > a\n{\n color: #f6f5f3\n}\n\ntable thead th\n{\n border-bottom-color: #373736\n}\n\n#page-content\n{\n background-color: #f6f5f3;\n color: #373736\n}\n\n#page-content h3\n{\n border-bottom-color: #ccc\n}\n\n#page-navigation\n{\n background-color: #e6e5e3;\n border-bottom-color: #373736;\n color: #373736;\n}\n\n#page-navigation button\n{\n color: #373736\n}\n\n#page-navigation #page-navigation-links > li a\n{\n color: #373736\n}\n\n#page-navigation #page-navigation-links > li.open > a, #page-navigation #page-navigation-links > li > a:hover\n{\n background-color: #f6f5f3\n}\n\n.dropdown-menu\n{\n background-color: #e6e5e3;\n border-color: #373736;\n box-shadow: 0 5px 10px rgba(0, 0, 0, .15)\n}\n\n.dropdown-menu a:active, .dropdown-menu a:focus, .dropdown-menu a:hover\n{\n background-color: #f6f5f3\n}\n\narticle\n{\n box-shadow: none\n}\n\narticle h1, article h3\n{\n color: #242423\n}\n\narticle .build-details-comments a, article .build-group > h3 > a, article a.more-link\n{\n color: #242423\n}\n\nul.pagination > li.active > a\n{\n background: #373736;\n color: #e6e5e3 !important\n}\n\nul.pagination > li:active:not(.disabled) > a, ul.pagination > li:focus:not(.disabled) > a, ul.pagination > li:hover:not(.disabled) > a\n{\n background: #242423;\n color: #f6f5f3 !important\n}\n\n#modal-search-overlay #modal-search\n{\n background-color: #f6f5f3\n}\n\n#modal-search-overlay #modal-search h3\n{\n color: #373736\n}\n\n#modal-search-overlay #modal-search > #modal-search-box > #modal-search-button, #modal-search-overlay #modal-search > #modal-search-box > #modal-search-input\n{\n background-color: #fff;\n border-color: #242423;\n color: #373736;\n}\n/*# sourceMappingURL=light.css.map */"]}

View File

@ -1,4 +1,6 @@
<html> <html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>Verification: 702baad42b020be7</body> <body>Verification: 702baad42b020be7</body>
</html> </html>