Code style update; Project cleanup

refactor-intermediate-models
BuildFeed Bot 2018-02-06 22:16:37 +00:00
parent e6f5ac6fe4
commit 2f247cfb40
93 changed files with 3134 additions and 27149 deletions

View File

@ -17,7 +17,7 @@ namespace MongoAuth
var returnArray = new byte[byteCount];
byte curByte = 0,
bitsRemaining = 8;
bitsRemaining = 8;
int arrayIndex = 0;
@ -62,7 +62,7 @@ namespace MongoAuth
var returnArray = new char[charCount];
byte nextChar = 0,
bitsRemaining = 5;
bitsRemaining = 5;
int arrayIndex = 0;
foreach (byte b in input)
@ -86,7 +86,9 @@ namespace MongoAuth
{
returnArray[arrayIndex++] = ValueToChar(nextChar);
while (arrayIndex != charCount)
{
returnArray[arrayIndex++] = '='; //padding
}
}
return new string(returnArray);
@ -101,11 +103,13 @@ namespace MongoAuth
{
return value - 65;
}
//50-55 == numbers 2-7
if (value < 56 && value > 49)
{
return value - 24;
}
//97-122 == lowercase letters
if (value < 123 && value > 96)
{

View File

@ -21,6 +21,7 @@ namespace MongoAuth
{
port = 27017; // mongo default port
}
Port = port;
Database = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoDB"])

View File

@ -59,13 +59,14 @@ namespace MongoAuth
_enablePasswordReset = TryReadBool(config["enablePasswordReset"], _enablePasswordReset);
_maxInvalidPasswordAttempts = TryReadInt(config["maxInvalidPasswordAttempts"], _maxInvalidPasswordAttempts);
_minRequiredNonAlphanumericCharacters = TryReadInt(config["minRequiredNonAlphanumericCharacters"], _minRequiredNonAlphanumericCharacters);
_minRequiredNonAlphanumericCharacters = TryReadInt(config["minRequiredNonAlphanumericCharacters"],
_minRequiredNonAlphanumericCharacters);
_minRequriedPasswordLength = TryReadInt(config["minRequriedPasswordLength"], _minRequriedPasswordLength);
_passwordAttemptWindow = TryReadInt(config["passwordAttemptWindow"], _passwordAttemptWindow);
_requiresUniqueEmail = TryReadBool(config["requiresUniqueEmail"], _requiresUniqueEmail);
MongoClientSettings settings = new MongoClientSettings
var settings = new MongoClientSettings
{
Server = new MongoServerAddress(DatabaseConfig.Host, DatabaseConfig.Port)
};
@ -77,22 +78,24 @@ namespace MongoAuth
DatabaseConfig.Password);
}
MongoClient dbClient = new MongoClient(settings);
var dbClient = new MongoClient(settings);
_memberCollection = dbClient.GetDatabase(DatabaseConfig.Database).GetCollection<MongoMember>(MEMBER_COLLECTION_NAME);
_memberCollection = dbClient.GetDatabase(DatabaseConfig.Database)
.GetCollection<MongoMember>(MEMBER_COLLECTION_NAME);
#pragma warning disable 4014
#pragma warning disable 4014
SetupIndexes();
#pragma warning restore 4014
#pragma warning restore 4014
}
public async Task SetupIndexes()
{
List<BsonDocument> indexes = await (await _memberCollection.Indexes.ListAsync()).ToListAsync();
var indexes = await (await _memberCollection.Indexes.ListAsync()).ToListAsync();
if (indexes.All(i => i["name"] != "_idx_username"))
{
await _memberCollection.Indexes.CreateOneAsync(Builders<MongoMember>.IndexKeys.Ascending(b => b.UserName),
await _memberCollection.Indexes.CreateOneAsync(
Builders<MongoMember>.IndexKeys.Ascending(b => b.UserName),
new CreateIndexOptions
{
Name = "_idx_username",
@ -102,7 +105,8 @@ namespace MongoAuth
if (indexes.All(i => i["name"] != "_idx_email"))
{
await _memberCollection.Indexes.CreateOneAsync(Builders<MongoMember>.IndexKeys.Ascending(b => b.EmailAddress),
await _memberCollection.Indexes.CreateOneAsync(
Builders<MongoMember>.IndexKeys.Ascending(b => b.EmailAddress),
new CreateIndexOptions
{
Name = "_idx_email",
@ -117,7 +121,8 @@ namespace MongoAuth
if (isAuthenticated)
{
Task<MongoMember> task = _memberCollection.Find(m => m.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync();
var task = _memberCollection.Find(m => m.UserName.ToLower() == username.ToLower())
.SingleOrDefaultAsync();
task.Wait();
MongoMember mm = task.Result;
@ -127,12 +132,12 @@ namespace MongoAuth
}
var salt = new byte[24];
byte[] hash = CalculateHash(newPassword, ref salt);
var hash = CalculateHash(newPassword, ref salt);
mm.PassSalt = salt;
mm.PassHash = hash;
Task<ReplaceOneResult> replaceTask = _memberCollection.ReplaceOneAsync(m => m.Id == mm.Id, mm);
var replaceTask = _memberCollection.ReplaceOneAsync(m => m.Id == mm.Id, mm);
replaceTask.Wait();
return replaceTask.IsCompleted;
@ -141,12 +146,12 @@ namespace MongoAuth
return false;
}
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotImplementedException();
}
public override bool ChangePasswordQuestionAndAnswer(string username, string password,
string newPasswordQuestion, string newPasswordAnswer) => throw new NotImplementedException();
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
public override MembershipUser CreateUser(string username, string password, string email,
string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey,
out MembershipCreateStatus status)
{
if (password.Length < MinRequiredPasswordLength)
{
@ -156,8 +161,8 @@ namespace MongoAuth
MembershipUser mu = null;
Task<long> dupeUsers = _memberCollection.Find(m => m.UserName.ToLower() == username.ToLower()).CountAsync();
Task<long> dupeEmails = _memberCollection.Find(m => m.EmailAddress.ToLower() == email.ToLower()).CountAsync();
var dupeUsers = _memberCollection.Find(m => m.UserName.ToLower() == username.ToLower()).CountAsync();
var dupeEmails = _memberCollection.Find(m => m.EmailAddress.ToLower() == email.ToLower()).CountAsync();
dupeUsers.Wait();
dupeEmails.Wait();
@ -172,9 +177,9 @@ namespace MongoAuth
else
{
var salt = new byte[24];
byte[] hash = CalculateHash(password, ref salt);
var hash = CalculateHash(password, ref salt);
MongoMember mm = new MongoMember
var mm = new MongoMember
{
Id = Guid.NewGuid(),
UserName = username,
@ -195,7 +200,19 @@ namespace MongoAuth
if (insertTask.Status == TaskStatus.RanToCompletion)
{
status = MembershipCreateStatus.Success;
mu = new MembershipUser(Name, mm.UserName, mm.Id, mm.EmailAddress, "", "", mm.IsApproved, mm.IsLockedOut, mm.CreationDate, mm.LastLoginDate, mm.LastActivityDate, DateTime.MinValue, mm.LastLockoutDate);
mu = new MembershipUser(Name,
mm.UserName,
mm.Id,
mm.EmailAddress,
"",
"",
mm.IsApproved,
mm.IsLockedOut,
mm.CreationDate,
mm.LastLoginDate,
mm.LastActivityDate,
DateTime.MinValue,
mm.LastLockoutDate);
}
else
{
@ -208,7 +225,7 @@ namespace MongoAuth
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
Task<DeleteResult> task = _memberCollection.DeleteOneAsync(m => m.UserName.ToLower() == username.ToLower());
var task = _memberCollection.DeleteOneAsync(m => m.UserName.ToLower() == username.ToLower());
task.Wait();
return task.Result.IsAcknowledged && task.Result.DeletedCount == 1;
@ -216,94 +233,119 @@ namespace MongoAuth
public bool DeleteUser(Guid id)
{
Task<DeleteResult> task = _memberCollection.DeleteOneAsync(m => m.Id == id);
var task = _memberCollection.DeleteOneAsync(m => m.Id == id);
task.Wait();
return task.Result.IsAcknowledged && task.Result.DeletedCount == 1;
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
out int totalRecords) => throw new NotImplementedException();
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
out int totalRecords) => throw new NotImplementedException();
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection muc = new MembershipUserCollection();
var muc = new MembershipUserCollection();
IFindFluent<MongoMember, MongoMember> users = _memberCollection.Find(new BsonDocument()).Sort(Builders<MongoMember>.Sort.Ascending(m => m.UserName));
var users = _memberCollection.Find(new BsonDocument())
.Sort(Builders<MongoMember>.Sort.Ascending(m => m.UserName));
Task<long> totalRecordsTask = users.CountAsync();
var totalRecordsTask = users.CountAsync();
totalRecordsTask.Wait();
totalRecords = Convert.ToInt32(totalRecordsTask.Result);
users = users.Skip(pageIndex * pageSize).Limit(pageSize);
Task<List<MongoMember>> pageItemsTask = users.ToListAsync();
var pageItemsTask = users.ToListAsync();
pageItemsTask.Wait();
foreach (MongoMember mm in pageItemsTask.Result)
{
muc.Add(new MembershipUser(Name, mm.UserName, mm.Id, mm.EmailAddress, "", "", mm.IsApproved, mm.IsLockedOut, FixupDatesFromMongo(mm.CreationDate), FixupDatesFromMongo(mm.LastLoginDate), FixupDatesFromMongo(mm.LastActivityDate), DateTime.MinValue, FixupDatesFromMongo(mm.LastLockoutDate)));
muc.Add(new MembershipUser(Name,
mm.UserName,
mm.Id,
mm.EmailAddress,
"",
"",
mm.IsApproved,
mm.IsLockedOut,
FixupDatesFromMongo(mm.CreationDate),
FixupDatesFromMongo(mm.LastLoginDate),
FixupDatesFromMongo(mm.LastActivityDate),
DateTime.MinValue,
FixupDatesFromMongo(mm.LastLockoutDate)));
}
return muc;
}
public override int GetNumberOfUsersOnline()
{
throw new NotImplementedException();
}
public override int GetNumberOfUsersOnline() => throw new NotImplementedException();
public override string GetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override string GetPassword(string username, string answer) => throw new NotImplementedException();
public override MembershipUser GetUser(string username, bool userIsOnline)
{
Task<MongoMember> task = _memberCollection.Find(f => f.UserName.ToLower() == username.ToLower()).FirstOrDefaultAsync();
var task = _memberCollection.Find(f => f.UserName.ToLower() == username.ToLower()).FirstOrDefaultAsync();
task.Wait();
MongoMember mm = task.Result;
return mm == null
? null
: new MembershipUser(Name, mm.UserName, mm.Id, mm.EmailAddress, "", "", mm.IsApproved, mm.IsLockedOut, FixupDatesFromMongo(mm.CreationDate), FixupDatesFromMongo(mm.LastLoginDate), FixupDatesFromMongo(mm.LastActivityDate), DateTime.MinValue, FixupDatesFromMongo(mm.LastLockoutDate));
: new MembershipUser(Name,
mm.UserName,
mm.Id,
mm.EmailAddress,
"",
"",
mm.IsApproved,
mm.IsLockedOut,
FixupDatesFromMongo(mm.CreationDate),
FixupDatesFromMongo(mm.LastLoginDate),
FixupDatesFromMongo(mm.LastActivityDate),
DateTime.MinValue,
FixupDatesFromMongo(mm.LastLockoutDate));
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
Task<MongoMember> task = _memberCollection.Find(f => f.Id == (Guid)providerUserKey).FirstOrDefaultAsync();
var task = _memberCollection.Find(f => f.Id == (Guid)providerUserKey).FirstOrDefaultAsync();
task.Wait();
MongoMember mm = task.Result;
return mm == null
? null
: new MembershipUser(Name, mm.UserName, mm.Id, mm.EmailAddress, "", "", mm.IsApproved, mm.IsLockedOut, FixupDatesFromMongo(mm.CreationDate), FixupDatesFromMongo(mm.LastLoginDate), FixupDatesFromMongo(mm.LastActivityDate), DateTime.MinValue, FixupDatesFromMongo(mm.LastLockoutDate));
: new MembershipUser(Name,
mm.UserName,
mm.Id,
mm.EmailAddress,
"",
"",
mm.IsApproved,
mm.IsLockedOut,
FixupDatesFromMongo(mm.CreationDate),
FixupDatesFromMongo(mm.LastLoginDate),
FixupDatesFromMongo(mm.LastActivityDate),
DateTime.MinValue,
FixupDatesFromMongo(mm.LastLockoutDate));
}
public override string GetUserNameByEmail(string email)
{
Task<MongoMember> task = _memberCollection.Find(f => f.EmailAddress.ToLower() == email.ToLower()).FirstOrDefaultAsync();
var task = _memberCollection.Find(f => f.EmailAddress.ToLower() == email.ToLower()).FirstOrDefaultAsync();
task.Wait();
return task.Result.UserName;
}
public override string ResetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override string ResetPassword(string username, string answer) => throw new NotImplementedException();
public void ChangeApproval(Guid id, bool newStatus)
{
Task<UpdateResult> task = _memberCollection.UpdateOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, id), Builders<MongoMember>.Update.Set(u => u.IsApproved, newStatus));
var task = _memberCollection.UpdateOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, id),
Builders<MongoMember>.Update.Set(u => u.IsApproved, newStatus));
task.Wait();
}
@ -324,13 +366,16 @@ namespace MongoAuth
updateDefinition.Add(Builders<MongoMember>.Update.Set(u => u.LastLockoutDate, DateTime.MinValue));
}
Task<UpdateResult> task = _memberCollection.UpdateOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, id), Builders<MongoMember>.Update.Combine(updateDefinition));
var task = _memberCollection.UpdateOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, id),
Builders<MongoMember>.Update.Combine(updateDefinition));
task.Wait();
}
public override bool UnlockUser(string userName)
{
Task<UpdateResult> task = _memberCollection.UpdateOneAsync(Builders<MongoMember>.Filter.Eq(m => m.UserName.ToLower(), userName.ToLower()), Builders<MongoMember>.Update.Set(m => m.IsLockedOut, false));
var task = _memberCollection.UpdateOneAsync(
Builders<MongoMember>.Filter.Eq(m => m.UserName.ToLower(), userName.ToLower()),
Builders<MongoMember>.Update.Set(m => m.IsLockedOut, false));
task.Wait();
return task.Result.IsAcknowledged && task.Result.ModifiedCount == 1;
@ -343,7 +388,7 @@ namespace MongoAuth
public override bool ValidateUser(string username, string password)
{
Task<MongoMember> task = _memberCollection.Find(f => f.UserName.ToLower() == username.ToLower()).FirstOrDefaultAsync();
var task = _memberCollection.Find(f => f.UserName.ToLower() == username.ToLower()).FirstOrDefaultAsync();
task.Wait();
MongoMember mm = task.Result;
@ -353,8 +398,8 @@ namespace MongoAuth
return false;
}
byte[] salt = mm.PassSalt;
byte[] hash = CalculateHash(password, ref salt);
var salt = mm.PassSalt;
var hash = CalculateHash(password, ref salt);
bool isFail = false;
@ -397,7 +442,7 @@ namespace MongoAuth
mm.LockoutWindowAttempts = 0;
}
Task<ReplaceOneResult> updTask = _memberCollection.ReplaceOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, mm.Id), mm);
var updTask = _memberCollection.ReplaceOneAsync(Builders<MongoMember>.Filter.Eq(u => u.Id, mm.Id), mm);
updTask.Wait();
return !isFail;
@ -405,7 +450,8 @@ namespace MongoAuth
public async Task<string> GenerateValidationHash(Guid id)
{
MongoMember mm = await _memberCollection.Find(Builders<MongoMember>.Filter.Eq(u => u.Id, id)).FirstOrDefaultAsync();
MongoMember mm = await _memberCollection.Find(Builders<MongoMember>.Filter.Eq(u => u.Id, id))
.FirstOrDefaultAsync();
if (mm == null)
{
return null;
@ -413,8 +459,9 @@ namespace MongoAuth
using (SHA256 sha = SHA256.Create())
{
string content = $"{mm.Id}.{Convert.ToBase64String(mm.PassSalt)}.{ConfigurationManager.AppSettings["data:SecretKey"]}";
byte[] hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(content));
string content =
$"{mm.Id}.{Convert.ToBase64String(mm.PassSalt)}.{ConfigurationManager.AppSettings["data:SecretKey"]}";
var hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(content));
return Base32Encoding.ToString(hashBytes);
}
@ -422,7 +469,8 @@ namespace MongoAuth
public async Task<bool> ValidateUserFromHash(Guid id, string validate)
{
MongoMember mm = await _memberCollection.Find(Builders<MongoMember>.Filter.Eq(u => u.Id, id)).FirstOrDefaultAsync();
MongoMember mm = await _memberCollection.Find(Builders<MongoMember>.Filter.Eq(u => u.Id, id))
.FirstOrDefaultAsync();
if (mm == null)
{
return false;
@ -430,8 +478,9 @@ namespace MongoAuth
using (SHA256 sha = SHA256.Create())
{
string content = $"{mm.Id}.{Convert.ToBase64String(mm.PassSalt)}.{ConfigurationManager.AppSettings["data:SecretKey"]}";
byte[] hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(content));
string content =
$"{mm.Id}.{Convert.ToBase64String(mm.PassSalt)}.{ConfigurationManager.AppSettings["data:SecretKey"]}";
var hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(content));
string expected = Base32Encoding.ToString(hashBytes);
bool success = string.Equals(expected, validate, StringComparison.InvariantCultureIgnoreCase);
@ -449,19 +498,19 @@ namespace MongoAuth
{
if (!salt.Any(v => v != 0))
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
var rng = new RNGCryptoServiceProvider();
rng.GetBytes(salt);
}
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
var passwordBytes = Encoding.UTF8.GetBytes(password);
var hashPlaintext = new byte[salt.Length + passwordBytes.Length];
passwordBytes.CopyTo(hashPlaintext, 0);
salt.CopyTo(hashPlaintext, passwordBytes.Length);
SHA512CryptoServiceProvider sha = new SHA512CryptoServiceProvider();
byte[] hash = sha.ComputeHash(hashPlaintext);
var sha = new SHA512CryptoServiceProvider();
var hash = sha.ComputeHash(hashPlaintext);
return hash;
}

View File

@ -22,7 +22,7 @@ namespace MongoAuth
public override string ApplicationName
{
get { return ""; }
get => "";
set { }
}
@ -30,7 +30,7 @@ namespace MongoAuth
{
base.Initialize(name, config);
MongoClientSettings settings = new MongoClientSettings
var settings = new MongoClientSettings
{
Server = new MongoServerAddress(DatabaseConfig.Host, DatabaseConfig.Port)
};
@ -42,21 +42,23 @@ namespace MongoAuth
DatabaseConfig.Password);
}
MongoClient dbClient = new MongoClient(settings);
var dbClient = new MongoClient(settings);
_roleCollection = dbClient.GetDatabase(DatabaseConfig.Database).GetCollection<MongoRole>(ROLE_COLLECTION_NAME);
_memberCollection = dbClient.GetDatabase(DatabaseConfig.Database).GetCollection<MongoMember>(MEMBER_COLLECTION_NAME);
_roleCollection = dbClient.GetDatabase(DatabaseConfig.Database)
.GetCollection<MongoRole>(ROLE_COLLECTION_NAME);
_memberCollection = dbClient.GetDatabase(DatabaseConfig.Database)
.GetCollection<MongoMember>(MEMBER_COLLECTION_NAME);
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
Task<List<MongoRole>> roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync();
var roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync();
roleTask.Wait();
List<MongoRole> roles = roleTask.Result;
var roles = roleTask.Result;
Task<List<MongoMember>> userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync();
var userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync();
userTask.Wait();
List<MongoMember> users = userTask.Result;
var users = userTask.Result;
for (int i = 0; i < roles.Count; i++)
{
@ -67,29 +69,30 @@ namespace MongoAuth
newUsers.AddRange(roles[i].Users);
}
IEnumerable<Guid> usersToAdd = from u in users
where newUsers.All(v => v != u.Id)
select u.Id;
var usersToAdd = from u in users
where newUsers.All(v => v != u.Id)
select u.Id;
newUsers.AddRange(usersToAdd);
roles[i].Users = newUsers.ToArray();
Task<ReplaceOneResult> update = _roleCollection.ReplaceOneAsync(Builders<MongoRole>.Filter.Eq(r => r.Id, roles[i].Id), roles[i]);
var update =
_roleCollection.ReplaceOneAsync(Builders<MongoRole>.Filter.Eq(r => r.Id, roles[i].Id), roles[i]);
update.Wait();
}
}
public override void CreateRole(string roleName)
{
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
role.Wait();
if (role.Result != null)
{
return;
}
MongoRole mr = new MongoRole
var mr = new MongoRole
{
Id = Guid.NewGuid(),
RoleName = roleName
@ -101,7 +104,7 @@ namespace MongoAuth
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
role.Wait();
if (role.Result != null
@ -111,7 +114,7 @@ namespace MongoAuth
throw new ProviderException(Resources.RoleNotEmpty);
}
Task<DeleteResult> task = _roleCollection.DeleteOneAsync(r => r.RoleName == roleName);
var task = _roleCollection.DeleteOneAsync(r => r.RoleName == roleName);
task.Wait();
return true;
@ -119,7 +122,7 @@ namespace MongoAuth
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
role.Wait();
if (role.Result == null)
@ -127,7 +130,9 @@ namespace MongoAuth
return Array.Empty<string>();
}
Task<List<MongoMember>> users = _memberCollection.Find(u => role.Result.Users.Contains(u.Id) && u.UserName.ToLower().Contains(usernameToMatch.ToLower())).ToListAsync();
var users = _memberCollection.Find(u
=> role.Result.Users.Contains(u.Id) && u.UserName.ToLower().Contains(usernameToMatch.ToLower()))
.ToListAsync();
users.Wait();
return users.Result.Select(r => r.UserName).ToArray();
@ -135,7 +140,7 @@ namespace MongoAuth
public override string[] GetAllRoles()
{
Task<List<MongoRole>> roles = _roleCollection.Find(new BsonDocument()).ToListAsync();
var roles = _roleCollection.Find(new BsonDocument()).ToListAsync();
roles.Wait();
return roles.Result.Select(r => r.RoleName).ToArray();
@ -143,7 +148,7 @@ namespace MongoAuth
public override string[] GetRolesForUser(string username)
{
Task<MongoMember> user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync();
var user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync();
user.Wait();
if (user.Result == null)
@ -151,7 +156,7 @@ namespace MongoAuth
return Array.Empty<string>();
}
Task<List<MongoRole>> role = _roleCollection.Find(r => r.Users != null && r.Users.Contains(user.Result.Id)).ToListAsync();
var role = _roleCollection.Find(r => r.Users != null && r.Users.Contains(user.Result.Id)).ToListAsync();
role.Wait();
return role.Result.Select(r => r.RoleName).ToArray();
@ -159,7 +164,7 @@ namespace MongoAuth
public override string[] GetUsersInRole(string roleName)
{
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
role.Wait();
if (role.Result == null)
@ -167,7 +172,7 @@ namespace MongoAuth
return Array.Empty<string>();
}
Task<List<MongoMember>> users = _memberCollection.Find(u => role.Result.Users.Contains(u.Id)).ToListAsync();
var users = _memberCollection.Find(u => role.Result.Users.Contains(u.Id)).ToListAsync();
users.Wait();
return users.Result.Select(u => u.UserName).ToArray();
@ -175,8 +180,8 @@ namespace MongoAuth
public override bool IsUserInRole(string username, string roleName)
{
Task<MongoMember> user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync();
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
user.Wait();
role.Wait();
@ -191,28 +196,28 @@ namespace MongoAuth
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
Task<List<MongoRole>> roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync();
var roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync();
roleTask.Wait();
List<MongoRole> roles = roleTask.Result;
var roles = roleTask.Result;
Task<List<MongoMember>> userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync();
var userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync();
userTask.Wait();
List<MongoMember> users = userTask.Result;
var users = userTask.Result;
foreach (MongoRole t in roles)
{
t.Users = (from u in t.Users
where users.All(v => v.Id != u)
select u).ToArray();
where users.All(v => v.Id != u)
select u).ToArray();
Task<ReplaceOneResult> update = _roleCollection.ReplaceOneAsync(Builders<MongoRole>.Filter.Eq(r => r.Id, t.Id), t);
var update = _roleCollection.ReplaceOneAsync(Builders<MongoRole>.Filter.Eq(r => r.Id, t.Id), t);
update.Wait();
}
}
public override bool RoleExists(string roleName)
{
Task<MongoRole> role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
var role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync();
role.Wait();
return role.Result != null;

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@ -33,4 +32,4 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<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" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<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" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
</startup>
</configuration>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DnsClient" version="1.0.7" targetFramework="net47" />
<package id="MongoDB.Bson" version="2.5.0" targetFramework="net47" />

View File

@ -12,7 +12,9 @@ namespace BuildFeed.Model.Api
public string LabUrl { get; set; }
public bool IsLeaked => SourceType == TypeOfSource.PublicRelease || SourceType == TypeOfSource.InternalLeak || SourceType == TypeOfSource.UpdateGDR;
public bool IsLeaked => SourceType == TypeOfSource.PublicRelease
|| SourceType == TypeOfSource.InternalLeak
|| SourceType == TypeOfSource.UpdateGDR;
public DateTime Added { get; set; }

View File

@ -31,9 +31,9 @@ namespace BuildFeed.Model
public string LabUrl { get; private set; }
public bool IsLeaked => SourceType == TypeOfSource.PublicRelease ||
SourceType == TypeOfSource.InternalLeak ||
SourceType == TypeOfSource.UpdateGDR;
public bool IsLeaked => SourceType == TypeOfSource.PublicRelease
|| SourceType == TypeOfSource.InternalLeak
|| SourceType == TypeOfSource.UpdateGDR;
public string FullBuildString { get; private set; }

View File

@ -20,7 +20,10 @@ namespace BuildFeed.Model
}
var valuesWithoutNone = new ProjectFamily[values.Length - 1];
for (int i = 0, j = values.Length - 1; j > 0; j--, i++)
for (int i = 0,
j = values.Length - 1;
j > 0;
j--, i++)
{
valuesWithoutNone[i] = (ProjectFamily)values.GetValue(j);
}

View File

@ -11,76 +11,83 @@ namespace BuildFeed.Model
{
public async Task<FrontBuildGroup[]> SelectAllGroups(int limit = -1, int skip = 0)
{
IAggregateFluent<BsonDocument> query = _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)}")
}),
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);
var query = _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)}")
}),
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();
var grouping = await query.ToListAsync();
return (from g in grouping
select new FrontBuildGroup
select new FrontBuildGroup
{
Key = new BuildGroup
{
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();
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();
var 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);
var 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)
{

View File

@ -11,40 +11,51 @@ namespace BuildFeed.Model
{
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);
var query = _buildCollection.Aggregate()
.Group(new BsonDocument("_id", $"${nameof(Build.Lab)}"))
.Sort(new BsonDocument("_id", 1))
.Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
List<BsonDocument> grouping = await query.ToListAsync();
var grouping = await query.ToListAsync();
return (from g in grouping
where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray();
where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray();
}
public async Task<string[]> SelectLabsForVersion(int major, int minor)
{
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Match(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor)
}).Group(new BsonDocument("_id", $"${nameof(Build.Lab)}")).Sort(new BsonDocument("_id", 1));
var query = _buildCollection.Aggregate()
.Match(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor)
})
.Group(new BsonDocument("_id", $"${nameof(Build.Lab)}"))
.Sort(new BsonDocument("_id", 1));
List<BsonDocument> grouping = await query.ToListAsync();
var grouping = await query.ToListAsync();
return (from g in grouping
where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray();
where !g["_id"].IsBsonNull
select g["_id"].AsString).ToArray();
}
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(),
// incoming bullshit hack
bg => new Tuple<string>(bg.Key)).ToListAsync();
var 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
bg => new Tuple<string>(bg.Key))
.ToListAsync();
// work ourselves out of aforementioned bullshit hack
return result.Select(b => b.Item1).ToList();
@ -52,16 +63,20 @@ namespace BuildFeed.Model
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));
var 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();
var grouping = await query.ToListAsync();
return grouping.Count;
}
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);
var query = _buildCollection.Find(new BsonDocument(nameof(Build.LabUrl), lab))
.Sort(sortByCompileDate)
.Skip(skip);
if (limit > 0)
{
@ -71,6 +86,7 @@ namespace BuildFeed.Model
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

@ -8,13 +8,16 @@ namespace BuildFeed.Model
{
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 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);
var query = _buildCollection.Find(new BsonDocument(nameof(Build.SourceType), source))
.Sort(sortByOrder)
.Skip(skip);
if (limit > 0)
{
@ -24,6 +27,7 @@ namespace BuildFeed.Model
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

@ -10,50 +10,57 @@ namespace BuildFeed.Model
{
public async Task<BuildVersion[]> SelectAllVersions(int limit = -1, int skip = 0)
{
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate().Group(new BsonDocument("_id",
new BsonDocument
var query = _buildCollection.Aggregate()
.Group(new BsonDocument("_id",
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(nameof(BuildVersion.Minor), $"${nameof(Build.MinorVersion)}")
})).Sort(new BsonDocument
{
new BsonElement($"_id.{nameof(BuildVersion.Major)}", -1),
new BsonElement($"_id.{nameof(BuildVersion.Minor)}", -1)
}).Skip(skip);
new BsonElement($"_id.{nameof(BuildVersion.Major)}", -1),
new BsonElement($"_id.{nameof(BuildVersion.Minor)}", -1)
})
.Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
List<BsonDocument> grouping = await query.ToListAsync();
var 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();
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();
var 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);
var query = _buildCollection.Find(new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), major),
new BsonElement(nameof(Build.MinorVersion), minor)
})
.Sort(sortByOrder)
.Skip(skip);
if (limit > 0)
{
@ -63,10 +70,11 @@ namespace BuildFeed.Model
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)
});
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

@ -11,7 +11,7 @@ namespace BuildFeed.Model
{
public async Task<int[]> SelectAllYears(int limit = -1, int skip = 0)
{
IAggregateFluent<BsonDocument> query =
var query =
_buildCollection.Aggregate()
.Match(Builders<Build>.Filter.Ne(b => b.BuildTime, null))
.Group(new BsonDocument("_id", new BsonDocument("$year", $"${nameof(Build.BuildTime)}")))
@ -23,25 +23,33 @@ namespace BuildFeed.Model
query = query.Limit(limit);
}
List<BsonDocument> grouping = await query.ToListAsync();
var grouping = await query.ToListAsync();
return (from g in grouping
where !g["_id"].IsBsonNull
select g["_id"].AsInt32).ToArray();
where !g["_id"].IsBsonNull
select g["_id"].AsInt32).ToArray();
}
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();
var 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;
}
public async Task<List<Build>> SelectYear(int year, int limit = -1, int skip = 0)
{
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)),
Builders<Build>.Filter.Lte(b => b.BuildTime, new DateTime(year, 12, 31, 23, 59, 59, DateTimeKind.Utc)))).Sort(sortByCompileDate).Skip(skip);
var query =
_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);
if (limit > 0)
{
@ -51,10 +59,10 @@ namespace BuildFeed.Model
return await query.ToListAsync();
}
public async Task<long> SelectYearCount(int year)
=>
await
_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))));
public async Task<long> SelectYearCount(int year) => await
_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))));
}
}

View File

@ -230,16 +230,16 @@ namespace BuildFeed.Model
},
Items = from i in g["items"].AsBsonArray
select new FrontPageBuild
{
Id = i[nameof(Build.Id)].AsGuid,
MajorVersion = (uint)i[nameof(Build.MajorVersion)].AsInt32,
MinorVersion = (uint)i[nameof(Build.MinorVersion)].AsInt32,
Number = (uint)i[nameof(Build.Number)].AsInt32,
Revision = (uint?)i[nameof(Build.Revision)].AsNullableInt32,
Lab = i[nameof(Build.Lab)].AsString,
BuildTime = i[nameof(Build.BuildTime)].ToNullableUniversalTime()
}
select new FrontPageBuild
{
Id = i[nameof(Build.Id)].AsGuid,
MajorVersion = (uint)i[nameof(Build.MajorVersion)].AsInt32,
MinorVersion = (uint)i[nameof(Build.MinorVersion)].AsInt32,
Number = (uint)i[nameof(Build.Number)].AsInt32,
Revision = (uint?)i[nameof(Build.Revision)].AsNullableInt32,
Lab = i[nameof(Build.Lab)].AsString,
BuildTime = i[nameof(Build.BuildTime)].ToNullableUniversalTime()
}
}).ToArray();
IEnumerable<ProjectFamily> listOfFamilies =

View File

@ -21,6 +21,7 @@ namespace BuildFeed.Model
{
port = 27017; // mongo default port
}
Port = port;
Database = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["data:MongoDB"])
@ -33,10 +34,10 @@ namespace BuildFeed.Model
public static void SetupIndexes()
{
BuildRepository b = new BuildRepository();
#pragma warning disable 4014
var b = new BuildRepository();
#pragma warning disable 4014
b.SetupIndexes();
#pragma warning restore 4014
#pragma warning restore 4014
}
}
}

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<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" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<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" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
</startup>
</configuration>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="6.2.2" targetFramework="net47" />
<package id="DnsClient" version="1.0.7" targetFramework="net47" />

302
BuildFeed.sln.DotSettings Normal file
View File

@ -0,0 +1,302 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/IdentifierHighlightingEnabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Built-in: Full Cleanup</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/LOCAL_FUNCTION_BODY/@EntryValue">ExpressionBody</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_PREPROCESSOR_IF/@EntryValue">USUAL_INDENT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_PREPROCESSOR_OTHER/@EntryValue">USUAL_INDENT</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_EMBEDDED_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/NESTED_TERNARY_STYLE/@EntryValue">EXPANDED</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_EXPR_ACCESSOR_ON_SINGLE_LINE/@EntryValue">ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_EXPR_METHOD_ON_SINGLE_LINE/@EntryValue">ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_EXPR_PROPERTY_ON_SINGLE_LINE/@EntryValue">ALWAYS</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_TYPE_CONSTRAINTS_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_ARROW_WITH_EXPRESSIONS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_BINARY_OPSIGN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_EXTENDS_COLON/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_FIRST_TYPE_PARAMETER_CONSTRAINT/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_CHAINED_BINARY_EXPRESSIONS/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_CHAINED_METHOD_CALLS/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINQ_EXPRESSIONS/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_MULTIPLE_DECLARATION_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_MULTIPLE_TYPE_PARAMEER_CONSTRAINTS_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_OBJECT_AND_COLLECTION_INITIALIZER_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_TERNARY_EXPR_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CssFormatter/BRACE_STYLE/@EntryValue">NEXT_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CssFormatter/PROPERTIES_STYLE/@EntryValue">SEPARATE_LINES</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CssFormatter/SELECTOR_STYLE/@EntryValue">SEPARATE_LINES</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/HtmlFormatter/NormalizeTagNames/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/HtmlFormatter/TagAttributeIndenting/@EntryValue">OneStep</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/HtmlFormatter/TagAttributesFormat/@EntryValue">OnSingleLine</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/HtmlFormatter/TagSpaceBeforeHeaderEnd1/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/ALIGN_UNION_TYPE_USAGE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/CONTROL_STATEMENTS_BRACES/@EntryValue">NEXT_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/FORCE_CONTROL_STATEMENTS_BRACES/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/FUNCTION_BRACES/@EntryValue">NEXT_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/FUNCTION_IN_INVOCATION_BRACES/@EntryValue">NEXT_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/PLACE_FINALLY_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/SINGLE_STATEMENT_FUNCTION_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/TYPES_BRACES/@EntryValue">NEXT_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/WRAP_CHAINED_METHOD_CALLS/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/WRAP_ENUM_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&#xD;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName="Non-reorderable types"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;Kind Is="Struct" /&gt;&#xD;
&lt;HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /&gt;&#xD;
&lt;HasAttribute Name="JetBrains.Annotations.NoReorder" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;HasMember&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="Xunit.FactAttribute" Inherited="True" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/HasMember&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Setup/Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;ImplementsInterface Name="System.IDisposable" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind Order="Constructor" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Test Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="Xunit.FactAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Setup/Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Test Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="Default Pattern"&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Delegates"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Enums"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind Order="Constant Field" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Properties, Indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Interface Implementations"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Member" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Nested Types"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Type" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVarWhenEvident</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FGLOBAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLABEL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FOBJECT_005FPROPERTY_005FOF_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FINTERFACE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMIXED_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FEXPORTED/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FLOCAL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FHTML_005FCONTROL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FNAME/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FPREFIX/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/CodeStyle/RazorCodeStyle/PreferQualifiedReference/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/TypeScriptCodeStyle/ExplicitPublicModifier/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/TypeScriptCodeStyle/ImportReferenceStyle/@EntryValue">ECMAScript6</s:String>
<s:Boolean x:Key="/Default/CodeStyle/TypeScriptCodeStyle/NoImplicitAny/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ESettingsUpgrade_002EJsParsFormattingSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ESettingsUpgrade_002EJsWrapperSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ETypeScript_002ESettingsUpgrade_002ETsModuleAliasesSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EXml_002ECodeStyle_002EFormatSettingsUpgrade_002EXmlMoveToCommonFormatterSettingsUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -3,156 +3,162 @@
@using BuildFeed.Code
@helper PaginationBlock(int currentPage, int totalPages, string view, RouteValueDictionary rd)
{
string multiView = view + "Page";
string multiView = view + "Page";
if (totalPages > 1)
{
<ul class="pagination">
@if (currentPage == 2)
{
RouteValueDictionary rvd = new RouteValueDictionary(rd);
rvd.Remove("page");
<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)
{
RouteValueDictionary firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
<li>
<a href="@MvcIntrinsics.Url.Action(view, firstRvd)">
<i class="fa fa-angle-double-left"></i>
</a>
</li>
RouteValueDictionary rvd = new RouteValueDictionary(rd)
if (totalPages > 1)
{
<ul class="pagination">
@if (currentPage == 2)
{
["page"] = currentPage - 1
};
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-left"></i>
</a>
</li>
}
else
{
<li class="disabled">
<span>
<i class="fa fa-angle-double-left"></i>
</span>
</li>
<li class="disabled">
<span>
<i class="fa fa-angle-left"></i>
</span>
</li>
}
@{
RouteValueDictionary rvdIndex = new RouteValueDictionary(rd);
rvdIndex.Remove("page");
IEnumerable<int> pages;
}
@if (totalPages == 1)
{
RouteValueDictionary firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Array.Empty<int>();
<li @( 1 == currentPage ? "class=active" : "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (totalPages <= 7 && totalPages >= 2)
{
RouteValueDictionary firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Enumerable.Range(2, totalPages - 1);
<li @( 1 == currentPage ? "class=active" : "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (currentPage <= 4)
{
RouteValueDictionary firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Enumerable.Range(2, 6);
<li @( 1 == currentPage ? "class=active" : "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (currentPage >= totalPages - 2)
{
pages = Enumerable.Range(totalPages - 6, 7);
}
else
{
pages = Enumerable.Range(currentPage - 3, 7);
}
@foreach (int i in pages)
{
RouteValueDictionary rvd = new RouteValueDictionary(rd)
var rvd = new RouteValueDictionary(rd);
rvd.Remove("page");
<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)
{
["page"] = i
};
var firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
<li>
<a href="@MvcIntrinsics.Url.Action(view, firstRvd)">
<i class="fa fa-angle-double-left"></i>
</a>
</li>
<li @( i == currentPage
? "class=active"
: "")>
@MvcIntrinsics.Html.ActionLink(i.ToString(), multiView, rvd)</li>
}
@if (currentPage < totalPages)
{
RouteValueDictionary rvd = new RouteValueDictionary(rd)
var rvd = new RouteValueDictionary(rd)
{
["page"] = currentPage - 1
};
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-left"></i>
</a>
</li>
}
else
{
["page"] = currentPage + 1
};
<li class="disabled">
<span>
<i class="fa fa-angle-double-left"></i>
</span>
</li>
<li class="disabled">
<span>
<i class="fa fa-angle-left"></i>
</span>
</li>
}
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-right"></i>
</a>
</li>
RouteValueDictionary lastRvd = new RouteValueDictionary(rd)
@{
var rvdIndex = new RouteValueDictionary(rd);
rvdIndex.Remove("page");
IEnumerable<int> pages;
}
@if (totalPages == 1)
{
["page"] = totalPages
};
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, lastRvd)">
<i class="fa fa-angle-double-right"></i>
</a>
</li>
}
else
{
<li class="disabled">
<span>
<i class="fa fa-angle-right"></i>
</span>
</li>
<li class="disabled">
<span>
<i class="fa fa-angle-double-right"></i>
</span>
</li>
}
</ul>
}
var firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Array.Empty<int>();
<li @( 1 == currentPage
? "class=active"
: "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (totalPages <= 7 && totalPages >= 2)
{
var firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Enumerable.Range(2, totalPages - 1);
<li @( 1 == currentPage
? "class=active"
: "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (currentPage <= 4)
{
var firstRvd = new RouteValueDictionary(rd);
firstRvd.Remove("page");
pages = Enumerable.Range(2, 6);
<li @( 1 == currentPage
? "class=active"
: "")>
@MvcIntrinsics.Html.ActionLink(1.ToString(), view, firstRvd)
</li>
}
else if (currentPage >= totalPages - 2)
{
pages = Enumerable.Range(totalPages - 6, 7);
}
else
{
pages = Enumerable.Range(currentPage - 3, 7);
}
@foreach (int i in pages)
{
var rvd = new RouteValueDictionary(rd)
{
["page"] = i
};
<li @( i == currentPage
? "class=active"
: "")>
@MvcIntrinsics.Html.ActionLink(i.ToString(), multiView, rvd)</li>
}
@if (currentPage < totalPages)
{
var rvd = new RouteValueDictionary(rd)
{
["page"] = currentPage + 1
};
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, rvd)">
<i class="fa fa-angle-right"></i>
</a>
</li>
var lastRvd = new RouteValueDictionary(rd)
{
["page"] = totalPages
};
<li>
<a href="@MvcIntrinsics.Url.Action(multiView, lastRvd)">
<i class="fa fa-angle-double-right"></i>
</a>
</li>
}
else
{
<li class="disabled">
<span>
<i class="fa fa-angle-right"></i>
</span>
</li>
<li class="disabled">
<span>
<i class="fa fa-angle-double-right"></i>
</span>
</li>
}
</ul>
}
}

View File

@ -1,27 +1,22 @@
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Security;
using BuildFeed.Controllers;
using BuildFeed.Model;
namespace BuildFeed.Admin.Controllers
{
[Authorize(Roles = "Administrators")]
[RouteArea("admin")]
[RoutePrefix("")]
public class RootController : BaseController
{
[Authorize(Roles = "Administrators")]
[Route("")]
public ActionResult Index()
{
return View();
}
public ActionResult Index() => View();
[Authorize(Roles = "Administrators")]
[Route("regen-cache")]
public async Task<ActionResult> RegenerateCache()
{
BuildRepository bRepo = new BuildRepository();
var bRepo = new BuildRepository();
await bRepo.RegenerateCachedProperties();
return RedirectToAction(nameof(Index));

View File

@ -1,19 +1,19 @@
@{
ViewBag.Title = $"Administration | {InvariantTerms.SiteName}";
ViewBag.Title = $"Administration | {InvariantTerms.SiteName}";
}
<h1>Administration</h1>
<ul>
<li>
@Html.ActionLink("Manage users", nameof(UsersController.Index), "Users")
<ul>
<li>@Html.ActionLink("View administrators", nameof(UsersController.Admins), "Users")</li>
</ul>
</li>
<li>
@Html.ActionLink("Manage metadata", nameof(MetaController.Index), "Meta")
</li>
<li>
@Html.ActionLink("Manage users", nameof(UsersController.Index), "Users")
<ul>
<li>@Html.ActionLink("View administrators", nameof(UsersController.Admins), "Users")</li>
</ul>
</li>
<li>
@Html.ActionLink("Manage metadata", nameof(MetaController.Index), "Meta")
</li>
<li>
@Html.ActionLink("Regenerate cached properties", nameof(RootController.RegenerateCache), "Root")
</li>

View File

@ -1,7 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;
using BuildFeed.Areas.admin.Models.ViewModel;
using BuildFeed.Admin.Models.ViewModel;
using BuildFeed.Controllers;
using BuildFeed.Model;

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
@ -19,7 +18,7 @@ namespace BuildFeed.Admin.Controllers
[Route("admins")]
public ActionResult Admins()
{
List<MembershipUser> admins = Roles.GetUsersInRole("Administrators").Select(Membership.GetUser).ToList();
var admins = Roles.GetUsersInRole("Administrators").Select(Membership.GetUser).ToList();
return View(admins.OrderByDescending(m => m.UserName));
}
@ -27,7 +26,7 @@ namespace BuildFeed.Admin.Controllers
[Route("approve/{id:guid}")]
public ActionResult Approve(Guid id)
{
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
var provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeApproval(id, true);
return RedirectToAction(nameof(Index));
}
@ -35,7 +34,7 @@ namespace BuildFeed.Admin.Controllers
[Route("unapprove/{id:guid}")]
public ActionResult Unapprove(Guid id)
{
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
var provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeApproval(id, false);
return RedirectToAction(nameof(Index));
}
@ -43,7 +42,7 @@ namespace BuildFeed.Admin.Controllers
[Route("lock/{id:guid}")]
public ActionResult Lock(Guid id)
{
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
var provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeLockStatus(id, true);
return RedirectToAction(nameof(Index));
}
@ -51,7 +50,7 @@ namespace BuildFeed.Admin.Controllers
[Route("unlock/{id:guid}")]
public ActionResult Unlock(Guid id)
{
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
var provider = Membership.Provider as MongoMembershipProvider;
provider?.ChangeLockStatus(id, false);
return RedirectToAction(nameof(Index));
}
@ -59,7 +58,7 @@ namespace BuildFeed.Admin.Controllers
[Route("delete/{id:guid}")]
public ActionResult Delete(Guid id)
{
MongoMembershipProvider provider = Membership.Provider as MongoMembershipProvider;
var provider = Membership.Provider as MongoMembershipProvider;
provider?.DeleteUser(id);
return RedirectToAction(nameof(Index));
}

View File

@ -2,7 +2,7 @@
using System.Linq;
using BuildFeed.Model;
namespace BuildFeed.Areas.admin.Models.ViewModel
namespace BuildFeed.Admin.Models.ViewModel
{
public class MetaListing
{

View File

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

View File

@ -1,6 +1,12 @@
@model BuildFeed.Model.MetaItemModel
@using BuildFeed.Model
@model MetaItemModel
@{
ViewBag.Title = $"Add metadata for {Model.Id.Value} | {InvariantTerms.SiteName}";
ViewBag.Title = $"Add metadata for {Model.Id.Value} | {InvariantTerms.SiteName}";
}
@section head
{
<link href="~/Scripts/trumbowyg/ui/trumbowyg.min.css" rel="stylesheet" type="text/css" />
}
<h1>@($"Add metadata for {Model.Id.Value}")</h1>
@ -8,97 +14,94 @@
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.Id.Type)
@Html.HiddenFor(model => model.Id.Value)
@Html.HiddenFor(model => model.Id.Type)
@Html.HiddenFor(model => model.Id.Value)
<div class="form-group">
@Html.LabelFor(model => model.MetaDescription)
<div class="wide-group">
@Html.TextAreaFor(model => model.MetaDescription, new
{
rows = "4"
})
<div>
<span id="meta-count">0</span> characters
@Html.ValidationMessageFor(model => model.MetaDescription)
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.MetaDescription)
<div class="wide-group">
@Html.TextAreaFor(model => model.MetaDescription, new
{
rows = "4"
})
<div>
<span id="meta-count">0</span> characters
@Html.ValidationMessageFor(model => model.MetaDescription)
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.PageContent)
<div class="wide-group">
@Html.TextAreaFor(model => model.PageContent)
<div>
@Html.ValidationMessageFor(model => model.PageContent)
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.PageContent)
<div class="wide-group">
@Html.TextAreaFor(model => model.PageContent)
<div>
@Html.ValidationMessageFor(model => model.PageContent)
</div>
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="Add metadata" />
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="Add metadata" />
</div>
</div>
}
@section Scripts
{
<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>
<link href="~/Scripts/trumbowyg/ui/trumbowyg.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="~/Scripts/trumbowyg/trumbowyg.min.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="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" integrity="sha256-g1QKGxqsp+x5JkuN/JjHl96je2wztgS5Wo4h4c7gm9M=" crossorigin="anonymous"></script>
<script type="text/javascript">
function updateMetaCount()
{
var count = document.getElementById("@Html.IdFor(model => model.MetaDescription)").value.length;
$("#meta-count").text(count.toFixed(0));
if (count === 0)
{
$("#meta-count").attr("class", "");
}
else if (count < 160)
{
$("#meta-count").attr("class", "text-success");
}
else
{
$("#meta-count").attr("class", "text-danger");
}
}
$(function()
{
var btnsGrps = $.trumbowyg.btnsGrps;
$("#@Html.IdFor(model => model.PageContent)")
.trumbowyg({
autogrow: true,
btns: [
['strong', 'em'],
'|', 'link',
'|', 'btnGrp-lists',
'|', 'btnGrp-justify',
'|', 'viewHTML',
'|'
]
});
$(".trumbowyg").addClass("trumbowyg-black");
$("#@Html.IdFor(model => model.MetaDescription)")
.keyup(function()
<script type="text/javascript">
function updateMetaCount()
{
var count = document.getElementById("@Html.IdFor(model => model.MetaDescription)").value.length;
$("#meta-count").text(count.toFixed(0));
if (count === 0)
{
updateMetaCount();
});
$("#meta-count").attr("class", "");
}
else if (count < 160)
{
$("#meta-count").attr("class", "text-success");
}
else
{
$("#meta-count").attr("class", "text-danger");
}
}
updateMetaCount();
});
</script>
$(function()
{
$.trumbowyg.svgPath = "/Scripts/trumbowyg/ui/icons.svg";
$("#@Html.IdFor(model => model.PageContent)")
.trumbowyg({
autogrow: true,
btns: [
['strong', 'em'],
'|', 'link',
'|', ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
'|', ['unorderedList', 'orderedList'],
'|', 'viewHTML',
'|'
]
});
$("#@Html.IdFor(model => model.MetaDescription)")
.keyup(function()
{
updateMetaCount();
});
updateMetaCount();
});
</script>
}

View File

@ -1,81 +1,82 @@
@using BuildFeed.Model
@model BuildFeed.Areas.admin.Models.ViewModel.MetaListing
@using BuildFeed.Admin.Models.ViewModel
@using BuildFeed.Model
@model MetaListing
@{
ViewBag.Title = $"Manage metadata | {InvariantTerms.SiteName}";
ViewBag.Title = $"Manage metadata | {InvariantTerms.SiteName}";
}
<h1>Manage metadata</h1>
<ul>
<li>@Html.ActionLink("Return to admin panel", nameof(RootController.Index), "Root")</li>
<li>@Html.ActionLink("Return to admin panel", nameof(RootController.Index), "Root")</li>
</ul>
<h3>Current items</h3>
<table>
<thead>
<tr>
<th>Name</th>
<th style="width: 50px"></th>
</tr>
</thead>
<tbody>
@foreach (IGrouping<MetaType, MetaItemModel> group in Model.CurrentItems)
{
<tr>
<td colspan="3">
<h4>@group.Key</h4>
</td>
</tr>
foreach (MetaItemModel item in group)
{
<tr>
<td>@item.Id.Value</td>
<td>
@Html.ActionLink("Edit", nameof(MetaController.Edit), new
{
type = item.Id.Type,
value = item.Id.Value
}, new
{
@class = "button",
style = "width:50px"
})</td>
</tr>
}
}
</tbody>
<thead>
<tr>
<th>Name</th>
<th style="width: 50px"></th>
</tr>
</thead>
<tbody>
@foreach (var group in Model.CurrentItems)
{
<tr>
<td colspan="3">
<h4>@group.Key</h4>
</td>
</tr>
foreach (MetaItemModel item in group)
{
<tr>
<td>@item.Id.Value</td>
<td>
@Html.ActionLink("Edit", nameof(MetaController.Edit), new
{
type = item.Id.Type,
value = item.Id.Value
}, new
{
@class = "button",
style = "width:50px"
})</td>
</tr>
}
}
</tbody>
</table>
<h3>Add new items</h3>
<table>
<thead>
<tr>
<th>Name</th>
<th style="width: 50px"></th>
</tr>
</thead>
<tbody>
@foreach (IGrouping<MetaType, MetaItemModel> group in Model.NewItems)
{
<tr>
<td colspan="3">
<h4>@group.Key</h4>
</td>
</tr>
foreach (MetaItemModel item in group)
{
<tr>
<td>@item.Id.Value</td>
<td>
@Html.ActionLink("Create", nameof(MetaController.Create), new
{
type = item.Id.Type,
value = item.Id.Value
}, new
{
@class = "button",
style = "width:50px"
})</td>
</tr>
}
}
</tbody>
<thead>
<tr>
<th>Name</th>
<th style="width: 50px"></th>
</tr>
</thead>
<tbody>
@foreach (var group in Model.NewItems)
{
<tr>
<td colspan="3">
<h4>@group.Key</h4>
</td>
</tr>
foreach (MetaItemModel item in group)
{
<tr>
<td>@item.Id.Value</td>
<td>
@Html.ActionLink("Create", nameof(MetaController.Create), new
{
type = item.Id.Type,
value = item.Id.Value
}, new
{
@class = "button",
style = "width:50px"
})</td>
</tr>
}
}
</tbody>
</table>

View File

@ -2,46 +2,46 @@
@model IEnumerable<MembershipUser>
@{
ViewBag.Title = "View administrators | BuildFeed";
ViewBag.Title = "View administrators | BuildFeed";
}
<h1>View administrators</h1>
<ul>
<li>@Html.ActionLink("Manage users", "Index")</li>
<li>@Html.ActionLink("Return to admin panel", "Index", "Root")</li>
<li>@Html.ActionLink("Manage users", "Index")</li>
<li>@Html.ActionLink("Return to admin panel", "Index", "Root")</li>
</ul>
<table class="table table-striped table-bordered table-admin">
<thead>
<tr>
<th>
Username
</th>
<th>
Email Address
</th>
<th>
Last Login Time
</th>
</tr>
</thead>
<tbody>
@foreach (MembershipUser mu in Model)
{
<tr>
<td>
@mu.UserName
</td>
<td>
<a href="mailto:@mu.Email">@mu.Email</a>
</td>
<td>
@(mu.LastLoginDate == default(DateTime)
? "Never"
: mu.LastLoginDate.Humanize())
</td>
</tr>
}
</tbody>
<thead>
<tr>
<th>
Username
</th>
<th>
Email Address
</th>
<th>
Last Login Time
</th>
</tr>
</thead>
<tbody>
@foreach (MembershipUser mu in Model)
{
<tr>
<td>
@mu.UserName
</td>
<td>
<a href="mailto:@mu.Email">@mu.Email</a>
</td>
<td>
@(mu.LastLoginDate == default(DateTime)
? "Never"
: mu.LastLoginDate.Humanize())
</td>
</tr>
}
</tbody>
</table>

View File

@ -2,108 +2,108 @@
@model IEnumerable<MembershipUser>
@{
ViewBag.Title = $"Manage users | {InvariantTerms.SiteName}";
ViewBag.Title = $"Manage users | {InvariantTerms.SiteName}";
}
<h1>Manage users</h1>
<ul>
<li>@Html.ActionLink("View administrators", "Admins")</li>
<li>@Html.ActionLink("Clean-up old unapproved users", "Cleanup")</li>
<li>@Html.ActionLink("Return to admin panel", "Index", "Root")</li>
<li>@Html.ActionLink("View administrators", "Admins")</li>
<li>@Html.ActionLink("Clean-up old unapproved users", "Cleanup")</li>
<li>@Html.ActionLink("Return to admin panel", "Index", "Root")</li>
</ul>
<table id="user-table">
<thead>
<tr>
<th>
Username
</th>
<th>
Email Address
</th>
<th>
Registration Time
</th>
<th>
Last Login Time
</th>
<th>
Last Lockout Time
</th>
<th style="width: 100px;"></th>
<th style="width: 100px;"></th>
<th style="width: 100px;"></th>
</tr>
</thead>
<tbody>
@foreach (MembershipUser mu in Model)
{
<tr>
<td>
@mu.UserName
</td>
<td>
<a href="mailto:@mu.Email" title="@mu.Email">@mu.Email</a>
</td>
<td>
@mu.CreationDate.Humanize()
</td>
<td>
@(mu.LastLoginDate == DateTime.MinValue
? "Never"
: mu.LastLoginDate.Humanize())
</td>
<td>
@(mu.LastLockoutDate == DateTime.MinValue
? "Never"
: mu.LastLockoutDate.Humanize())
</td>
<td class="text-right">
@(mu.IsApproved
? Html.ActionLink("Unapprove", nameof(UsersController.Unapprove), new
{
<thead>
<tr>
<th>
Username
</th>
<th>
Email Address
</th>
<th>
Registration Time
</th>
<th>
Last Login Time
</th>
<th>
Last Lockout Time
</th>
<th style="width: 100px;"></th>
<th style="width: 100px;"></th>
<th style="width: 100px;"></th>
</tr>
</thead>
<tbody>
@foreach (MembershipUser mu in Model)
{
<tr>
<td>
@mu.UserName
</td>
<td>
<a href="mailto:@mu.Email" title="@mu.Email">@mu.Email</a>
</td>
<td>
@mu.CreationDate.Humanize()
</td>
<td>
@(mu.LastLoginDate == DateTime.MinValue
? "Never"
: mu.LastLoginDate.Humanize())
</td>
<td>
@(mu.LastLockoutDate == DateTime.MinValue
? "Never"
: mu.LastLockoutDate.Humanize())
</td>
<td class="text-right">
@(mu.IsApproved
? Html.ActionLink("Unapprove", nameof(UsersController.Unapprove), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button delete-button"
})
: Html.ActionLink("Approve", nameof(UsersController.Approve), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button add-button"
}))
</td>
<td class="text-right">
@(!mu.IsLockedOut
? Html.ActionLink("Lock", nameof(UsersController.Lock), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button delete-button"
})
: Html.ActionLink("Unlock", nameof(UsersController.Unlock), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button add-button"
}))
</td>
<td>
@Html.ActionLink("Delete", nameof(UsersController.Delete), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button delete-button"
})
: Html.ActionLink("Approve", nameof(UsersController.Approve), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button add-button"
}))
</td>
<td class="text-right">
@(!mu.IsLockedOut
? Html.ActionLink("Lock", nameof(UsersController.Lock), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button delete-button"
})
: Html.ActionLink("Unlock", nameof(UsersController.Unlock), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button add-button"
}))
</td>
<td>
@Html.ActionLink("Delete", nameof(UsersController.Delete), new
{
id = mu.ProviderUserKey
}, new
{
@class = "button delete-button",
onclick = @"return !(confirm(""Are you sure you want to delete this user?"") === false);"
})
</td>
</tr>
}
</tbody>
}, new
{
@class = "button delete-button",
onclick = @"return !(confirm(""Are you sure you want to delete this user?"") === false);"
})
</td>
</tr>
}
</tbody>
</table>

View File

@ -1,36 +1,36 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="BuildFeed" />
<add namespace="BuildFeed.Local" />
<add namespace="BuildFeed.Admin.Controllers" />
</namespaces>
</pages>
</system.web.webPages.razor>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="BuildFeed" />
<add namespace="BuildFeed.Local" />
<add namespace="BuildFeed.Admin.Controllers" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
<system.webServer>
<handlers>
<remove name="BlockViewHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>

View File

@ -1,6 +1,6 @@
using System.Web.Mvc;
namespace BuildFeed.Areas.admin
namespace BuildFeed.Admin
{
public class AdminAreaRegistration : AreaRegistration
{

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<users>
<user>77FAD24B9B2579631630796D246267C3</user>
<user>77FAD24B9B2579631630796D246267C3</user>
</users>

View File

@ -372,16 +372,6 @@
<Content Include="res\css\inc\_variables.scss" />
<Content Include="res\css\inc\_nord.scss" />
<Content Include="res\css\winter.scss" />
<None Include="Scripts\jquery-3.3.1.intellisense.js" />
<Content Include="Scripts\jquery-3.3.1.js" />
<Content Include="Scripts\jquery-3.3.1.min.js" />
<Content Include="Scripts\jquery-3.3.1.slim.js" />
<Content Include="Scripts\jquery-3.3.1.slim.min.js" />
<None Include="Scripts\jquery.validate-vsdoc.js" />
<Content Include="Scripts\jquery.validate.js" />
<Content Include="Scripts\jquery.validate.min.js" />
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
<Content Include="Scripts\trumbowyg\langs\ar.min.js" />
<Content Include="Scripts\trumbowyg\langs\bg.min.js" />
<Content Include="Scripts\trumbowyg\langs\by.min.js" />
@ -482,8 +472,6 @@
<Content Include="Views\front\AddBulk.cshtml" />
<Content Include="Views\account\validate-success.cshtml" />
<Content Include="Views\account\validate-failure.cshtml" />
<Content Include="Scripts\jquery-3.3.1.slim.min.map" />
<Content Include="Scripts\jquery-3.3.1.min.map" />
<None Include="tsconfig.json" />
<Content Include="Views\front\ViewFamily.cshtml" />
</ItemGroup>

View File

@ -17,7 +17,7 @@ namespace BuildFeed.Code
var returnArray = new byte[byteCount];
byte curByte = 0,
bitsRemaining = 8;
bitsRemaining = 8;
int arrayIndex = 0;
@ -62,7 +62,7 @@ namespace BuildFeed.Code
var returnArray = new char[charCount];
byte nextChar = 0,
bitsRemaining = 5;
bitsRemaining = 5;
int arrayIndex = 0;
foreach (byte b in input)
@ -103,11 +103,13 @@ namespace BuildFeed.Code
{
return value - 65;
}
//50-55 == numbers 2-7
if (value < 56 && value > 49)
{
return value - 24;
}
//97-122 == lowercase letters
if (value < 123 && value > 96)
{

View File

@ -10,11 +10,18 @@ namespace BuildFeed.Code
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bool success = DateTime.TryParse(value.AttemptedValue, CultureInfo.CurrentUICulture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out DateTime retValue);
bool success = DateTime.TryParse(value.AttemptedValue,
CultureInfo.CurrentUICulture.DateTimeFormat,
DateTimeStyles.AllowWhiteSpaces,
out DateTime retValue);
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

View File

@ -13,7 +13,7 @@ namespace BuildFeed.Code
public static IHtmlString CheckboxListForEnum<T>(this HtmlHelper html, string id, T currentItem)
where T : struct
{
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
foreach (T enumItem in Enum.GetValues(typeof(T)).Cast<T>())
{
@ -26,16 +26,17 @@ namespace BuildFeed.Code
continue;
}
TagBuilder wrapper = new TagBuilder("div");
var wrapper = new TagBuilder("div");
wrapper.Attributes.Add("class", "checkbox");
TagBuilder label = new TagBuilder("label");
var label = new TagBuilder("label");
TagBuilder input = new TagBuilder("input");
var 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);

View File

@ -9,12 +9,12 @@ namespace BuildFeed.Code
{
public static async Task SendRegistrationEmail(MembershipUser mu, string validationLink)
{
using (MailMessage mm = new MailMessage(EMAIL_FROM, mu.Email))
using (var mm = new MailMessage(EMAIL_FROM, mu.Email))
{
mm.Subject = string.Format(VariantTerms.Email_Registration_Subject, InvariantTerms.SiteName);
mm.Body = string.Format(VariantTerms.Email_Registration_Body, InvariantTerms.SiteName, validationLink);
using (SmtpClient sc = new SmtpClient())
using (var sc = new SmtpClient())
{
await sc.SendMailAsync(mm);
}

View File

@ -19,48 +19,50 @@ namespace BuildFeed.Code
AppId = Guid.Parse(ConfigurationManager.AppSettings["push:AppId"]),
IncludedSegments = new List<string>
{
#if DEBUG
#if DEBUG
"Testers"
#else
#else
"All"
#endif
#endif
},
Headings =
{
{LanguageCodes.Arabic, GetNewBuildTitleForLanguage("ar")},
{LanguageCodes.Czech, GetNewBuildTitleForLanguage("cs")},
{LanguageCodes.German, GetNewBuildTitleForLanguage("de")},
{LanguageCodes.Greek, GetNewBuildTitleForLanguage("el")},
{LanguageCodes.English, GetNewBuildTitleForLanguage("en")},
{LanguageCodes.Spanish, GetNewBuildTitleForLanguage("es")},
{LanguageCodes.Persian, GetNewBuildTitleForLanguage("fa")},
{LanguageCodes.Finnish, GetNewBuildTitleForLanguage("fi")},
{LanguageCodes.French, GetNewBuildTitleForLanguage("fr")},
{LanguageCodes.Hebrew, GetNewBuildTitleForLanguage("he")},
{LanguageCodes.Croatian, GetNewBuildTitleForLanguage("hr")},
{LanguageCodes.Hungarian, GetNewBuildTitleForLanguage("hu")},
{LanguageCodes.Indonesian, GetNewBuildTitleForLanguage("id")},
{LanguageCodes.Italian, GetNewBuildTitleForLanguage("it")},
{LanguageCodes.Japanese, GetNewBuildTitleForLanguage("ja")},
{LanguageCodes.Korean, GetNewBuildTitleForLanguage("ko")},
{LanguageCodes.Lithuanian, GetNewBuildTitleForLanguage("lt")},
{LanguageCodes.Dutch, GetNewBuildTitleForLanguage("nl")},
{LanguageCodes.Polish, GetNewBuildTitleForLanguage("pl")},
{LanguageCodes.Portuguese, GetNewBuildTitleForLanguage("pt")}, // Portuguese translation has notification translation ready, Brazil is used more, but not available right now.
{LanguageCodes.Romanian, GetNewBuildTitleForLanguage("ro")},
{LanguageCodes.Russian, GetNewBuildTitleForLanguage("ru")},
{LanguageCodes.Slovak, GetNewBuildTitleForLanguage("sk")},
{ LanguageCodes.Arabic, GetNewBuildTitleForLanguage("ar") },
{ LanguageCodes.Czech, GetNewBuildTitleForLanguage("cs") },
{ LanguageCodes.German, GetNewBuildTitleForLanguage("de") },
{ LanguageCodes.Greek, GetNewBuildTitleForLanguage("el") },
{ LanguageCodes.English, GetNewBuildTitleForLanguage("en") },
{ LanguageCodes.Spanish, GetNewBuildTitleForLanguage("es") },
{ LanguageCodes.Persian, GetNewBuildTitleForLanguage("fa") },
{ LanguageCodes.Finnish, GetNewBuildTitleForLanguage("fi") },
{ LanguageCodes.French, GetNewBuildTitleForLanguage("fr") },
{ LanguageCodes.Hebrew, GetNewBuildTitleForLanguage("he") },
{ LanguageCodes.Croatian, GetNewBuildTitleForLanguage("hr") },
{ LanguageCodes.Hungarian, GetNewBuildTitleForLanguage("hu") },
{ LanguageCodes.Indonesian, GetNewBuildTitleForLanguage("id") },
{ LanguageCodes.Italian, GetNewBuildTitleForLanguage("it") },
{ LanguageCodes.Japanese, GetNewBuildTitleForLanguage("ja") },
{ LanguageCodes.Korean, GetNewBuildTitleForLanguage("ko") },
{ LanguageCodes.Lithuanian, GetNewBuildTitleForLanguage("lt") },
{ LanguageCodes.Dutch, GetNewBuildTitleForLanguage("nl") },
{ LanguageCodes.Polish, GetNewBuildTitleForLanguage("pl") },
{
LanguageCodes.Portuguese, GetNewBuildTitleForLanguage("pt")
}, // Portuguese translation has notification translation ready, Brazil is used more, but not available right now.
{ LanguageCodes.Romanian, GetNewBuildTitleForLanguage("ro") },
{ LanguageCodes.Russian, GetNewBuildTitleForLanguage("ru") },
{ LanguageCodes.Slovak, GetNewBuildTitleForLanguage("sk") },
// no slovenian support for OneSignal?
{LanguageCodes.Swedish, GetNewBuildTitleForLanguage("sv")},
{LanguageCodes.Turkish, GetNewBuildTitleForLanguage("tr")},
{LanguageCodes.Ukrainian, GetNewBuildTitleForLanguage("uk")},
{LanguageCodes.Vietnamese, GetNewBuildTitleForLanguage("vi")},
{LanguageCodes.ChineseSimplified, GetNewBuildTitleForLanguage("zh-hans")},
{LanguageCodes.ChineseTraditional, GetNewBuildTitleForLanguage("zh-hant")}
{ LanguageCodes.Swedish, GetNewBuildTitleForLanguage("sv") },
{ LanguageCodes.Turkish, GetNewBuildTitleForLanguage("tr") },
{ LanguageCodes.Ukrainian, GetNewBuildTitleForLanguage("uk") },
{ LanguageCodes.Vietnamese, GetNewBuildTitleForLanguage("vi") },
{ LanguageCodes.ChineseSimplified, GetNewBuildTitleForLanguage("zh-hans") },
{ LanguageCodes.ChineseTraditional, GetNewBuildTitleForLanguage("zh-hant") }
},
Contents =
{
{LanguageCodes.English, build.AlternateBuildString}
{ LanguageCodes.English, build.AlternateBuildString }
},
Url = url
});
@ -68,9 +70,13 @@ namespace BuildFeed.Code
private static string GetNewBuildTitleForLanguage(string lang)
{
string localised = VariantTerms.ResourceManager.GetString(nameof(VariantTerms.Notification_NewBuild), CultureInfo.GetCultureInfo(lang));
string localised = VariantTerms.ResourceManager.GetString(nameof(VariantTerms.Notification_NewBuild),
CultureInfo.GetCultureInfo(lang));
string generic = VariantTerms.ResourceManager.GetString(nameof(VariantTerms.Notification_NewBuild), CultureInfo.InvariantCulture) ?? "{0}";
string generic =
VariantTerms.ResourceManager.GetString(nameof(VariantTerms.Notification_NewBuild),
CultureInfo.InvariantCulture)
?? "{0}";
return string.IsNullOrEmpty(localised)
? string.Format(generic, InvariantTerms.SiteName)

View File

@ -64,10 +64,12 @@ namespace BuildFeed.Code.Options
{
try
{
CultureInfo ci = (CultureInfo)CultureInfo.GetCultureInfo(langCookie).Clone();
var ci = (CultureInfo)CultureInfo.GetCultureInfo(langCookie).Clone();
// 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)
{
ci.DateTimeFormat.Calendar = gc;

View File

@ -10,7 +10,7 @@ namespace BuildFeed.Code
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
Theme theme = new Theme(Theme.DetectTheme(filterContext.HttpContext));
var theme = new Theme(Theme.DetectTheme(filterContext.HttpContext));
filterContext.HttpContext.Response.PushPromise("/res/css/default.css");
filterContext.HttpContext.Response.PushPromise(VirtualPathUtility.ToAbsolute(theme.CssPath));
@ -18,6 +18,7 @@ namespace BuildFeed.Code
{
filterContext.HttpContext.Response.PushPromise("/res/css/rtl.css");
}
filterContext.HttpContext.Response.PushPromise("/res/ts/bfs.js");
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
@ -31,9 +30,9 @@ namespace BuildFeed.Controllers
? 129600
: 60;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength);
var ticket = new FormsAuthenticationTicket(ru.UserName, true, expiryLength);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
var cookieTicket = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
Expires = DateTime.Now.AddMinutes(expiryLength),
Path = FormsAuthentication.FormsCookiePath
@ -98,7 +97,13 @@ namespace BuildFeed.Controllers
{
if (ModelState.IsValid)
{
MembershipUser mu = Membership.CreateUser(ru.UserName, ru.Password, ru.EmailAddress, "{IGNORE}", "{IGNORE}", false, out MembershipCreateStatus status);
MembershipUser mu = Membership.CreateUser(ru.UserName,
ru.Password,
ru.EmailAddress,
"{IGNORE}",
"{IGNORE}",
false,
out MembershipCreateStatus status);
switch (status)
{
@ -106,17 +111,18 @@ namespace BuildFeed.Controllers
{
Roles.AddUserToRole(mu.UserName, "Users");
MongoMembershipProvider provider = (MongoMembershipProvider)Membership.Provider;
Guid id = (Guid)mu.ProviderUserKey;
var provider = (MongoMembershipProvider)Membership.Provider;
var id = (Guid)mu.ProviderUserKey;
string hash = (await provider.GenerateValidationHash(id)).ToLowerInvariant();
string fullUrl = Request.Url?.GetLeftPart(UriPartial.Authority) + Url.Action("Validate",
"Account",
new
{
id,
hash
});
string fullUrl = Request.Url?.GetLeftPart(UriPartial.Authority)
+ Url.Action("Validate",
"Account",
new
{
id,
hash
});
await EmailManager.SendRegistrationEmail(mu, fullUrl);
return RedirectToAction(nameof(RegisterThanks));
}
@ -144,7 +150,7 @@ namespace BuildFeed.Controllers
[Route("validate/{id:guid}/{hash}/")]
public async Task<ActionResult> Validate(Guid id, string hash)
{
MongoMembershipProvider provider = (MongoMembershipProvider)Membership.Provider;
var provider = (MongoMembershipProvider)Membership.Provider;
bool success = await provider.ValidateUserFromHash(id, hash);
return View(success

View File

@ -27,39 +27,30 @@ namespace BuildFeed.Controllers
}
public async Task<ApiBuild[]> GetBuilds(int limit = 20, int skip = 0)
{
return (from b in await _bModel.SelectBuildsByOrder(limit, skip)
select Mapper.Map<ApiBuild>(b)).ToArray();
}
=> (from b in await _bModel.SelectBuildsByOrder(limit, skip)
select Mapper.Map<ApiBuild>(b)).ToArray();
public async Task<FrontBuildGroup[]> GetBuildGroups(int limit = 20, int skip = 0)
{
FrontBuildGroup[] bgroups = await _bModel.SelectAllGroups(limit, skip);
var bgroups = await _bModel.SelectAllGroups(limit, skip);
return bgroups.ToArray();
}
public async Task<ApiBuild[]> GetBuildsForBuildGroup(uint major, uint minor, uint number, uint? revision = null)
{
return (from b in await _bModel.SelectGroup(new BuildGroup
{
Major = major,
Minor = minor,
Build = number,
Revision = revision
})
select Mapper.Map<ApiBuild>(b)).ToArray();
}
=> (from b in await _bModel.SelectGroup(new BuildGroup
{
Major = major,
Minor = minor,
Build = number,
Revision = revision
})
select Mapper.Map<ApiBuild>(b)).ToArray();
public async Task<ApiBuild[]> GetBuildsByLab(string lab, int limit = 20, int skip = 0)
{
return (from b in await _bModel.SelectLab(lab, limit, skip)
select Mapper.Map<ApiBuild>(b)).ToArray();
}
=> (from b in await _bModel.SelectLab(lab, limit, skip)
select Mapper.Map<ApiBuild>(b)).ToArray();
public async Task<List<FamilyOverview>> GetFamilyOverviews()
{
return await _bModel.SelectFamilyOverviews();
}
public async Task<List<FamilyOverview>> GetFamilyOverviews() => await _bModel.SelectFamilyOverviews();
public async Task<IEnumerable<string>> GetWin10Labs()
{
@ -77,11 +68,14 @@ namespace BuildFeed.Controllers
{
return false;
}
if (Membership.ValidateUser(apiModel.Username, apiModel.Password) && (Roles.IsUserInRole(apiModel.Username, "Editors") || Roles.IsUserInRole(apiModel.Username, "Administrators")))
if (Membership.ValidateUser(apiModel.Username, apiModel.Password)
&& (Roles.IsUserInRole(apiModel.Username, "Editors")
|| Roles.IsUserInRole(apiModel.Username, "Administrators")))
{
var generateOldItem = new Func<NewBuild, BuildDetails>(nb =>
{
BuildDetails bi = new BuildDetails
var bi = new BuildDetails
{
MajorVersion = nb.MajorVersion,
MinorVersion = nb.MinorVersion,
@ -97,7 +91,7 @@ namespace BuildFeed.Controllers
return bi;
});
IEnumerable<Build> builds = apiModel.NewBuilds.Select(nb => new Build
var builds = apiModel.NewBuilds.Select(nb => new Build
{
MajorVersion = nb.MajorVersion,
MinorVersion = nb.MinorVersion,
@ -127,12 +121,14 @@ namespace BuildFeed.Controllers
{
await _bModel.Insert(build);
OneSignalClient osc = new OneSignalClient(ConfigurationManager.AppSettings["push:OneSignalApiKey"]);
var 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");
}
return true;
}
return false;
}
@ -146,26 +142,26 @@ namespace BuildFeed.Controllers
var results = new List<SearchResult>();
results.AddRange(from s in (from c in await _bModel.SelectAllSources()
select new
{
Text = MvcExtensions.GetDisplayTextForEnum(c),
Value = c
})
where s.Text.ToLower().Contains(id.ToLower())
orderby s.Text.ToLower().IndexOf(id.ToLower(), StringComparison.Ordinal)
select new SearchResult
{
Url = Url.Route("Source Root",
new
{
controller = "Front",
action = "ViewSource",
source = s.Value
}),
Label = s.Text.Replace(id, "<strong>" + id + "</strong>"),
Title = s.Text,
Group = VariantTerms.Search_Source
});
select new
{
Text = MvcExtensions.GetDisplayTextForEnum(c),
Value = c
})
where s.Text.ToLower().Contains(id.ToLower())
orderby s.Text.ToLower().IndexOf(id.ToLower(), StringComparison.Ordinal)
select new SearchResult
{
Url = Url.Route("Source Root",
new
{
controller = "Front",
action = "ViewSource",
source = s.Value
}),
Label = s.Text.Replace(id, "<strong>" + id + "</strong>"),
Title = s.Text,
Group = VariantTerms.Search_Source
});
if (results.Count >= maxResults)
{
@ -173,22 +169,22 @@ namespace BuildFeed.Controllers
}
results.AddRange(from v in await _bModel.SelectAllVersions()
where $"{v.Major}.{v.Minor}".StartsWith(id)
orderby v.Major descending, v.Minor descending
select new SearchResult
{
Url = Url.Route("Version Root",
new
{
controller = "Front",
action = "ViewVersion",
major = v.Major,
minor = v.Minor
}),
Label = $"{v.Major}.{v.Minor}".Replace(id, "<strong>" + id + "</strong>"),
Title = "",
Group = VariantTerms.Search_Version
});
where $"{v.Major}.{v.Minor}".StartsWith(id)
orderby v.Major descending, v.Minor descending
select new SearchResult
{
Url = Url.Route("Version Root",
new
{
controller = "Front",
action = "ViewVersion",
major = v.Major,
minor = v.Minor
}),
Label = $"{v.Major}.{v.Minor}".Replace(id, "<strong>" + id + "</strong>"),
Title = "",
Group = VariantTerms.Search_Version
});
if (results.Count >= maxResults)
{
@ -196,21 +192,21 @@ namespace BuildFeed.Controllers
}
results.AddRange(from y in await _bModel.SelectAllYears()
where y.ToString().Contains(id)
orderby y descending
select new SearchResult
{
Url = Url.Route("Year Root",
new
{
controller = "Front",
action = "ViewYear",
year = y
}),
Label = y.ToString().Replace(id, "<strong>" + id + "</strong>"),
Title = "",
Group = VariantTerms.Search_Year
});
where y.ToString().Contains(id)
orderby y descending
select new SearchResult
{
Url = Url.Route("Year Root",
new
{
controller = "Front",
action = "ViewYear",
year = y
}),
Label = y.ToString().Replace(id, "<strong>" + id + "</strong>"),
Title = "",
Group = VariantTerms.Search_Year
});
if (results.Count >= maxResults)
{
@ -218,19 +214,19 @@ namespace BuildFeed.Controllers
}
results.AddRange(from l in await _bModel.SearchLabs(id)
select new SearchResult
{
Url = Url.Route("Lab Root",
new
{
controller = "Front",
action = "ViewLab",
lab = l.Replace('/', '-')
}),
Label = l.Replace(id, $"<strong>{id}</strong>"),
Title = l,
Group = VariantTerms.Search_Lab
});
select new SearchResult
{
Url = Url.Route("Lab Root",
new
{
controller = "Front",
action = "ViewLab",
lab = l.Replace('/', '-')
}),
Label = l.Replace(id, $"<strong>{id}</strong>"),
Title = l,
Group = VariantTerms.Search_Lab
});
if (results.Count >= maxResults)
{
@ -238,19 +234,19 @@ namespace BuildFeed.Controllers
}
results.AddRange(from b in await _bModel.SelectBuildsByStringSearch(id, maxResults)
select new SearchResult
{
Url = Url.Route("Build",
new
{
controller = "Front",
action = "ViewBuild",
id = b.Id
}),
Label = b.FullBuildString.Replace(id, $"<strong>{id}</strong>"),
Title = b.FullBuildString,
Group = VariantTerms.Search_Build
});
select new SearchResult
{
Url = Url.Route("Build",
new
{
controller = "Front",
action = "ViewBuild",
id = b.Id
}),
Label = b.FullBuildString.Replace(id, $"<strong>{id}</strong>"),
Title = b.FullBuildString,
Group = VariantTerms.Search_Build
});
if (results.Count == 0)
{

View File

@ -35,7 +35,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> Index()
{
ViewBag.Versions = await _bModel.SelectAllFamilies();
@ -50,7 +50,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> IndexPage(int page)
{
var buildGroups = await _bModel.SelectAllGroups(PAGE_SIZE, (page - 1) * PAGE_SIZE);
@ -73,7 +73,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewGroup(uint major, uint minor, uint number, uint? revision = null)
{
var bg = new BuildGroup
@ -99,7 +99,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewBuild(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -131,7 +131,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[CustomContentType(ContentType = "image/png", Order = 2)]
#endif
#endif
public async Task<ActionResult> TwitterCard(Guid id)
{
Build b = await _bModel.SelectById(id);
@ -279,7 +279,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewFamily(ProjectFamily family)
{
return await ViewFamilyPage(family, 1);
@ -289,7 +289,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewFamilyPage(ProjectFamily family, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -317,7 +317,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewLab(string lab)
{
return await ViewLabPage(lab, 1);
@ -327,7 +327,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewLabPage(string lab, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -355,7 +355,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewSource(TypeOfSource source)
{
return await ViewSourcePage(source, 1);
@ -365,7 +365,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewSourcePage(TypeOfSource source, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -393,7 +393,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewYear(int year)
{
return await ViewYearPage(year, 1);
@ -403,7 +403,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "page", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewYearPage(int year, int page)
{
ViewBag.MetaItem = await _mModel.SelectById(new MetaItemKey
@ -430,7 +430,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewVersion(uint major, uint minor)
{
return await ViewVersionPage(major, minor, 1);
@ -440,7 +440,7 @@ namespace BuildFeed.Controllers
#if !DEBUG
[OutputCache(Duration = 600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
[OutputCachePush(Order = 2)]
#endif
#endif
public async Task<ActionResult> ViewVersionPage(uint major, uint minor, int page)
{
string valueString = $"{major}.{minor}";

View File

@ -29,12 +29,12 @@ namespace BuildFeed.Controllers
}
[Route("sitemap/")]
#if !DEBUG
#if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
#endif
#endif
public async Task<ActionResult> Sitemap()
{
List<Build> builds = await _bModel.SelectBuildsByOrder();
var builds = await _bModel.SelectBuildsByOrder();
var actions = new Dictionary<string, SitemapPagedAction[]>
{
{
@ -54,144 +54,146 @@ namespace BuildFeed.Controllers
},
{
"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()
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()
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
{
controller = "Front",
action = "ViewYear",
year = bv.Key,
page = 1
}),
Pages = (bv.Count() + (FrontController.PAGE_SIZE - 1)) / FrontController.PAGE_SIZE
}).ToArray()
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
{
controller = "Front",
action = "ViewYear",
year = bv.Key,
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()
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
var model = new SitemapData
{
Builds = (from b in builds
group b by new
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
Build = b.Number,
b.Revision
}
into bg
orderby bg.Key.Major descending, bg.Key.Minor descending, bg.Key.Build descending, bg.Key.Revision descending
select new SitemapDataBuildGroup
{
Id = new BuildGroup
{
Major = bg.Key.Major,
Minor = bg.Key.Minor,
Build = bg.Key.Build,
Revision = bg.Key.Revision
},
Builds = (from bgb in bg
select new SitemapDataBuild
{
Id = bgb.Id,
Name = bgb.FullBuildString
}).ToArray()
}).ToArray(),
group b by new
{
Major = b.MajorVersion,
Minor = b.MinorVersion,
Build = b.Number,
b.Revision
}
into bg
orderby bg.Key.Major descending, bg.Key.Minor descending, bg.Key.Build descending, bg.Key.Revision
descending
select new SitemapDataBuildGroup
{
Id = new BuildGroup
{
Major = bg.Key.Major,
Minor = bg.Key.Minor,
Build = bg.Key.Build,
Revision = bg.Key.Revision
},
Builds = (from bgb in bg
select new SitemapDataBuild
{
Id = bgb.Id,
Name = bgb.FullBuildString
}).ToArray()
}).ToArray(),
Actions = actions,
Labs = (from b in builds
group b by b.Lab
into lab
select lab.Key).ToArray()
group b by b.Lab
into lab
select lab.Key).ToArray()
};
return View(model);
}
[Route("xml-sitemap/")]
#if !DEBUG
#if !DEBUG
[OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName;lang;theme")]
#endif
#endif
public async Task<ActionResult> XmlSitemap()
{
XNamespace xn = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
var xlist = new List<XElement>();
// home page
XElement home = new XElement(xn + "url");
var home = new XElement(xn + "url");
home.Add(new XElement(xn + "loc", Request.Url?.GetLeftPart(UriPartial.Authority) + "/"));
home.Add(new XElement(xn + "changefreq", "daily"));
xlist.Add(home);
foreach (Build b in await _bModel.Select())
{
XElement url = new XElement(xn + "url");
var url = new XElement(xn + "url");
url.Add(new XElement(xn + "loc",
Request.Url?.GetLeftPart(UriPartial.Authority) + Url.Action("ViewBuild",
Request.Url?.GetLeftPart(UriPartial.Authority)
+ Url.Action("ViewBuild",
"Front",
new
{
@ -201,13 +203,14 @@ namespace BuildFeed.Controllers
{
url.Add(new XElement(xn + "lastmod", b.Modified.ToString("yyyy-MM-dd")));
}
xlist.Add(url);
}
XDeclaration decl = new XDeclaration("1.0", "utf-8", "");
XElement root = new XElement(xn + "urlset", xlist);
var decl = new XDeclaration("1.0", "utf-8", "");
var root = new XElement(xn + "urlset", xlist);
XDocument xdoc = new XDocument(decl, root);
var xdoc = new XDocument(decl, root);
Response.ContentType = "application/xml";
xdoc.Save(Response.OutputStream);

View File

@ -26,7 +26,7 @@ namespace BuildFeed
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
DateTimeModelBinder db = new DateTimeModelBinder();
var db = new DateTimeModelBinder();
ModelBinders.Binders.Add(typeof(DateTime), db);
ModelBinders.Binders.Add(typeof(DateTime?), db);
@ -42,9 +42,9 @@ namespace BuildFeed
public override string GetVaryByCustomString(HttpContext context, string custom)
{
string[] parts = custom.Split(';');
var parts = custom.Split(';');
var varyParts = new List<string>();
HttpContextWrapper contextWrapper = new HttpContextWrapper(context);
var contextWrapper = new HttpContextWrapper(context);
foreach (string part in parts)
{

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,429 +0,0 @@
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*!
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
if (container) {
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
}
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
$(function () {
$jQval.unobtrusive.parse(document);
});
}(jQuery));

File diff suppressed because one or more lines are too long

View File

@ -1,32 +1,32 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="BuildFeed" />
<add namespace="BuildFeed.Local" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="BuildFeed" />
<add namespace="BuildFeed.Local" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>

View File

@ -1,68 +1,69 @@
@using BuildFeed.Controllers
@model BuildFeed.Model.View.LoginUser
@using BuildFeed.Model.View
@model LoginUser
@{
ViewBag.Title = $"{VariantTerms.Support_Login} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
ViewBag.Title = $"{VariantTerms.Support_Login} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
}
<h1>@VariantTerms.Support_Login</h1>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.AntiForgeryToken()
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
<div class="form-group">
@Html.LabelFor(model => model.UserName)
<div>
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserName)
<div>
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password)
<div>
@Html.PasswordFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password)
<div>
@Html.PasswordFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<label for="@Html.IdFor(model => model.RememberMe)">
@Html.CheckBoxFor(model => model.RememberMe) @Html.DisplayNameFor(model => model.RememberMe)
</label>
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<label for="@Html.IdFor(model => model.RememberMe)">
@Html.CheckBoxFor(model => model.RememberMe) @Html.DisplayNameFor(model => model.RememberMe)
</label>
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_Login" /> &ensp;
@Html.ActionLink(VariantTerms.Support_Register, nameof(AccountController.Register), new
{
controller = "Account"
}, new
{
@class = "button"
})
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_Login" /> &ensp;
@Html.ActionLink(VariantTerms.Support_Register, nameof(AccountController.Register), new
{
controller = "Account"
}, new
{
@class = "button"
})
</div>
</div>
}
@section Scripts
{
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" integrity="sha256-g1QKGxqsp+x5JkuN/JjHl96je2wztgS5Wo4h4c7gm9M=" crossorigin="anonymous"></script>
}

View File

@ -1,59 +1,60 @@
@model BuildFeed.Model.View.ChangePassword
@using BuildFeed.Model.View
@model ChangePassword
@{
ViewBag.Title = $"{VariantTerms.Support_ChangePassword} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
ViewBag.Title = $"{VariantTerms.Support_ChangePassword} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
}
<h1>@VariantTerms.Support_ChangePassword</h1>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.AntiForgeryToken()
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
<div class="form-group">
@Html.LabelFor(model => model.OldPassword)
<div>
@Html.PasswordFor(model => model.OldPassword)
@Html.ValidationMessageFor(model => model.OldPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.OldPassword)
<div>
@Html.PasswordFor(model => model.OldPassword)
@Html.ValidationMessageFor(model => model.OldPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.NewPassword)
<div>
@Html.PasswordFor(model => model.NewPassword)
@Html.ValidationMessageFor(model => model.NewPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.NewPassword)
<div>
@Html.PasswordFor(model => model.NewPassword)
@Html.ValidationMessageFor(model => model.NewPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ConfirmNewPassword)
<div>
@Html.PasswordFor(model => model.ConfirmNewPassword)
@Html.ValidationMessageFor(model => model.ConfirmNewPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ConfirmNewPassword)
<div>
@Html.PasswordFor(model => model.ConfirmNewPassword)
@Html.ValidationMessageFor(model => model.ConfirmNewPassword)
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_ChangePassword" class="btn btn-primary" />
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_ChangePassword" class="btn btn-primary" />
</div>
</div>
}
@section Scripts
{
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" integrity="sha256-g1QKGxqsp+x5JkuN/JjHl96je2wztgS5Wo4h4c7gm9M=" crossorigin="anonymous"></script>
}

View File

@ -1,67 +1,68 @@
@model BuildFeed.Model.View.RegistrationUser
@using BuildFeed.Model.View
@model RegistrationUser
@{
ViewBag.Title = $"{VariantTerms.Support_Register} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
ViewBag.Title = $"{VariantTerms.Support_Register} | {InvariantTerms.SiteName}";
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
}
<h1>@VariantTerms.Support_Register</h1>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.AntiForgeryToken()
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
if (ViewData["ErrorMessage"] != null)
{
<p class="text-danger">
@ViewData["ErrorMessage"]
</p>
}
<div class="form-group">
@Html.LabelFor(model => model.UserName)
<div>
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserName)
<div>
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password)
<div>
@Html.PasswordFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password)
<div>
@Html.PasswordFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ConfirmPassword)
<div>
@Html.PasswordFor(model => model.ConfirmPassword)
@Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ConfirmPassword)
<div>
@Html.PasswordFor(model => model.ConfirmPassword)
@Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.EmailAddress)
<div class="col-md-10">
@Html.TextBoxFor(model => model.EmailAddress)
@Html.ValidationMessageFor(model => model.EmailAddress)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.EmailAddress)
<div class="col-md-10">
@Html.TextBoxFor(model => model.EmailAddress)
@Html.ValidationMessageFor(model => model.EmailAddress)
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_Register" />
</div>
</div>
<div class="form-group">
<span class="label-placeholder"></span>
<div>
<input type="submit" value="@VariantTerms.Support_Register" />
</div>
</div>
}
@section Scripts
{
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" integrity="sha256-g1QKGxqsp+x5JkuN/JjHl96je2wztgS5Wo4h4c7gm9M=" crossorigin="anonymous"></script>
}

View File

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

View File

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

View File

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

View File

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

View File

@ -4,57 +4,58 @@
@using Humanizer
@model IEnumerable<FrontBuildGroup>
@{
ViewBag.Title = $"{string.Format(VariantTerms.Front_HomepageH1, InvariantTerms.ProductName)} {string.Format(VariantTerms.Common_TitlePage, (int)ViewBag.PageNumber)} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{string.Format(VariantTerms.Front_HomepageH1, InvariantTerms.ProductName)} {string.Format(VariantTerms.Common_TitlePage, (int)ViewBag.PageNumber)} | {InvariantTerms.SiteName}";
}
@section head
{
<meta name="robots" content="noindex, follow" />
<meta name="robots" content="noindex, follow" />
}
<h1>@string.Format(VariantTerms.Front_HomepageH1, InvariantTerms.ProductName)</h1>
<h3>@VariantTerms.Front_Listing</h3>
<div class="build-group-listing">
@foreach (FrontBuildGroup group in Model)
{
<div class="build-group">
<h3 class="build-group-title">
<a href="@Url.Action(nameof(FrontController.ViewGroup), new
{
major = group.Key.Major,
minor = group.Key.Minor,
number = group.Key.Build,
revision = group.Key.Revision
})">
@group.Key.ToString()
</a>
</h3>
@if (group.LastBuild.HasValue)
{
@foreach (FrontBuildGroup group in Model)
{
<div class="build-group">
<h3 class="build-group-title">
<a href="@Url.Action(nameof(FrontController.ViewGroup), new
{
major = group.Key.Major,
minor = group.Key.Minor,
number = group.Key.Build,
revision = group.Key.Revision
})">
@group.Key.ToString()
</a>
</h3>
@if (group.LastBuild.HasValue)
{
<p class="build-group-p">
@{
DateTime maxDate = group.LastBuild.Value;
if (maxDate.AddDays(28) > DateTime.Now)
{
<span title="@maxDate.ToLongDateWithoutDay()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.Humanize()</span>
}
else
{
<span title="@maxDate.Humanize()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.ToLongDateWithoutDay()</span>
}
}
</p>
}
<p class="build-group-p">
@{
DateTime maxDate = group.LastBuild.Value;
if (maxDate.AddDays(28) > DateTime.Now)
{
<span title="@maxDate.ToLongDateWithoutDay()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.Humanize()</span>
}
else
{
<span title="@maxDate.Humanize()">
<i class="fa fa-calendar fa-fw"></i> @maxDate.ToLongDateWithoutDay()</span>
}
}
<i class="fa fa-server fa-fw"></i> @string.Format(VariantTerms.Front_NumOfBuilds, group.BuildCount)
</p>
}
<p class="build-group-p">
<i class="fa fa-server fa-fw"></i> @string.Format(VariantTerms.Front_NumOfBuilds, group.BuildCount)
</p>
</div>
}
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
</div>
}
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
<div class="build-group-empty"></div>
</div>
@PaginationHelpers.PaginationBlock((int)ViewBag.PageNumber, (int)ViewBag.PageCount, nameof(FrontController.Index), ViewContext.RouteData.Values)

View File

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

View File

@ -126,7 +126,7 @@ else
@section Scripts
{
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="~/Scripts/trumbowyg/trumbowyg.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=" crossorigin="anonymous"></script>

View File

@ -114,7 +114,7 @@
}
}
</select>
<button onclick="window.location = document.getElementById('search-version').value; return false;">
<button onclick="window.location = document.getElementById('search-version').value;return false;">
<i class="fa fa-search"></i>
</button>
</div>

View File

@ -1,143 +1,144 @@
@using System.Globalization
@using BuildFeed.Code
@using BuildFeed.Controllers
@model BuildFeed.Model.Build
@using BuildFeed.Model
@model Build
@{
ViewBag.Title = $"{Model.FullBuildString} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{Model.FullBuildString} | {InvariantTerms.SiteName}";
}
@section head
{
<meta property="og:title" content="@Model.FullBuildString" />
<meta property="og:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
{
id = Model.Id
})">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@Model.FullBuildString | @InvariantTerms.SiteName">
<meta name="twitter:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
<meta property="og:title" content="@Model.FullBuildString" />
<meta property="og:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
{
id = Model.Id
id = Model.Id
})">
@{
string metaDesc = Model.BuildTime.HasValue
? string.Format(VariantTerms.Meta_BuildDate, Model.Number, Model.Lab, Model.BuildTime.Value.ToLongDateWithoutDay())
: string.Format(VariantTerms.Meta_BuildNoDate, Model.Number, Model.Lab);
}
<meta name="description" content="@metaDesc" />
<meta property="og:description" content="@metaDesc" />
<meta name="twitter:description" content="@metaDesc" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@Model.FullBuildString | @InvariantTerms.SiteName">
<meta name="twitter:image" content="@Request.Url.GetLeftPart(UriPartial.Authority)@Url.Action("twitterCard", new
{
id = Model.Id
})">
@{
string metaDesc = Model.BuildTime.HasValue
? string.Format(VariantTerms.Meta_BuildDate, Model.Number, Model.Lab, Model.BuildTime.Value.ToLongDateWithoutDay())
: string.Format(VariantTerms.Meta_BuildNoDate, Model.Number, Model.Lab);
}
<meta name="description" content="@metaDesc" />
<meta property="og:description" content="@metaDesc" />
<meta name="twitter:description" content="@metaDesc" />
}
<h1 dir="ltr" class="eager-wrapping">@Model.AlternateBuildString</h1>
<h3>@VariantTerms.Front_Details</h3>
<div class="build-details-flex">
<div class="build-details-flex-item">
@Html.LabelFor(model => model.MajorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MajorVersion)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.MinorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MinorVersion)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Number)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.Number)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Revision)
<p class="build-details-flex-value">
@if (Model.Revision.HasValue)
{
@Html.DisplayFor(model => model.Revision)
}
else
{
@("-")
}
</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.MajorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MajorVersion)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.MinorVersion)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.MinorVersion)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Number)
<p class="build-details-flex-value">@Html.DisplayFor(model => model.Number)</p>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Revision)
<p class="build-details-flex-value">
@if (Model.Revision.HasValue)
{
@Html.DisplayFor(model => model.Revision)
}
else
{
@("-")
}
</p>
</div>
</div>
<div class="build-details-flex">
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Family)
<div class="build-details-flex-value">
@Html.DisplayFor(model => model.Family, "Enumeration")
</div>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Lab)
<p class="build-details-flex-value">
@if (string.IsNullOrEmpty(Model.Lab))
{
<em>@VariantTerms.Front_NoLabString</em>
}
else
{
@Model.Lab<br />
<a href="@Url.Action(nameof(FrontController.ViewLab), new
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Family)
<div class="build-details-flex-value">
@Html.DisplayFor(model => model.Family, "Enumeration")
</div>
</div>
<div class="build-details-flex-item">
@Html.LabelFor(model => model.Lab)
<p class="build-details-flex-value">
@if (string.IsNullOrEmpty(Model.Lab))
{
<em>@VariantTerms.Front_NoLabString</em>
}
else
{
@Model.Lab<br />
<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>
<div class="build-details-flex">
<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 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 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
{
lab = Model.LabUrl
source = Model.SourceType
})" class="more-link">
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromLab, Model.Lab)
<i class="fa fa-plus-circle fa-sm"></i>&nbsp;
@string.Format(VariantTerms.Front_MoreFromSource, MvcExtensions.GetDisplayTextForEnum(Model.SourceType))
</a>
}
</p>
</div>
</div>
<div class="build-details-flex">
<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 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 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>
</div>
</div>
<br />
@if (!string.IsNullOrWhiteSpace(Model.SourceDetailsFiltered))
{
<h3>@Html.DisplayNameFor(model => model.SourceDetails)</h3>
<div class="build-details-flex-value">@Html.Raw(Model.SourceDetailsFiltered)</div>
<br />
<h3>@Html.DisplayNameFor(model => model.SourceDetails)</h3>
<div class="build-details-flex-value">@Html.Raw(Model.SourceDetailsFiltered)</div>
<br />
}
<h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div>
@ -145,60 +146,61 @@
@if (Roles.IsUserInRole("Editors") || Roles.IsUserInRole("Administrators"))
{
<h3>@VariantTerms.Front_EditorActions</h3>
<p class="build-details-flex-value">
@Html.ActionLink(VariantTerms.Front_Edit, nameof(FrontController.EditBuild), new
{
id = Model.Id
}, new
{
@class = "button edit-button"
})
@if (Roles.IsUserInRole("Administrators"))
{
@Html.ActionLink(VariantTerms.Front_Delete, nameof(FrontController.DeleteBuild), new
{
<h3>@VariantTerms.Front_EditorActions</h3>
<p class="build-details-flex-value">
@Html.ActionLink(VariantTerms.Front_Edit, nameof(FrontController.EditBuild), new
{
id = Model.Id
}, new
{
@class = "button delete-button"
})
}
</p>
}, new
{
@class = "button edit-button"
})
@if (Roles.IsUserInRole("Administrators"))
{
@Html.ActionLink(VariantTerms.Front_Delete, nameof(FrontController.DeleteBuild), new
{
id = Model.Id
}, new
{
@class = "button delete-button"
})
}
</p>
}
<section class="build-details-comments">
<h3>@VariantTerms.Front_Comments</h3>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'buildfeed';
var disqus_url = 'https://buildfeed.net/actions/info/@((object)Model.LegacyId ?? Model.Id)/';
<h3>@VariantTerms.Front_Comments</h3>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'buildfeed';
var disqus_url = 'https://buildfeed.net/actions/info/@((object)Model.LegacyId ?? Model.Id)/';
(function()
{
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])
.appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
(function()
{
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])
.appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</section>
<p>
<a href="@Url.Action(nameof(FrontController.ViewGroup), new
{
major = Model.MajorVersion,
minor = Model.MinorVersion,
number = Model.Number,
revision = Model.Revision
})" class="button">
@VariantTerms.Front_ReturnToOverview
</a>
&ensp;
<a href="@Url.Action(nameof(FrontController.IndexPage), new
{
page = 1
})" class="button">@VariantTerms.Front_ReturnToListing</a>
<a href="@Url.Action(nameof(FrontController.ViewGroup), new
{
major = Model.MajorVersion,
minor = Model.MinorVersion,
number = Model.Number,
revision = Model.Revision
})" class="button">
@VariantTerms.Front_ReturnToOverview
</a>
&ensp;
<a href="@Url.Action(nameof(FrontController.IndexPage), new
{
page = 1
})" class="button">
@VariantTerms.Front_ReturnToListing</a>
</p>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,96 +1,299 @@

@using System.Globalization
@{
ViewBag.Title = $"{VariantTerms.Common_Credits} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{VariantTerms.Common_Credits} | {InvariantTerms.SiteName}";
}
<h1>@VariantTerms.Common_Credits</h1>
<dl class="credits-list">
<dt>BuildFeed Team</dt>
<dd>Thomas Hounsell&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tomhounsell"><i class="fa fa-twitter"></i></a></dd>
<dd>Nick (ultrawindows)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nickurtnl"><i class="fa fa-twitter"></i></a></dd>
<dd>Ahmed (airportsfan)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/airportsfan"><i class="fa fa-twitter"></i></a></dd>
<dd>Lukas (tfwboredom)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tfwboredom"><i class="fa fa-twitter"></i></a></dd>
<dd>Soorya (fakirmeditation)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/fakirmeditation"><i class="fa fa-twitter"></i></a></dd>
<dt>BuildFeed Team</dt>
<dd>
Thomas Hounsell&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tomhounsell">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Nick (ultrawindows)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nickurtnl">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Ahmed (airportsfan)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/airportsfan">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Lukas (tfwboredom)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tfwboredom">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Soorya (fakirmeditation)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/fakirmeditation">
<i class="fa fa-twitter"></i>
</a>
</dd>
</dl>
<div class="credits-wrapper">
<dl class="credits-list">
<dt>Arabic (@System.Globalization.CultureInfo.GetCultureInfo("ar").NativeName) Translation</dt>
<dd>Ahmed (airportsfan)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/airportsfan"><i class="fa fa-twitter"></i></a></dd>
<dt>Bengali (@System.Globalization.CultureInfo.GetCultureInfo("bn").NativeName) Translation</dt>
<dd>Mehedi Hassan&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mehedih_"><i class="fa fa-twitter"></i></a></dd>
<dt>Czech (@System.Globalization.CultureInfo.GetCultureInfo("cs").NativeName) Translation</dt>
<dd>David (rezedus)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/rezedus"><i class="fa fa-twitter"></i></a></dd>
<dt>German (@System.Globalization.CultureInfo.GetCultureInfo("de").NativeName) Translation</dt>
<dd>The Dhel&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/The_Dhel"><i class="fa fa-twitter"></i></a></dd>
<dd>Christopher&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/evil_pro_"><i class="fa fa-twitter"></i></a></dd>
<dt>Greek (@System.Globalization.CultureInfo.GetCultureInfo("el").NativeName) Translation</dt>
<dd>Hacker?pcs</dd>
<dd>Sotiris Michail&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/SnakeOnStick"><i class="fa fa-twitter"></i></a></dd>
<dt>Spanish (@System.Globalization.CultureInfo.GetCultureInfo("es").NativeName) Translation</dt>
<dd>Nightsteed</dd>
<dd>Ben Ward&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/_BenW_"><i class="fa fa-twitter"></i></a></dd>
<dd>Meober Whagby&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ultimofriki"><i class="fa fa-twitter"></i></a></dd>
<dt>Farsi (@System.Globalization.CultureInfo.GetCultureInfo("fa").NativeName) Translation</dt>
<dd>Niloo&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Niloo0937"><i class="fa fa-twitter"></i></a></dd>
<dt>Finnish (@System.Globalization.CultureInfo.GetCultureInfo("fi").NativeName) Translation</dt>
<dd>Daniel Gurney (wheatley)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Daniel_Gurney0"><i class="fa fa-twitter"></i></a></dd>
<dt>French (@System.Globalization.CultureInfo.GetCultureInfo("fr").NativeName) Translation</dt>
<dd>CgSYannick&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/YannickTHFR"><i class="fa fa-twitter"></i></a></dd>
<dd>Gustave M.&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/gus33000"><i class="fa fa-twitter"></i></a></dd>
<dd>Christophe Lavalle&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ChristopheLav"><i class="fa fa-twitter"></i></a></dd>
<dt>Croatian (@System.Globalization.CultureInfo.GetCultureInfo("hr").NativeName) Translation</dt>
<dd>Mario Bešen&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mariobesen"><i class="fa fa-twitter"></i></a></dd>
<dt>Hebrew (@System.Globalization.CultureInfo.GetCultureInfo("he").NativeName) Translation</dt>
<dd>David Fainshtein&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/david_f"><i class="fa fa-twitter"></i></a></dd>
<dt>Indonesian (@System.Globalization.CultureInfo.GetCultureInfo("id").NativeName) Translation</dt>
<dd>Andreas</dd>
<dt>Italian (@System.Globalization.CultureInfo.GetCultureInfo("it").NativeName) Translation</dt>
<dd>Meober Whagby&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ultimofriki"><i class="fa fa-twitter"></i></a></dd>
<dd>Simone Nataz&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/djnataz"><i class="fa fa-twitter"></i></a></dd>
<dt>Japanese (@System.Globalization.CultureInfo.GetCultureInfo("ja").NativeName) Translation</dt>
<dd>parly&ensp;<a target="_blank" rel="nofollow noopener" href="https://github.com/parly"><i class="fa fa-github"></i></a></dd>
<dt>Korean (@System.Globalization.CultureInfo.GetCultureInfo("ko").NativeName) Translation</dt>
<dd>qta3426</dd>
<dd>SD SkyKlouD&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/_SDSkyKlouD"><i class="fa fa-twitter"></i></a></dd>
</dl>
<dl class="credits-list">
<dt>Lithuanian (@System.Globalization.CultureInfo.GetCultureInfo("lt").NativeName) Translation</dt>
<dd>Super User&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Superb_User"><i class="fa fa-twitter"></i></a></dd>
<dt>Dutch (@System.Globalization.CultureInfo.GetCultureInfo("nl").NativeName) Translation</dt>
<dd>Nick (ultrawindows)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nickurtnl"><i class="fa fa-twitter"></i></a></dd>
<dt>Polish (@System.Globalization.CultureInfo.GetCultureInfo("pl").NativeName) Translation</dt>
<dd>piotrulos&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/piotrulos"><i class="fa fa-twitter"></i></a></dd>
<dd>dzaggiel&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/dzaggiel"><i class="fa fa-twitter"></i></a></dd>
<dt>Portuguese (@System.Globalization.CultureInfo.GetCultureInfo("pt").NativeName) Translation</dt>
<dd>OBattler</dd>
<dt>Portugese - Brazilian (@System.Globalization.CultureInfo.GetCultureInfo("pt-br").NativeName) Translation</dt>
<dd>RichardG</dd>
@*<dt>Pseudo-localisation (@System.Globalization.CultureInfo.GetCultureInfo("qps-ploc").NativeName) Translation</dt>
<dl class="credits-list">
<dt>Arabic (@CultureInfo.GetCultureInfo("ar").NativeName) Translation</dt>
<dd>
Ahmed (airportsfan)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/airportsfan">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Bengali (@CultureInfo.GetCultureInfo("bn").NativeName) Translation</dt>
<dd>
Mehedi Hassan&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mehedih_">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Czech (@CultureInfo.GetCultureInfo("cs").NativeName) Translation</dt>
<dd>
David (rezedus)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/rezedus">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>German (@CultureInfo.GetCultureInfo("de").NativeName) Translation</dt>
<dd>
The Dhel&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/The_Dhel">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Christopher&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/evil_pro_">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Greek (@CultureInfo.GetCultureInfo("el").NativeName) Translation</dt>
<dd>Hacker?pcs</dd>
<dd>
Sotiris Michail&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/SnakeOnStick">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Spanish (@CultureInfo.GetCultureInfo("es").NativeName) Translation</dt>
<dd>Nightsteed</dd>
<dd>
Ben Ward&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/_BenW_">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Meober Whagby&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ultimofriki">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Farsi (@CultureInfo.GetCultureInfo("fa").NativeName) Translation</dt>
<dd>
Niloo&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Niloo0937">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Finnish (@CultureInfo.GetCultureInfo("fi").NativeName) Translation</dt>
<dd>
Daniel Gurney (wheatley)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Daniel_Gurney0">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>French (@CultureInfo.GetCultureInfo("fr").NativeName) Translation</dt>
<dd>
CgSYannick&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/YannickTHFR">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Gustave M.&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/gus33000">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Christophe Lavalle&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ChristopheLav">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Croatian (@CultureInfo.GetCultureInfo("hr").NativeName) Translation</dt>
<dd>
Mario Bešen&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mariobesen">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Hebrew (@CultureInfo.GetCultureInfo("he").NativeName) Translation</dt>
<dd>
David Fainshtein&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/david_f">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Indonesian (@CultureInfo.GetCultureInfo("id").NativeName) Translation</dt>
<dd>Andreas</dd>
<dt>Italian (@CultureInfo.GetCultureInfo("it").NativeName) Translation</dt>
<dd>
Meober Whagby&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/ultimofriki">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Simone Nataz&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/djnataz">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Japanese (@CultureInfo.GetCultureInfo("ja").NativeName) Translation</dt>
<dd>
parly&ensp;
<a target="_blank" rel="nofollow noopener" href="https://github.com/parly">
<i class="fa fa-github"></i>
</a>
</dd>
<dt>Korean (@CultureInfo.GetCultureInfo("ko").NativeName) Translation</dt>
<dd>qta3426</dd>
<dd>
SD SkyKlouD&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/_SDSkyKlouD">
<i class="fa fa-twitter"></i>
</a>
</dd>
</dl>
<dl class="credits-list">
<dt>Lithuanian (@CultureInfo.GetCultureInfo("lt").NativeName) Translation</dt>
<dd>
Super User&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Superb_User">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Dutch (@CultureInfo.GetCultureInfo("nl").NativeName) Translation</dt>
<dd>
Nick (ultrawindows)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nickurtnl">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Polish (@CultureInfo.GetCultureInfo("pl").NativeName) Translation</dt>
<dd>
piotrulos&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/piotrulos">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
dzaggiel&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/dzaggiel">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Portuguese (@CultureInfo.GetCultureInfo("pt").NativeName) Translation</dt>
<dd>OBattler</dd>
<dt>Portugese - Brazilian (@CultureInfo.GetCultureInfo("pt-br").NativeName) Translation</dt>
<dd>RichardG</dd>
@*<dt>Pseudo-localisation (@System.Globalization.CultureInfo.GetCultureInfo("qps-ploc").NativeName) Translation</dt>
<dd>Thomas Hounsell, with&ensp;<a target="_blank" rel="nofollow noopener" href="http://www.pseudolocalize.com/"><i class="fa fa-globe"></i> Pseudolocalize!</a></dd>*@
<dt>Romanian (@System.Globalization.CultureInfo.GetCultureInfo("ro").NativeName) Translation</dt>
<dd>ovctvct&ensp;<a target="_blank" rel="nofollow noopener" href="https://www.youtube.com/channel/UC9AC01rKiwDhVPvAsT93rjw"><i class="fa fa-youtube"></i></a></dd>
<dt>Russian (@System.Globalization.CultureInfo.GetCultureInfo("ru").NativeName) Translation</dt>
<dd>Roman (rlinev)&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/rlinev"><i class="fa fa-twitter"></i></a></dd>
<dd>Fuhrer_Adolf&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Fuhrer_Adolf"><i class="fa fa-twitter"></i></a></dd>
<dt>Slovak (@System.Globalization.CultureInfo.GetCultureInfo("sk").NativeName) Translation</dt>
<dd>Lukas&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tfwboredom"><i class="fa fa-twitter"></i></a></dd>
<dt>Slovenian (@System.Globalization.CultureInfo.GetCultureInfo("sl").NativeName) Translation</dt>
<dd>Overdoze</dd>
<dt>Swedish (@System.Globalization.CultureInfo.GetCultureInfo("sv").NativeName) Translation</dt>
<dd>mrpijey&ensp;<a target="_blank" rel="nofollow noopener" href="http://www.mrpijey.net/"><i class="fa fa-globe"></i></a></dd>
<dt>Turkish (@System.Globalization.CultureInfo.GetCultureInfo("tr").NativeName) Translation</dt>
<dd>Furkan AKÇATEPE&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/FurkanAKATEPE"><i class="fa fa-twitter"></i></a></dd>
<dd>Can Taşan</dd>
<dd>Duhan Ömür&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/BilgisyrKurdu16"><i class="fa fa-twitter"></i></a></dd>
<dt>Ukrainian (@System.Globalization.CultureInfo.GetCultureInfo("uk").NativeName) Translation</dt>
<dd>Fuhrer_Adolf&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Fuhrer_Adolf"><i class="fa fa-twitter"></i></a></dd>
<dt>Vietnamese (@System.Globalization.CultureInfo.GetCultureInfo("vi").NativeName) Translation</dt>
<dd>Trần Kim Long Hải&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/trankimlonghai"><i class="fa fa-twitter"></i></a></dd>
<dt>Chinese - Simplified (@System.Globalization.CultureInfo.GetCultureInfo("zh-hans").NativeName) Translation</dt>
<dd>Zheng He&ensp;<a target="_blank" rel="nofollow noopener" href="http://www.betaworld.cn/"><i class="fa fa-globe"></i></a></dd>
<dt>Chinese - Traditional (@System.Globalization.CultureInfo.GetCultureInfo("zh-hant").NativeName) Translation</dt>
<dd>Andrew Huang&ensp;<a target="_blank" rel="nofollow noopener" href="https://twitter.com/AndrewDev8383"><i class="fa fa-twitter"></i></a>&ensp;<a target="_blank" rel="nofollow noopener" href="http://isite.tw/"><i class="fa fa-globe"></i></a></dd>
<dd>GT Wang&ensp;<a target="_blank" rel="nofollow noopener" href="http://mkvq.blogspot.com/"><i class="fa fa-globe"></i></a></dd>
</dl>
</div>
<dt>Romanian (@CultureInfo.GetCultureInfo("ro").NativeName) Translation</dt>
<dd>
ovctvct&ensp;
<a target="_blank" rel="nofollow noopener" href="https://www.youtube.com/channel/UC9AC01rKiwDhVPvAsT93rjw">
<i class="fa fa-youtube"></i>
</a>
</dd>
<dt>Russian (@CultureInfo.GetCultureInfo("ru").NativeName) Translation</dt>
<dd>
Roman (rlinev)&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/rlinev">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>
Fuhrer_Adolf&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Fuhrer_Adolf">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Slovak (@CultureInfo.GetCultureInfo("sk").NativeName) Translation</dt>
<dd>
Lukas&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tfwboredom">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Slovenian (@CultureInfo.GetCultureInfo("sl").NativeName) Translation</dt>
<dd>Overdoze</dd>
<dt>Swedish (@CultureInfo.GetCultureInfo("sv").NativeName) Translation</dt>
<dd>
mrpijey&ensp;
<a target="_blank" rel="nofollow noopener" href="http://www.mrpijey.net/">
<i class="fa fa-globe"></i>
</a>
</dd>
<dt>Turkish (@CultureInfo.GetCultureInfo("tr").NativeName) Translation</dt>
<dd>
Furkan AKÇATEPE&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/FurkanAKATEPE">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dd>Can Taşan</dd>
<dd>
Duhan Ömür&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/BilgisyrKurdu16">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Ukrainian (@CultureInfo.GetCultureInfo("uk").NativeName) Translation</dt>
<dd>
Fuhrer_Adolf&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/Fuhrer_Adolf">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Vietnamese (@CultureInfo.GetCultureInfo("vi").NativeName) Translation</dt>
<dd>
Trần Kim Long Hải&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/trankimlonghai">
<i class="fa fa-twitter"></i>
</a>
</dd>
<dt>Chinese - Simplified (@CultureInfo.GetCultureInfo("zh-hans").NativeName) Translation</dt>
<dd>
Zheng He&ensp;
<a target="_blank" rel="nofollow noopener" href="http://www.betaworld.cn/">
<i class="fa fa-globe"></i>
</a>
</dd>
<dt>Chinese - Traditional (@CultureInfo.GetCultureInfo("zh-hant").NativeName) Translation</dt>
<dd>
Andrew Huang&ensp;
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/AndrewDev8383">
<i class="fa fa-twitter"></i>
</a>&ensp;
<a target="_blank" rel="nofollow noopener" href="http://isite.tw/">
<i class="fa fa-globe"></i>
</a>
</dd>
<dd>
GT Wang&ensp;
<a target="_blank" rel="nofollow noopener" href="http://mkvq.blogspot.com/">
<i class="fa fa-globe"></i>
</a>
</dd>
</dl>
</div>

View File

@ -1,52 +1,52 @@
@{
ViewBag.Title = $"{VariantTerms.Common_RssFeeds} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{VariantTerms.Common_RssFeeds} | {InvariantTerms.SiteName}";
}
<h1>@VariantTerms.Common_RssFeeds</h1>
<ul>
<li>
<a href="@Url.Action("Index", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyCompiled">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyCompiled</a>
</li>
<li>
<a href="@Url.Action("Leaked", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyLeaked">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyLeaked</a>
</li>
<li>
<a href="@Url.Action("Added", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyAdded">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyAdded</a>
</li>
<li>
<a href="@Url.Action("Version", new
{
controller = "Rss"
})" title="@VariantTerms.Support_HighestVersion">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_HighestVersion</a>
</li>
<li>
<a href="#rss-labs" data-toggle="collapse">@VariantTerms.Search_Lab</a>
<ul id="rss-labs" class="collapse">
@foreach (string lab in ViewBag.Labs)
{
<li>
<a href="@Url.Action("Lab", new
{
controller = "Rss",
lab
})" title="@lab">
<i class="fa fa-sm fa-rss"></i> @lab</a>
</li>
}
</ul>
</li>
<li>
<a href="@Url.Action("Index", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyCompiled">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyCompiled</a>
</li>
<li>
<a href="@Url.Action("Leaked", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyLeaked">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyLeaked</a>
</li>
<li>
<a href="@Url.Action("Added", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyAdded">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyAdded</a>
</li>
<li>
<a href="@Url.Action("Version", new
{
controller = "Rss"
})" title="@VariantTerms.Support_HighestVersion">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_HighestVersion</a>
</li>
<li>
<a href="#rss-labs" data-toggle="collapse">@VariantTerms.Search_Lab</a>
<ul id="rss-labs" class="collapse">
@foreach (string lab in ViewBag.Labs)
{
<li>
<a href="@Url.Action("Lab", new
{
controller = "Rss",
lab
})" title="@lab">
<i class="fa fa-sm fa-rss"></i> @lab</a>
</li>
}
</ul>
</li>
</ul>

View File

@ -1,130 +1,130 @@
@using BuildFeed.Controllers
@using BuildFeed.Model.View
@model BuildFeed.Model.View.SitemapData
@model SitemapData
@{
ViewBag.Title = $"{VariantTerms.Common_Sitemap} | {InvariantTerms.SiteName}";
ViewBag.Title = $"{VariantTerms.Common_Sitemap} | {InvariantTerms.SiteName}";
}
<h1>@VariantTerms.Common_Sitemap</h1>
<ul>
<li>
@Html.ActionLink("BuildFeed", nameof(FrontController.Index), "Front")
<ul>
<li>
<a href="#sitemap-builds">Builds</a>
<ul id="sitemap-builds">
@foreach (SitemapDataBuildGroup buildGroup in Model.Builds)
{
<li>
@Html.ActionLink(buildGroup.Id.ToString(), "ViewGroup", new
{
controller = "Front",
major = buildGroup.Id.Major,
minor = buildGroup.Id.Minor,
number = buildGroup.Id.Build,
revision = buildGroup.Id.Revision
})
<ul>
@foreach (SitemapDataBuild build in buildGroup.Builds)
{
<li>
@Html.ActionLink(build.Name, "ViewBuild", new
{
controller = "Front",
id = build.Id
})</li>
}
</ul>
</li>
}
</ul>
</li>
@foreach (KeyValuePair<string, SitemapPagedAction[]> item in Model.Actions)
{
<li>
@Html.ActionLink("BuildFeed", nameof(FrontController.Index), "Front")
<ul>
<li>
<a href="#sitemap-@item.Key.ToLower()">@item.Key</a>
<ul id="sitemap-@item.Key.ToLower()">
@foreach (SitemapPagedAction action in item.Value)
{
if (string.IsNullOrEmpty(action.Name))
{
<li>@Html.ActionLink("Page 1", action.Action, action.UrlParams)</li>
for (int i = 2; i <= action.Pages; i++)
{
RouteValueDictionary urlParams = action.UrlParams;
urlParams["page"] = i;
<li>@Html.ActionLink($"Page {i}", action.Action + "Page", urlParams)</li>
}
}
else
{
<a href="#sitemap-builds">Builds</a>
<ul id="sitemap-builds">
@foreach (SitemapDataBuildGroup buildGroup in Model.Builds)
{
<li>
<a href="#sitemap-@action.UniqueId">@action.Name</a>
<ul id="sitemap-@action.UniqueId">
<li>@Html.ActionLink("Page 1", action.Action, action.UrlParams)</li>
@for (int i = 2; i <= action.Pages; i++)
{
RouteValueDictionary urlParams = action.UrlParams;
urlParams["page"] = i;
<li>@Html.ActionLink($"Page {i}", action.Action + "Page", urlParams)</li>
}
</ul>
@Html.ActionLink(buildGroup.Id.ToString(), "ViewGroup", new
{
controller = "Front",
major = buildGroup.Id.Major,
minor = buildGroup.Id.Minor,
number = buildGroup.Id.Build,
revision = buildGroup.Id.Revision
})
<ul>
@foreach (SitemapDataBuild build in buildGroup.Builds)
{
<li>
@Html.ActionLink(build.Name, "ViewBuild", new
{
controller = "Front",
id = build.Id
})</li>
}
</ul>
</li>
}
}
</ul>
}
</ul>
</li>
}
<li>
<a href="#sitemap-rss">@VariantTerms.Common_RssFeeds</a>
<ul id="sitemap-rss">
<li>
<a href="@Url.Action("Index", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyCompiled">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyCompiled</a>
</li>
<li>
<a href="@Url.Action("Leaked", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyLeaked">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyLeaked</a>
</li>
<li>
<a href="@Url.Action("Added", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyAdded">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyAdded</a>
</li>
<li>
<a href="@Url.Action("Version", new
{
controller = "Rss"
})" title="@VariantTerms.Support_HighestVersion">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_HighestVersion</a>
</li>
<li>
<a href="#rss-labs">@VariantTerms.Model_LabString</a>
<ul id="rss-labs">
@foreach (string lab in Model.Labs)
{
<li>
<a href="@Url.Action("Lab", new
{
controller = "Rss",
lab
})" title="@lab">
<i class="fa fa-sm fa-rss"></i> @lab</a>
</li>
}
</ul>
</li>
</ul>
</li>
</ul>
</li>
@foreach (var item in Model.Actions)
{
<li>
<a href="#sitemap-@item.Key.ToLower()">@item.Key</a>
<ul id="sitemap-@item.Key.ToLower()">
@foreach (SitemapPagedAction action in item.Value)
{
if (string.IsNullOrEmpty(action.Name))
{
<li>@Html.ActionLink("Page 1", action.Action, action.UrlParams)</li>
for (int i = 2; i <= action.Pages; i++)
{
RouteValueDictionary urlParams = action.UrlParams;
urlParams["page"] = i;
<li>@Html.ActionLink($"Page {i}", action.Action + "Page", urlParams)</li>
}
}
else
{
<li>
<a href="#sitemap-@action.UniqueId">@action.Name</a>
<ul id="sitemap-@action.UniqueId">
<li>@Html.ActionLink("Page 1", action.Action, action.UrlParams)</li>
@for (int i = 2; i <= action.Pages; i++)
{
RouteValueDictionary urlParams = action.UrlParams;
urlParams["page"] = i;
<li>@Html.ActionLink($"Page {i}", action.Action + "Page", urlParams)</li>
}
</ul>
</li>
}
}
</ul>
</li>
}
<li>
<a href="#sitemap-rss">@VariantTerms.Common_RssFeeds</a>
<ul id="sitemap-rss">
<li>
<a href="@Url.Action("Index", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyCompiled">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyCompiled</a>
</li>
<li>
<a href="@Url.Action("Leaked", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyLeaked">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyLeaked</a>
</li>
<li>
<a href="@Url.Action("Added", new
{
controller = "Rss"
})" title="@VariantTerms.Support_RecentlyAdded">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_RecentlyAdded</a>
</li>
<li>
<a href="@Url.Action("Version", new
{
controller = "Rss"
})" title="@VariantTerms.Support_HighestVersion">
<i class="fa fa-sm fa-rss"></i> @VariantTerms.Support_HighestVersion</a>
</li>
<li>
<a href="#rss-labs">@VariantTerms.Model_LabString</a>
<ul id="rss-labs">
@foreach (string lab in Model.Labs)
{
<li>
<a href="@Url.Action("Lab", new
{
controller = "Rss",
lab
})" title="@lab">
<i class="fa fa-sm fa-rss"></i> @lab</a>
</li>
}
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
</system.web>
<system.webServer>
</system.webServer>
<system.web>
</system.web>
<system.webServer>
</system.webServer>
</configuration>

View File

@ -1,28 +1,28 @@
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<customErrors mode="On" xdt:Transform="Insert" />
<compilation xdt:Transform="RemoveAttributes(debug)" />
<trace enabled="false" requestLimit="40" pageOutput="false" xdt:Transform="Replace" />
</system.web>
<system.webServer>
<rewrite>
<rules>
<rule name="CanonicalHost" stopProcessing="true" xdt:Transform="Insert">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^buildfeed\.net$" negate="true" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://buildfeed.net/{R:1}" />
</rule>
</rules>
</rewrite>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000" xdt:Transform="Insert" />
</customHeaders>
</httpProtocol>
</system.webServer>
<system.web>
<customErrors mode="On" xdt:Transform="Insert" />
<compilation xdt:Transform="RemoveAttributes(debug)" />
<trace enabled="false" requestLimit="40" pageOutput="false" xdt:Transform="Replace" />
</system.web>
<system.webServer>
<rewrite>
<rules>
<rule name="CanonicalHost" stopProcessing="true" xdt:Transform="Insert">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^buildfeed\.net$" negate="true" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://buildfeed.net/{R:1}" />
</rule>
</rules>
</rewrite>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000" xdt:Transform="Insert" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>

View File

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="res/ico/tiny.png" />
<square150x150logo src="res/ico/square.png" />
<wide310x150logo src="res/ico/wide.png" />
<square310x310logo src="res/ico/large.png" />
<TileColor>#2E3440</TileColor>
</tile>
<notification>
<polling-uri src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=1" />
<polling-uri2 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=2" />
<polling-uri3 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=3" />
<polling-uri4 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=4" />
<polling-uri5 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=5" />
<frequency>30</frequency>
<cycle>1</cycle>
</notification>
</msapplication>
<msapplication>
<tile>
<square70x70logo src="res/ico/tiny.png" />
<square150x150logo src="res/ico/square.png" />
<wide310x150logo src="res/ico/wide.png" />
<square310x310logo src="res/ico/large.png" />
<TileColor>#2E3440</TileColor>
</tile>
<notification>
<polling-uri src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=1" />
<polling-uri2 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=2" />
<polling-uri3 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=3" />
<polling-uri4 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=4" />
<polling-uri5 src="http://notifications.buildmypinnedsite.com/?feed=https://buildfeed.net/rss/Added/&amp;id=5" />
<frequency>30</frequency>
<cycle>1</cycle>
</notification>
</msapplication>
</browserconfig>

View File

@ -8,38 +8,38 @@ var uglify = require("gulp-uglify-es").default;
var autoprefixer = require("gulp-autoprefixer");
gulp.task("sass-compile",
function()
{
gulp.src("./res/css/*.scss")
.pipe(sourceMaps.init())
.pipe(sass())
.pipe(autoprefixer({
browsers: ["> 1%", "IE 10-11", "last 5 versions"],
cascade: false
}))
.pipe(cleanCss())
.pipe(sourceMaps.write("./"))
.pipe(gulp.dest("./res/css/"));
});
function()
{
gulp.src("./res/css/*.scss")
.pipe(sourceMaps.init())
.pipe(sass())
.pipe(autoprefixer({
browsers: ["> 1%", "IE 10-11", "last 5 versions"],
cascade: false
}))
.pipe(cleanCss())
.pipe(sourceMaps.write("./"))
.pipe(gulp.dest("./res/css/"));
});
gulp.task("typescript",
function()
{
return gulp.src("./res/ts/*.ts")
.pipe(sourceMaps.init())
.pipe(ts({
target: "es6",
sourceMap: false
}))
.js
.pipe(uglify())
.pipe(sourceMaps.write("./"))
.pipe(gulp.dest("./res/ts/"));
});
function()
{
return gulp.src("./res/ts/*.ts")
.pipe(sourceMaps.init())
.pipe(ts({
target: "es6",
sourceMap: false
}))
.js
.pipe(uglify())
.pipe(sourceMaps.write("./"))
.pipe(gulp.dest("./res/ts/"));
});
gulp.task("watch-sass",
function()
{
gulp.watch("./res/css/**.scss", ["sass-compile"]);
gulp.watch("./res/ts/*.ts", ["typescript"]);
});
function()
{
gulp.watch("./res/css/**.scss", ["sass-compile"]);
gulp.watch("./res/ts/*.ts", ["typescript"]);
});

View File

@ -46,9 +46,7 @@
<package id="Humanizer.Core.zh-CN" version="2.2.0" targetFramework="net47" />
<package id="Humanizer.Core.zh-Hans" version="2.2.0" targetFramework="net47" />
<package id="Humanizer.Core.zh-Hant" version="2.2.0" targetFramework="net47" />
<package id="jQuery" version="3.3.1" targetFramework="net47" />
<package id="jquery.TypeScript.DefinitelyTyped" version="3.1.2" targetFramework="net47" />
<package id="jQuery.Validation" version="1.17.0" targetFramework="net47" />
<package id="jsrender.TypeScript.DefinitelyTyped" version="0.1.8" targetFramework="net47" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net47" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net47" />
@ -59,7 +57,6 @@
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net47" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net47" />
<package id="Microsoft.CSharp" version="4.4.1" targetFramework="net47" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net47" />
<package id="Microsoft.Net.Compilers" version="2.6.1" targetFramework="net47" developmentDependency="true" />
<package id="Microsoft.NETCore.Platforms" version="2.0.1" targetFramework="net47" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net47" />

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
</system.webServer>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
</system.webServer>
</configuration>

View File

@ -11,4 +11,4 @@ $strong-blue: #4076B5;
@mixin standard-box-shadow($color)
{
box-shadow: 0 0 10px 0 rgba($color, 0.33);
}
}

View File

@ -1 +1 @@
{"version":3,"sources":["rtl.scss"],"names":[],"mappings":"AAAA,2CAEG,WAAA,KAFH,gDAMM,WAAA,MAIN,gCAEG,WAAA,MAGH,kBAIM,WAAA,KAJN,kBASM,aAAA,EACA,YAAA,IAIN,6DAKM,WAAA,KALN,8DAUM,WAAA,MAIN,yBAEG,8DAIM,WAAA,OAJN,6DASM,WAAA","file":"rtl.css","sourcesContent":["nav#page-navigation #page-navigation-links\r\n{\r\n text-align: left;\r\n\r\n > li > a\r\n {\r\n text-align: right;\r\n }\r\n}\r\n\r\n.dropdown-parent .dropdown-menu\r\n{\r\n text-align: right;\r\n}\r\n\r\n.form-group\r\n{\r\n label\r\n {\r\n text-align: left;\r\n }\r\n\r\n > label\r\n {\r\n margin-right: 0;\r\n margin-left: 1em;\r\n }\r\n}\r\n\r\nfooter#page-footer .footer-flex .footer-flex-item\r\n{\r\n\r\n &:last-child\r\n {\r\n text-align: left;\r\n }\r\n\r\n &:first-child\r\n {\r\n text-align: right;\r\n }\r\n}\r\n\r\n@media (max-width: 640px)\r\n{\r\n footer#page-footer .footer-flex .footer-flex-item\r\n {\r\n &:first-child\r\n {\r\n text-align: center;\r\n }\r\n\r\n &:last-child\r\n {\r\n text-align: center;\r\n }\r\n }\r\n}\r\n"]}
{"version":3,"sources":["rtl.scss"],"names":[],"mappings":"AAAA,2CAEI,WAAA,KAFJ,gDAMQ,WAAA,MAIR,gCAEI,WAAA,MAGJ,kBAIQ,WAAA,KAJR,kBASQ,aAAA,EACA,YAAA,IAIR,6DAKQ,WAAA,KALR,8DAUQ,WAAA,MAIR,yBAEI,8DAIQ,WAAA,OAJR,6DASQ,WAAA","file":"rtl.css","sourcesContent":["nav#page-navigation #page-navigation-links\r\n{\r\n text-align: left;\r\n\r\n > li > a\r\n {\r\n text-align: right;\r\n }\r\n}\r\n\r\n.dropdown-parent .dropdown-menu\r\n{\r\n text-align: right;\r\n}\r\n\r\n.form-group\r\n{\r\n label\r\n {\r\n text-align: left;\r\n }\r\n\r\n > label\r\n {\r\n margin-right: 0;\r\n margin-left: 1em;\r\n }\r\n}\r\n\r\nfooter#page-footer .footer-flex .footer-flex-item\r\n{\r\n\r\n &:last-child\r\n {\r\n text-align: left;\r\n }\r\n\r\n &:first-child\r\n {\r\n text-align: right;\r\n }\r\n}\r\n\r\n@media (max-width: 640px)\r\n{\r\n footer#page-footer .footer-flex .footer-flex-item\r\n {\r\n &:first-child\r\n {\r\n text-align: center;\r\n }\r\n\r\n &:last-child\r\n {\r\n text-align: center;\r\n }\r\n }\r\n}\r\n"]}

View File

@ -1,58 +1,58 @@
nav#page-navigation #page-navigation-links
{
text-align: left;
text-align: left;
> li > a
{
text-align: right;
}
> li > a
{
text-align: right;
}
}
.dropdown-parent .dropdown-menu
{
text-align: right;
text-align: right;
}
.form-group
{
label
{
text-align: left;
}
label
{
text-align: left;
}
> label
{
margin-right: 0;
margin-left: 1em;
}
> label
{
margin-right: 0;
margin-left: 1em;
}
}
footer#page-footer .footer-flex .footer-flex-item
{
&:last-child
{
text-align: left;
}
&:last-child
{
text-align: left;
}
&:first-child
{
text-align: right;
}
&:first-child
{
text-align: right;
}
}
@media (max-width: 640px)
{
footer#page-footer .footer-flex .footer-flex-item
{
&:first-child
{
text-align: center;
}
footer#page-footer .footer-flex .footer-flex-item
{
&:first-child
{
text-align: center;
}
&:last-child
{
text-align: center;
}
}
&:last-child
{
text-align: center;
}
}
}

View File

@ -1,2 +1,2 @@
@import "dark.scss";
@import "inc/_christmas.scss";
@import "inc/_christmas.scss";

File diff suppressed because one or more lines are too long

View File

@ -4,195 +4,196 @@
module BuildFeed
{
let ajax: XMLHttpRequest;
let timeout: number;
let ajax: XMLHttpRequest;
let timeout: number;
export function MobileMenuToggle(ev: MouseEvent)
{
ev.preventDefault();
export function MobileMenuToggle(ev: MouseEvent)
{
ev.preventDefault();
const button = this as HTMLButtonElement;
button.nextElementSibling.classList.toggle("open");
}
const button = this as HTMLButtonElement;
button.nextElementSibling.classList.toggle("open");
}
export function DropdownClick(ev: MouseEvent)
{
ev.preventDefault();
export function DropdownClick(ev: MouseEvent)
{
ev.preventDefault();
const link = this as HTMLAnchorElement;
const alreadyOpen = link.parentElement.classList.contains("open");
const link = this as HTMLAnchorElement;
const alreadyOpen = link.parentElement.classList.contains("open");
CloseDropdowns(ev);
CloseDropdowns(ev);
if (!alreadyOpen)
{
link.parentElement.classList.toggle("open");
if (!alreadyOpen)
{
link.parentElement.classList.toggle("open");
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.classList.add("open");
}
}
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.classList.add("open");
}
}
export function CloseDropdowns(ev: MouseEvent)
{
ev.preventDefault();
export function CloseDropdowns(ev: MouseEvent)
{
ev.preventDefault();
const ddParents = document.getElementsByClassName("dropdown-parent");
for (let i = 0; i < ddParents.length; i++)
{
ddParents[i].classList.remove("open");
}
const ddParents = document.getElementsByClassName("dropdown-parent");
for (let i = 0; i < ddParents.length; i++)
{
ddParents[i].classList.remove("open");
}
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.classList.remove("open");
}
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.classList.remove("open");
}
export function SwitchTheme(ev: MouseEvent)
{
ev.preventDefault();
export function SwitchTheme(ev: MouseEvent)
{
ev.preventDefault();
const link = this as HTMLAnchorElement;
document.cookie = `bf_theme=${link.dataset["theme"]}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`;
location.reload(true);
}
const link = this as HTMLAnchorElement;
document.cookie = `bf_theme=${link.dataset["theme"]}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`;
location.reload(true);
}
export function SwitchLanguage(ev: MouseEvent)
{
ev.preventDefault();
export function SwitchLanguage(ev: MouseEvent)
{
ev.preventDefault();
const link = this as HTMLAnchorElement;
document.cookie = `bf_lang=${link.dataset["lang"]}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`;
location.reload(true);
}
const link = this as HTMLAnchorElement;
document.cookie = `bf_lang=${link.dataset["lang"]}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`;
location.reload(true);
}
export function OpenSearch(ev: MouseEvent)
{
ev.preventDefault();
export function OpenSearch(ev: MouseEvent)
{
ev.preventDefault();
const modal = document.getElementById("modal-search-overlay") as HTMLDivElement;
modal.classList.add("open");
}
const modal = document.getElementById("modal-search-overlay") as HTMLDivElement;
modal.classList.add("open");
}
export function CloseSearch(ev: MouseEvent)
{
ev.preventDefault();
export function CloseSearch(ev: MouseEvent)
{
ev.preventDefault();
const modal = document.getElementById("modal-search-overlay") as HTMLDivElement;
modal.classList.remove("open");
}
const modal = document.getElementById("modal-search-overlay") as HTMLDivElement;
modal.classList.remove("open");
}
export function StopClick(ev: MouseEvent)
{
ev.preventDefault();
ev.stopPropagation();
}
export function StopClick(ev: MouseEvent)
{
ev.preventDefault();
ev.stopPropagation();
}
export function InitiateSearch(ev: KeyboardEvent)
{
const resultPane = document.getElementById("modal-search-result") as HTMLDivElement;
resultPane.innerHTML = "";
export function InitiateSearch(ev: KeyboardEvent)
{
const resultPane = document.getElementById("modal-search-result") as HTMLDivElement;
resultPane.innerHTML = "";
if (typeof (timeout) !== "undefined")
{
clearTimeout(timeout);
}
if (typeof (timeout) !== "undefined")
{
clearTimeout(timeout);
}
if (typeof (ajax) !== "undefined" && ajax.readyState !== XMLHttpRequest.DONE)
{
ajax.abort();
}
if (typeof (ajax) !== "undefined" && ajax.readyState !== XMLHttpRequest.DONE)
{
ajax.abort();
}
timeout = setInterval(SendSearch, 200);
}
timeout = setInterval(SendSearch, 200);
}
export function SendSearch()
{
if (typeof (timeout) !== "undefined")
{
clearTimeout(timeout);
}
export function SendSearch()
{
if (typeof (timeout) !== "undefined")
{
clearTimeout(timeout);
}
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
ajax = new XMLHttpRequest();
ajax.onreadystatechange = CompleteSearch;
ajax.open("GET", `/api/GetSearchResult/${modalInput.value}/`, true);
ajax.setRequestHeader("accept", "application/json");
ajax.send(null);
}
ajax = new XMLHttpRequest();
ajax.onreadystatechange = CompleteSearch;
ajax.open("GET", `/api/GetSearchResult/${modalInput.value}/`, true);
ajax.setRequestHeader("accept", "application/json");
ajax.send(null);
}
export function CompleteSearch(ev: ProgressEvent)
{
if (ajax.readyState !== XMLHttpRequest.DONE || ajax.status !== 200)
{
return;
}
export function CompleteSearch(ev: ProgressEvent)
{
if (ajax.readyState !== XMLHttpRequest.DONE || ajax.status !== 200)
{
return;
}
const resultPane = document.getElementById("modal-search-result") as HTMLDivElement;
const templateContent = document.getElementById("result-template") as HTMLDivElement;
const template = jsrender.templates(templateContent.innerHTML);
const content = template.render(JSON.parse(ajax.responseText));
resultPane.innerHTML = content;
const resultPane = document.getElementById("modal-search-result") as HTMLDivElement;
const templateContent = document.getElementById("result-template") as HTMLDivElement;
const template = jsrender.templates(templateContent.innerHTML);
const content = template.render(JSON.parse(ajax.responseText));
resultPane.innerHTML = content;
const resultLinks = resultPane.getElementsByTagName("a");
for (let i = 0; i < resultLinks.length; i++)
{
resultLinks[i].addEventListener("click", (mev: MouseEvent) =>
{
mev.preventDefault();
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
ga("send", "pageview", `/api/GetSearchResult/${modalInput.value}/`);
location.assign((mev.currentTarget as HTMLAnchorElement).href);
});
}
}
const resultLinks = resultPane.getElementsByTagName("a");
for (let i = 0; i < resultLinks.length; i++)
{
resultLinks[i].addEventListener("click",
(mev: MouseEvent) =>
{
mev.preventDefault();
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
ga("send", "pageview", `/api/GetSearchResult/${modalInput.value}/`);
location.assign((mev.currentTarget as HTMLAnchorElement).href);
});
}
}
export function BuildFeedSetup(ev: Event)
{
const ddParents = document.getElementsByClassName("dropdown-parent");
for (let i = 0; i < ddParents.length; i++)
{
for (let j = 0; j < ddParents[i].childNodes.length; j++)
{
const el = ddParents[i].childNodes[j];
if (el.nodeName === "A")
export function BuildFeedSetup(ev: Event)
{
const ddParents = document.getElementsByClassName("dropdown-parent");
for (let i = 0; i < ddParents.length; i++)
{
for (let j = 0; j < ddParents[i].childNodes.length; j++)
{
el.addEventListener("click", DropdownClick);
const el = ddParents[i].childNodes[j];
if (el.nodeName === "A")
{
el.addEventListener("click", DropdownClick);
}
}
}
}
}
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.addEventListener("click", CloseDropdowns);
const menuClickCapture = document.getElementById("menu-open-overlay") as HTMLDivElement;
menuClickCapture.addEventListener("click", CloseDropdowns);
const ddThemes = document.getElementById("settings-theme-menu").getElementsByTagName("a");
for (let i = 0; i < ddThemes.length; i++)
{
ddThemes[i].addEventListener("click", SwitchTheme);
}
const ddThemes = document.getElementById("settings-theme-menu").getElementsByTagName("a");
for (let i = 0; i < ddThemes.length; i++)
{
ddThemes[i].addEventListener("click", SwitchTheme);
}
const ddLangs = document.getElementById("settings-lang-menu").getElementsByTagName("a");
for (let i = 0; i < ddLangs.length; i++)
{
ddLangs[i].addEventListener("click", SwitchLanguage);
}
const ddLangs = document.getElementById("settings-lang-menu").getElementsByTagName("a");
for (let i = 0; i < ddLangs.length; i++)
{
ddLangs[i].addEventListener("click", SwitchLanguage);
}
const btnNav = document.getElementById("page-navigation-toggle");
btnNav.addEventListener("click", MobileMenuToggle);
const btnNav = document.getElementById("page-navigation-toggle");
btnNav.addEventListener("click", MobileMenuToggle);
const btnSearch = document.getElementById("page-navigation-search");
btnSearch.addEventListener("click", OpenSearch);
const btnSearch = document.getElementById("page-navigation-search");
btnSearch.addEventListener("click", OpenSearch);
const modalOverlay = document.getElementById("modal-search-overlay") as HTMLDivElement;
modalOverlay.addEventListener("click", CloseSearch);
const modalOverlay = document.getElementById("modal-search-overlay") as HTMLDivElement;
modalOverlay.addEventListener("click", CloseSearch);
const modalDialog = document.getElementById("modal-search") as HTMLDivElement;
modalDialog.addEventListener("click", StopClick);
const modalDialog = document.getElementById("modal-search") as HTMLDivElement;
modalDialog.addEventListener("click", StopClick);
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
modalInput.addEventListener("keyup", InitiateSearch);
}
const modalInput = document.getElementById("modal-search-input") as HTMLInputElement;
modalInput.addEventListener("keyup", InitiateSearch);
}
}
window.addEventListener("load", BuildFeed.BuildFeedSetup);