Add authentication support (#185)
This commit is contained in:
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/.DS_Store
vendored
Binary file not shown.
BIN
gaseous-server/Assets/.DS_Store
vendored
BIN
gaseous-server/Assets/.DS_Store
vendored
Binary file not shown.
BIN
gaseous-server/Assets/Ratings/.DS_Store
vendored
BIN
gaseous-server/Assets/Ratings/.DS_Store
vendored
Binary file not shown.
16
gaseous-server/Classes/Auth/Classes/IdentityRole.cs
Normal file
16
gaseous-server/Classes/Auth/Classes/IdentityRole.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that implements the ASP.NET Identity
|
||||
/// IRole interface
|
||||
/// </summary>
|
||||
public class ApplicationRole : IdentityRole
|
||||
{
|
||||
}
|
||||
}
|
15
gaseous-server/Classes/Auth/Classes/IdentityUser.cs
Normal file
15
gaseous-server/Classes/Auth/Classes/IdentityUser.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that implements the ASP.NET Identity
|
||||
/// IUser interface
|
||||
/// </summary>
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
}
|
||||
}
|
171
gaseous-server/Classes/Auth/Classes/RoleStore.cs
Normal file
171
gaseous-server/Classes/Auth/Classes/RoleStore.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that implements the key ASP.NET Identity role store iterfaces
|
||||
/// </summary>
|
||||
public class RoleStore : IQueryableRoleStore<ApplicationRole>
|
||||
{
|
||||
private RoleTable roleTable;
|
||||
public Database Database { get; private set; }
|
||||
|
||||
public IQueryable<ApplicationRole> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ApplicationRole> roles = roleTable.GetRoles();
|
||||
return roles.AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
public RoleStore()
|
||||
{
|
||||
Database = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
roleTable = new RoleTable(Database);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase as argument
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public RoleStore(Database database)
|
||||
{
|
||||
Database = database;
|
||||
roleTable = new RoleTable(database);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> CreateAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
|
||||
roleTable.Insert(role);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
roleTable.Delete(role.Id);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<ApplicationRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
|
||||
{
|
||||
ApplicationRole result = roleTable.GetRoleById(roleId) as ApplicationRole;
|
||||
|
||||
return Task.FromResult<ApplicationRole>(result);
|
||||
}
|
||||
|
||||
public Task<bool> RoleExistsAsync(string roleId, CancellationToken cancellationToken)
|
||||
{
|
||||
ApplicationRole? result = roleTable.GetRoleById(roleId) as ApplicationRole;
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return Task.FromResult<bool>(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult<bool>(true);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApplicationRole?> FindByNameAsync(string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
ApplicationRole? result = roleTable.GetRoleByName(roleName) as ApplicationRole;
|
||||
|
||||
return Task.FromResult<ApplicationRole?>(result);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
roleTable.Update(role);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Database != null)
|
||||
{
|
||||
Database = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<string> GetRoleIdAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role != null)
|
||||
{
|
||||
return Task.FromResult<string>(roleTable.GetRoleId(role.Name));
|
||||
}
|
||||
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetRoleNameAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role != null)
|
||||
{
|
||||
return Task.FromResult<string?>(roleTable.GetRoleName(role.Id));
|
||||
}
|
||||
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
|
||||
public Task SetRoleNameAsync(ApplicationRole role, string? roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
|
||||
role.Name = roleName;
|
||||
roleTable.Update(role);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<string?> GetNormalizedRoleNameAsync(ApplicationRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role != null)
|
||||
{
|
||||
return Task.FromResult<string?>(roleTable.GetRoleName(role.Id));
|
||||
}
|
||||
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
|
||||
public Task SetNormalizedRoleNameAsync(ApplicationRole role, string? normalizedName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
|
||||
role.Name = normalizedName;
|
||||
roleTable.Update(role);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
}
|
||||
}
|
168
gaseous-server/Classes/Auth/Classes/RoleTable.cs
Normal file
168
gaseous-server/Classes/Auth/Classes/RoleTable.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents the Role table in the MySQL Database
|
||||
/// </summary>
|
||||
public class RoleTable
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase instance
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public RoleTable(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deltes a role from the Roles table
|
||||
/// </summary>
|
||||
/// <param name="roleId">The role Id</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(string roleId)
|
||||
{
|
||||
string commandText = "Delete from Roles where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@id", roleId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new Role in the Roles table
|
||||
/// </summary>
|
||||
/// <param name="roleName">The role's name</param>
|
||||
/// <returns></returns>
|
||||
public int Insert(ApplicationRole role)
|
||||
{
|
||||
string commandText = "Insert into Roles (Id, Name) values (@id, @name)";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@name", role.Name);
|
||||
parameters.Add("@id", role.Id);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a role name given the roleId
|
||||
/// </summary>
|
||||
/// <param name="roleId">The role Id</param>
|
||||
/// <returns>Role name</returns>
|
||||
public string? GetRoleName(string roleId)
|
||||
{
|
||||
string commandText = "Select Name from Roles where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@id", roleId);
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the role Id given a role name
|
||||
/// </summary>
|
||||
/// <param name="roleName">Role's name</param>
|
||||
/// <returns>Role's Id</returns>
|
||||
public string? GetRoleId(string roleName)
|
||||
{
|
||||
string? roleId = null;
|
||||
string commandText = "Select Id from Roles where Name = @name";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", roleName } };
|
||||
|
||||
DataTable result = _database.ExecuteCMD(commandText, parameters);
|
||||
if (result.Rows.Count > 0)
|
||||
{
|
||||
return Convert.ToString(result.Rows[0][0]);
|
||||
}
|
||||
|
||||
return roleId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ApplicationRole given the role Id
|
||||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
public ApplicationRole? GetRoleById(string roleId)
|
||||
{
|
||||
var roleName = GetRoleName(roleId);
|
||||
ApplicationRole? role = null;
|
||||
|
||||
if(roleName != null)
|
||||
{
|
||||
role = new ApplicationRole();
|
||||
role.Id = roleId;
|
||||
role.Name = roleName;
|
||||
role.NormalizedName = roleName.ToUpper();
|
||||
}
|
||||
|
||||
return role;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ApplicationRole given the role name
|
||||
/// </summary>
|
||||
/// <param name="roleName"></param>
|
||||
/// <returns></returns>
|
||||
public ApplicationRole? GetRoleByName(string roleName)
|
||||
{
|
||||
var roleId = GetRoleId(roleName);
|
||||
ApplicationRole role = null;
|
||||
|
||||
if (roleId != null)
|
||||
{
|
||||
role = new ApplicationRole();
|
||||
role.Id = roleId;
|
||||
role.Name = roleName;
|
||||
role.NormalizedName = roleName.ToUpper();
|
||||
}
|
||||
|
||||
return role;
|
||||
}
|
||||
|
||||
public int Update(ApplicationRole role)
|
||||
{
|
||||
string commandText = "Update Roles set Name = @name where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@id", role.Id);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
public List<ApplicationRole> GetRoles()
|
||||
{
|
||||
List<ApplicationRole> roles = new List<ApplicationRole>();
|
||||
|
||||
string commandText = "Select Name from Roles";
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
{
|
||||
ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
|
||||
role.Id = (string)row["Id"];
|
||||
role.Name = (string)row["Name"];
|
||||
role.NormalizedName = ((string)row["Name"]).ToUpper();
|
||||
roles.Add(role);
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
}
|
95
gaseous-server/Classes/Auth/Classes/UserClaimsTable.cs
Normal file
95
gaseous-server/Classes/Auth/Classes/UserClaimsTable.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Security.Claims;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents the UserClaims table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserClaimsTable
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase instance
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public UserClaimsTable(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a ClaimsIdentity instance given a userId
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public ClaimsIdentity FindByUserId(string userId)
|
||||
{
|
||||
ClaimsIdentity claims = new ClaimsIdentity();
|
||||
string commandText = "Select * from UserClaims where UserId = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@UserId", userId } };
|
||||
|
||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||
foreach (DataRow row in rows)
|
||||
{
|
||||
Claim claim = new Claim((string)row["ClaimType"], (string)row["ClaimValue"]);
|
||||
claims.AddClaim(claim);
|
||||
}
|
||||
|
||||
return claims;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all claims from a user given a userId
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from UserClaims where UserId = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("userId", userId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new claim in UserClaims table
|
||||
/// </summary>
|
||||
/// <param name="userClaim">User's claim to be added</param>
|
||||
/// <param name="userId">User's id</param>
|
||||
/// <returns></returns>
|
||||
public int Insert(Claim userClaim, string userId)
|
||||
{
|
||||
string commandText = "Insert into UserClaims (ClaimValue, ClaimType, UserId) values (@value, @type, @userId)";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("value", userClaim.Value);
|
||||
parameters.Add("type", userClaim.Type);
|
||||
parameters.Add("userId", userId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a claim from a user
|
||||
/// </summary>
|
||||
/// <param name="user">The user to have a claim deleted</param>
|
||||
/// <param name="claim">A claim to be deleted from user</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(IdentityUser user, Claim claim)
|
||||
{
|
||||
string commandText = "Delete from UserClaims where UserId = @userId and @ClaimValue = @value and ClaimType = @type";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("userId", user.Id);
|
||||
parameters.Add("value", claim.Value);
|
||||
parameters.Add("type", claim.Type);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
}
|
||||
}
|
117
gaseous-server/Classes/Auth/Classes/UserLoginsTable.cs
Normal file
117
gaseous-server/Classes/Auth/Classes/UserLoginsTable.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents the UserLogins table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserLoginsTable
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase instance
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public UserLoginsTable(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a login from a user in the UserLogins table
|
||||
/// </summary>
|
||||
/// <param name="user">User to have login deleted</param>
|
||||
/// <param name="login">Login to be deleted from user</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(IdentityUser user, UserLoginInfo login)
|
||||
{
|
||||
string commandText = "Delete from UserLogins where UserId = @userId and LoginProvider = @loginProvider and ProviderKey = @providerKey";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("UserId", user.Id);
|
||||
parameters.Add("loginProvider", login.LoginProvider);
|
||||
parameters.Add("providerKey", login.ProviderKey);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all Logins from a user in the UserLogins table
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from UserLogins where UserId = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("UserId", userId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new login in the UserLogins table
|
||||
/// </summary>
|
||||
/// <param name="user">User to have new login added</param>
|
||||
/// <param name="login">Login to be added</param>
|
||||
/// <returns></returns>
|
||||
public int Insert(IdentityUser user, UserLoginInfo login)
|
||||
{
|
||||
string commandText = "Insert into UserLogins (LoginProvider, ProviderKey, UserId) values (@loginProvider, @providerKey, @userId)";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("loginProvider", login.LoginProvider);
|
||||
parameters.Add("providerKey", login.ProviderKey);
|
||||
parameters.Add("userId", user.Id);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a userId given a user's login
|
||||
/// </summary>
|
||||
/// <param name="userLogin">The user's login info</param>
|
||||
/// <returns></returns>
|
||||
public string? FindUserIdByLogin(UserLoginInfo userLogin)
|
||||
{
|
||||
string commandText = "Select UserId from UserLogins where LoginProvider = @loginProvider and ProviderKey = @providerKey";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("loginProvider", userLogin.LoginProvider);
|
||||
parameters.Add("providerKey", userLogin.ProviderKey);
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of user's logins
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public List<UserLoginInfo> FindByUserId(string userId)
|
||||
{
|
||||
List<UserLoginInfo> logins = new List<UserLoginInfo>();
|
||||
string commandText = "Select * from UserLogins where UserId = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@userId", userId } };
|
||||
|
||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||
foreach (DataRow row in rows)
|
||||
{
|
||||
var login = new UserLoginInfo((string)row["LoginProvider"], (string)row["ProviderKey"], (string)row["LoginProvider"]);
|
||||
logins.Add(login);
|
||||
}
|
||||
|
||||
return logins;
|
||||
}
|
||||
}
|
||||
}
|
86
gaseous-server/Classes/Auth/Classes/UserRoleTable.cs
Normal file
86
gaseous-server/Classes/Auth/Classes/UserRoleTable.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents the UserRoles table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserRolesTable
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase instance
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public UserRolesTable(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of user's roles
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public List<string> FindByUserId(string userId)
|
||||
{
|
||||
List<string> roles = new List<string>();
|
||||
string commandText = "Select Roles.Name from UserRoles, Roles where UserRoles.UserId = @userId and UserRoles.RoleId = Roles.Id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||
foreach(DataRow row in rows)
|
||||
{
|
||||
roles.Add((string)row["Name"]);
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all roles from a user in the UserRoles table
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from UserRoles where UserId = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("UserId", userId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
public int DeleteUserFromRole(string userId, string roleId)
|
||||
{
|
||||
string commandText = "Delete from UserRoles where UserId = @userId and RoleId = @roleId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("userId", userId);
|
||||
parameters.Add("roleId", roleId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new role for a user in the UserRoles table
|
||||
/// </summary>
|
||||
/// <param name="user">The User</param>
|
||||
/// <param name="roleId">The Role's id</param>
|
||||
/// <returns></returns>
|
||||
public int Insert(IdentityUser user, string roleId)
|
||||
{
|
||||
string commandText = "Insert into UserRoles (UserId, RoleId) values (@userId, @roleId)";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("userId", user.Id);
|
||||
parameters.Add("roleId", roleId);
|
||||
|
||||
return (int)_database.ExecuteNonQuery(commandText, parameters);
|
||||
}
|
||||
}
|
||||
}
|
616
gaseous-server/Classes/Auth/Classes/UserStore.cs
Normal file
616
gaseous-server/Classes/Auth/Classes/UserStore.cs
Normal file
@@ -0,0 +1,616 @@
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
public class UserStore :
|
||||
IUserStore<ApplicationUser>,
|
||||
IUserRoleStore<ApplicationUser>,
|
||||
IUserLoginStore<ApplicationUser>,
|
||||
IUserClaimStore<ApplicationUser>,
|
||||
IUserPasswordStore<ApplicationUser>,
|
||||
IUserSecurityStampStore<ApplicationUser>,
|
||||
IQueryableUserStore<ApplicationUser>,
|
||||
IUserEmailStore<ApplicationUser>,
|
||||
IUserPhoneNumberStore<ApplicationUser>,
|
||||
IUserTwoFactorStore<ApplicationUser>,
|
||||
IUserLockoutStore<ApplicationUser>
|
||||
{
|
||||
private Database database;
|
||||
|
||||
private UserTable<ApplicationUser> userTable;
|
||||
private RoleTable roleTable;
|
||||
private UserRolesTable userRolesTable;
|
||||
private UserLoginsTable userLoginsTable;
|
||||
private UserClaimsTable userClaimsTable;
|
||||
|
||||
public UserStore()
|
||||
{
|
||||
database = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
userTable = new UserTable<ApplicationUser>(database);
|
||||
roleTable = new RoleTable(database);
|
||||
userRolesTable = new UserRolesTable(database);
|
||||
userLoginsTable = new UserLoginsTable(database);
|
||||
userClaimsTable = new UserClaimsTable(database);
|
||||
}
|
||||
|
||||
public UserStore(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
userTable = new UserTable<ApplicationUser>(database);
|
||||
roleTable = new RoleTable(database);
|
||||
userRolesTable = new UserRolesTable(database);
|
||||
userLoginsTable = new UserLoginsTable(database);
|
||||
userClaimsTable = new UserClaimsTable(database);
|
||||
}
|
||||
|
||||
public IQueryable<ApplicationUser> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ApplicationUser> users = userTable.GetUsers();
|
||||
return users.AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
public Task AddClaimsAsync(ApplicationUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (claims == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
foreach (Claim claim in claims)
|
||||
{
|
||||
userClaimsTable.Insert(claim, user.Id);
|
||||
}
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task AddLoginAsync(ApplicationUser user, UserLoginInfo login, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
throw new ArgumentNullException("login");
|
||||
}
|
||||
|
||||
userLoginsTable.Insert(user, login);
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task AddToRoleAsync(ApplicationUser user, string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(roleName))
|
||||
{
|
||||
throw new ArgumentException("Argument cannot be null or empty: roleName.");
|
||||
}
|
||||
|
||||
string roleId = roleTable.GetRoleId(roleName);
|
||||
if (!string.IsNullOrEmpty(roleId))
|
||||
{
|
||||
userRolesTable.Insert(user, roleId);
|
||||
}
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> CreateAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
userTable.Insert(user);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
userTable.Delete(user);
|
||||
}
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (database != null)
|
||||
{
|
||||
database = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApplicationUser?> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
|
||||
{
|
||||
if (String.IsNullOrEmpty(normalizedEmail))
|
||||
{
|
||||
throw new ArgumentNullException("email");
|
||||
}
|
||||
|
||||
ApplicationUser result = userTable.GetUserByEmail(normalizedEmail) as ApplicationUser;
|
||||
if (result != null)
|
||||
{
|
||||
return Task.FromResult<ApplicationUser>(result);
|
||||
}
|
||||
|
||||
return Task.FromResult<ApplicationUser>(null);
|
||||
}
|
||||
|
||||
public Task<ApplicationUser?> FindByIdAsync(string userId, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException("Null or empty argument: userId");
|
||||
}
|
||||
|
||||
ApplicationUser result = userTable.GetUserById(userId) as ApplicationUser;
|
||||
if (result != null)
|
||||
{
|
||||
return Task.FromResult<ApplicationUser>(result);
|
||||
}
|
||||
|
||||
return Task.FromResult<ApplicationUser>(null);
|
||||
}
|
||||
|
||||
public Task<ApplicationUser?> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken)
|
||||
{
|
||||
if (loginProvider == null || providerKey == null)
|
||||
{
|
||||
throw new ArgumentNullException("login");
|
||||
}
|
||||
|
||||
UserLoginInfo login = new UserLoginInfo(loginProvider, providerKey, loginProvider);
|
||||
|
||||
var userId = userLoginsTable.FindUserIdByLogin(login);
|
||||
if (userId != null)
|
||||
{
|
||||
ApplicationUser user = userTable.GetUserById(userId) as ApplicationUser;
|
||||
if (user != null)
|
||||
{
|
||||
return Task.FromResult<ApplicationUser>(user);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult<ApplicationUser>(null);
|
||||
}
|
||||
|
||||
public Task<ApplicationUser?> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(normalizedUserName))
|
||||
{
|
||||
throw new ArgumentException("Null or empty argument: normalizedUserName");
|
||||
}
|
||||
|
||||
List<ApplicationUser> result = userTable.GetUserByName(normalizedUserName) as List<ApplicationUser>;
|
||||
|
||||
// Should I throw if > 1 user?
|
||||
if (result != null && result.Count == 1)
|
||||
{
|
||||
return Task.FromResult<ApplicationUser>(result[0]);
|
||||
}
|
||||
|
||||
return Task.FromResult<ApplicationUser>(null);
|
||||
}
|
||||
|
||||
public Task<int> GetAccessFailedCountAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.AccessFailedCount);
|
||||
}
|
||||
|
||||
public Task<IList<Claim>> GetClaimsAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
ClaimsIdentity identity = userClaimsTable.FindByUserId(user.Id);
|
||||
|
||||
return Task.FromResult<IList<Claim>>(identity.Claims.ToList());
|
||||
}
|
||||
|
||||
public Task<string?> GetEmailAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.Email);
|
||||
}
|
||||
|
||||
public Task<bool> GetEmailConfirmedAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.EmailConfirmed);
|
||||
}
|
||||
|
||||
public Task<bool> GetLockoutEnabledAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.LockoutEnabled);
|
||||
}
|
||||
|
||||
public Task<DateTimeOffset?> GetLockoutEndDateAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user.LockoutEnd.HasValue)
|
||||
{
|
||||
return Task.FromResult((DateTimeOffset?)user.LockoutEnd.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult((DateTimeOffset?)new DateTimeOffset());
|
||||
}
|
||||
}
|
||||
|
||||
public Task<IList<UserLoginInfo>> GetLoginsAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
List<UserLoginInfo> logins = userLoginsTable.FindByUserId(user.Id);
|
||||
if (logins != null)
|
||||
{
|
||||
return Task.FromResult<IList<UserLoginInfo>>(logins);
|
||||
}
|
||||
|
||||
return Task.FromResult<IList<UserLoginInfo>>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetNormalizedEmailAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.NormalizedEmail);
|
||||
}
|
||||
|
||||
public Task<string?> GetNormalizedUserNameAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
return Task.FromResult<string?>(userTable.GetUserName(user.Id));
|
||||
}
|
||||
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetPasswordHashAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
return Task.FromResult<string?>(userTable.GetPasswordHash(user.Id));
|
||||
}
|
||||
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetPhoneNumberAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.PhoneNumber);
|
||||
}
|
||||
|
||||
public Task<bool> GetPhoneNumberConfirmedAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.PhoneNumberConfirmed);
|
||||
}
|
||||
|
||||
public Task<IList<string>> GetRolesAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
List<string> roles = userRolesTable.FindByUserId(user.Id);
|
||||
{
|
||||
if (roles != null)
|
||||
{
|
||||
return Task.FromResult<IList<string>>(roles);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult<IList<string>>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetSecurityStampAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.SecurityStamp);
|
||||
}
|
||||
|
||||
public Task<bool> GetTwoFactorEnabledAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.TwoFactorEnabled);
|
||||
}
|
||||
|
||||
public Task<string> GetUserIdAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
return Task.FromResult<string>(userTable.GetUserId(user.NormalizedUserName));
|
||||
}
|
||||
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task<string?> GetUserNameAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
//return Task.FromResult<string?>(userTable.GetUserName(user.Id));
|
||||
return Task.FromResult(user.UserName);
|
||||
}
|
||||
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
|
||||
public Task<IList<ApplicationUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IList<ApplicationUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> HasPasswordAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
var hasPassword = !string.IsNullOrEmpty(userTable.GetPasswordHash(user.Id));
|
||||
|
||||
return Task.FromResult<bool>(Boolean.Parse(hasPassword.ToString()));
|
||||
}
|
||||
|
||||
public Task<int> IncrementAccessFailedCountAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
user.AccessFailedCount++;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(user.AccessFailedCount);
|
||||
}
|
||||
|
||||
public Task<bool> IsInRoleAsync(ApplicationUser user, string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(roleName))
|
||||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
|
||||
List<string> roles = userRolesTable.FindByUserId(user.Id);
|
||||
{
|
||||
if (roles != null)
|
||||
{
|
||||
foreach (string role in roles)
|
||||
{
|
||||
if (role.ToUpper() == roleName.ToUpper())
|
||||
{
|
||||
return Task.FromResult<bool>(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult<bool>(false);
|
||||
}
|
||||
|
||||
public Task RemoveClaimsAsync(ApplicationUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (claims == null)
|
||||
{
|
||||
throw new ArgumentNullException("claim");
|
||||
}
|
||||
|
||||
foreach (Claim claim in claims)
|
||||
{
|
||||
userClaimsTable.Delete(user, claim);
|
||||
}
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task RemoveFromRoleAsync(ApplicationUser user, string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (roleName == null)
|
||||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
|
||||
IdentityRole? role = roleTable.GetRoleByName(roleName);
|
||||
|
||||
if (role != null)
|
||||
{
|
||||
userRolesTable.DeleteUserFromRole(user.Id, role.Id);
|
||||
}
|
||||
|
||||
return Task.FromResult<Object>(null);
|
||||
}
|
||||
|
||||
public Task RemoveLoginAsync(ApplicationUser user, string loginProvider, string providerKey, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (loginProvider == null || providerKey == null)
|
||||
{
|
||||
throw new ArgumentNullException("login");
|
||||
}
|
||||
|
||||
UserLoginInfo login = new UserLoginInfo(loginProvider, providerKey, loginProvider);
|
||||
|
||||
userLoginsTable.Delete(user, login);
|
||||
|
||||
return Task.FromResult<Object>(null);
|
||||
}
|
||||
|
||||
public Task ReplaceClaimAsync(ApplicationUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
if (claim == null || newClaim == null)
|
||||
{
|
||||
throw new ArgumentNullException("claim");
|
||||
}
|
||||
|
||||
userClaimsTable.Delete(user, claim);
|
||||
userClaimsTable.Insert(newClaim, user.Id);
|
||||
|
||||
return Task.FromResult<Object>(null);
|
||||
}
|
||||
|
||||
public Task ResetAccessFailedCountAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
user.AccessFailedCount = 0;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetEmailAsync(ApplicationUser user, string? email, CancellationToken cancellationToken)
|
||||
{
|
||||
user.Email = email;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetEmailConfirmedAsync(ApplicationUser user, bool confirmed, CancellationToken cancellationToken)
|
||||
{
|
||||
user.EmailConfirmed = confirmed;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetLockoutEnabledAsync(ApplicationUser user, bool enabled, CancellationToken cancellationToken)
|
||||
{
|
||||
user.LockoutEnabled = enabled;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetLockoutEndDateAsync(ApplicationUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken)
|
||||
{
|
||||
user.LockoutEnd = lockoutEnd;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetNormalizedEmailAsync(ApplicationUser user, string? normalizedEmail, CancellationToken cancellationToken)
|
||||
{
|
||||
user.NormalizedEmail = normalizedEmail;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetNormalizedUserNameAsync(ApplicationUser user, string? normalizedName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
user.NormalizedUserName = normalizedName;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task SetPasswordHashAsync(ApplicationUser user, string? passwordHash, CancellationToken cancellationToken)
|
||||
{
|
||||
user.PasswordHash = passwordHash;
|
||||
|
||||
return Task.FromResult<Object>(null);
|
||||
}
|
||||
|
||||
public Task SetPhoneNumberAsync(ApplicationUser user, string? phoneNumber, CancellationToken cancellationToken)
|
||||
{
|
||||
user.PhoneNumber = phoneNumber;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetPhoneNumberConfirmedAsync(ApplicationUser user, bool confirmed, CancellationToken cancellationToken)
|
||||
{
|
||||
user.PhoneNumberConfirmed = confirmed;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetSecurityStampAsync(ApplicationUser user, string stamp, CancellationToken cancellationToken)
|
||||
{
|
||||
user.SecurityStamp = stamp;
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetTwoFactorEnabledAsync(ApplicationUser user, bool enabled, CancellationToken cancellationToken)
|
||||
{
|
||||
user.TwoFactorEnabled = enabled;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SetUserNameAsync(ApplicationUser user, string? userName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
user.UserName = userName;
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
userTable.Update(user);
|
||||
|
||||
return Task.FromResult<IdentityResult>(IdentityResult.Success);
|
||||
}
|
||||
}
|
||||
}
|
371
gaseous-server/Classes/Auth/Classes/UserTable.cs
Normal file
371
gaseous-server/Classes/Auth/Classes/UserTable.cs
Normal file
@@ -0,0 +1,371 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents the Users table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserTable<TUser>
|
||||
where TUser :ApplicationUser
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a MySQLDatabase instance
|
||||
/// </summary>
|
||||
/// <param name="database"></param>
|
||||
public UserTable(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the user's name given a user id
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public string? GetUserName(string userId)
|
||||
{
|
||||
string commandText = "Select NormalizedUserName from Users where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a User ID given a user name
|
||||
/// </summary>
|
||||
/// <param name="userName">The user's name</param>
|
||||
/// <returns></returns>
|
||||
public string? GetUserId(string normalizedUserName)
|
||||
{
|
||||
string commandText = "Select Id from Users where NormalizedUserName = @name";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an TUser given the user's id
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public TUser GetUserById(string userId)
|
||||
{
|
||||
TUser user = null;
|
||||
string commandText = "Select * from Users where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||
if (rows != null && rows.Count == 1)
|
||||
{
|
||||
Dictionary<string, object> row = rows[0];
|
||||
user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
user.UserName = (string?)row["UserName"];
|
||||
user.PasswordHash = (string?)(string.IsNullOrEmpty((string?)row["PasswordHash"]) ? null : row["PasswordHash"]);
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
user.NormalizedUserName = (string?)(string.IsNullOrEmpty((string?)row["NormalizedUserName"]) ? null : row["NormalizedUserName"]);
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of TUser instances given a user name
|
||||
/// </summary>
|
||||
/// <param name="normalizedUserName">User's name</param>
|
||||
/// <returns></returns>
|
||||
public List<TUser> GetUserByName(string normalizedUserName)
|
||||
{
|
||||
List<TUser> users = new List<TUser>();
|
||||
string commandText = "Select * from Users where NormalizedEmail = @name";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
{
|
||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
user.UserName = (string?)row["UserName"];
|
||||
user.PasswordHash = (string?)(string.IsNullOrEmpty((string?)row["PasswordHash"]) ? null : row["PasswordHash"]);
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
user.NormalizedUserName = (string?)(string.IsNullOrEmpty((string?)row["NormalizedUserName"]) ? null : row["NormalizedUserName"]);
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public List<TUser> GetUsers()
|
||||
{
|
||||
List<TUser> users = new List<TUser>();
|
||||
string commandText = "Select * from Users order by NormalizedUserName";
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
{
|
||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
user.UserName = (string?)row["UserName"];
|
||||
user.PasswordHash = (string?)(string.IsNullOrEmpty((string?)row["PasswordHash"]) ? null : row["PasswordHash"]);
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
user.NormalizedUserName = (string?)(string.IsNullOrEmpty((string?)row["NormalizedUserName"]) ? null : row["NormalizedUserName"]);
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public TUser GetUserByEmail(string email)
|
||||
{
|
||||
List<TUser> users = GetUserByName(email);
|
||||
if (users.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return users[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the user's password hash
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
public string GetPasswordHash(string userId)
|
||||
{
|
||||
string commandText = "Select PasswordHash from Users where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@id", userId);
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the user's password hash
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="passwordHash"></param>
|
||||
/// <returns></returns>
|
||||
public int SetPasswordHash(string userId, string passwordHash)
|
||||
{
|
||||
string commandText = "Update Users set PasswordHash = @pwdHash where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@pwdHash", passwordHash);
|
||||
parameters.Add("@id", userId);
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the user's security stamp
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public string GetSecurityStamp(string userId)
|
||||
{
|
||||
string commandText = "Select SecurityStamp from Users where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string)table.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new user in the Users table
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public int Insert(TUser user)
|
||||
{
|
||||
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp, ConcurrencyStamp, Email, EmailConfirmed, PhoneNumber, PhoneNumberConfirmed, NormalizedEmail, NormalizedUserName, AccessFailedCount, LockoutEnabled, LockoutEnd, TwoFactorEnabled) values (@name, @id, @pwdHash, @SecStamp, @concurrencystamp, @email ,@emailconfirmed ,@phonenumber, @phonenumberconfirmed, @normalizedemail, @normalizedusername, @accesscount, @lockoutenabled, @lockoutenddate, @twofactorenabled);";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@name", user.UserName);
|
||||
parameters.Add("@id", user.Id);
|
||||
parameters.Add("@pwdHash", user.PasswordHash);
|
||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||
parameters.Add("@email", user.Email);
|
||||
parameters.Add("@emailconfirmed", user.EmailConfirmed);
|
||||
parameters.Add("@phonenumber", user.PhoneNumber);
|
||||
parameters.Add("@phonenumberconfirmed", user.PhoneNumberConfirmed);
|
||||
parameters.Add("@normalizedemail", user.NormalizedEmail);
|
||||
parameters.Add("@normalizedusername", user.NormalizedUserName);
|
||||
parameters.Add("@accesscount", user.AccessFailedCount);
|
||||
parameters.Add("@lockoutenabled", user.LockoutEnabled);
|
||||
parameters.Add("@lockoutenddate", user.LockoutEnd);
|
||||
parameters.Add("@twofactorenabled", user.TwoFactorEnabled);
|
||||
|
||||
// set default security profile
|
||||
SetSecurityProfile(user, new SecurityProfileViewModel());
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a user from the Users table
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id</param>
|
||||
/// <returns></returns>
|
||||
private int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from Users where Id = @userId";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a user from the Users table
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public int Delete(TUser user)
|
||||
{
|
||||
return Delete(user.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a user in the Users table
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public int Update(TUser user)
|
||||
{
|
||||
string commandText = @"Update Users set UserName = @userName, PasswordHash = @pwdHash, SecurityStamp = @secStamp, ConcurrencyStamp = @concurrencystamp, Email = @email, EmailConfirmed = @emailconfirmed, PhoneNumber = @phonenumber, PhoneNumberConfirmed = @phonenumberconfirmed, NormalizedEmail = @normalizedemail, NormalizedUserName = @normalizedusername, AccessFailedCount = @accesscount, LockoutEnabled = @lockoutenabled, LockoutEnd = @lockoutenddate, TwoFactorEnabled=@twofactorenabled WHERE Id = @userId;";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@userId", user.Id);
|
||||
parameters.Add("@userName", user.UserName);
|
||||
parameters.Add("@pwdHash", user.PasswordHash);
|
||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||
parameters.Add("@email", user.Email);
|
||||
parameters.Add("@emailconfirmed", user.EmailConfirmed);
|
||||
parameters.Add("@phonenumber", user.PhoneNumber);
|
||||
parameters.Add("@phonenumberconfirmed", user.PhoneNumberConfirmed);
|
||||
parameters.Add("@normalizedemail", user.NormalizedEmail);
|
||||
parameters.Add("@normalizedusername", user.NormalizedUserName);
|
||||
parameters.Add("@accesscount", user.AccessFailedCount);
|
||||
parameters.Add("@lockoutenabled", user.LockoutEnabled);
|
||||
parameters.Add("@lockoutenddate", user.LockoutEnd);
|
||||
parameters.Add("@twofactorenabled", user.TwoFactorEnabled);
|
||||
|
||||
// set the security profile
|
||||
SetSecurityProfile(user, user.SecurityProfile);
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
|
||||
private SecurityProfileViewModel GetSecurityProfile(TUser user)
|
||||
{
|
||||
string sql = "SELECT SecurityProfile FROM users WHERE Id=@Id;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("Id", user.Id);
|
||||
|
||||
List<Dictionary<string, object>> data = _database.ExecuteCMDDict(sql, dbDict);
|
||||
if (data.Count == 0)
|
||||
{
|
||||
// no saved profile - return the default one
|
||||
return new SecurityProfileViewModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
string? securityProfileString = (string?)data[0]["SecurityProfile"];
|
||||
if (securityProfileString != null && securityProfileString != "null")
|
||||
{
|
||||
SecurityProfileViewModel securityProfile = Newtonsoft.Json.JsonConvert.DeserializeObject<SecurityProfileViewModel>(securityProfileString);
|
||||
return securityProfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SecurityProfileViewModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int SetSecurityProfile(TUser user, SecurityProfileViewModel securityProfile)
|
||||
{
|
||||
string commandText = "UPDATE users SET SecurityProfile=@SecurityProfile WHERE Id=@Id;";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("Id", user.Id);
|
||||
parameters.Add("SecurityProfile", Newtonsoft.Json.JsonConvert.SerializeObject(securityProfile));
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
}
|
||||
}
|
100
gaseous-server/Classes/Auth/Models/AccountViewModels.cs
Normal file
100
gaseous-server/Classes/Auth/Models/AccountViewModels.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
public class ExternalLoginConfirmationViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
|
||||
public class ManageUserViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class LoginViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class RegisterViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Text)]
|
||||
[Display(Name = "User name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class ResetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class ForgotPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class AddPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class ChangePasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 10)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class DisplayRecoveryCodesViewModel
|
||||
{
|
||||
[Required]
|
||||
public IEnumerable<string> Codes { get; set; }
|
||||
|
||||
}
|
21
gaseous-server/Classes/Auth/Models/IndexViewModel.cs
Normal file
21
gaseous-server/Classes/Auth/Models/IndexViewModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class IndexViewModel
|
||||
{
|
||||
public bool HasPassword { get; set; }
|
||||
|
||||
public IList<UserLoginInfo> Logins { get; set; }
|
||||
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
public bool TwoFactor { get; set; }
|
||||
|
||||
public bool BrowserRemembered { get; set; }
|
||||
|
||||
public string AuthenticatorKey { get; set; }
|
||||
}
|
14
gaseous-server/Classes/Auth/Models/ManageLoginsViewModel.cs
Normal file
14
gaseous-server/Classes/Auth/Models/ManageLoginsViewModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class ManageLoginsViewModel
|
||||
{
|
||||
public IList<UserLoginInfo> CurrentLogins { get; set; }
|
||||
|
||||
public IList<AuthenticationScheme> OtherLogins { get; set; }
|
||||
}
|
46
gaseous-server/Classes/Auth/Models/ProfileViewModel.cs
Normal file
46
gaseous-server/Classes/Auth/Models/ProfileViewModel.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace Authentication
|
||||
{
|
||||
public class ProfileBasicViewModel
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public List<String> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public string HighestRole {
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
foreach (string role in Roles)
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case "Admin":
|
||||
// there is no higher
|
||||
_highestRole = role;
|
||||
break;
|
||||
case "Gamer":
|
||||
// only one high is Admin, so check for that
|
||||
if (_highestRole != "Admin")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
case "Player":
|
||||
// make sure _highestRole isn't already set to Gamer or Admin
|
||||
if (_highestRole != "Admin" && _highestRole != "Gamer")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_highestRole = "Player";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _highestRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
gaseous-server/Classes/Auth/Models/RemoveLoginViewModel.cs
Normal file
10
gaseous-server/Classes/Auth/Models/RemoveLoginViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class RemoveLoginViewModel
|
||||
{
|
||||
public string LoginProvider { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication
|
||||
{
|
||||
public class SecurityProfileViewModel
|
||||
{
|
||||
public AgeRestrictionItem AgeRestrictionPolicy { get; set; } = new AgeRestrictionItem{
|
||||
MaximumAgeRestriction = "Adult",
|
||||
IncludeUnrated = true
|
||||
};
|
||||
|
||||
public class AgeRestrictionItem
|
||||
{
|
||||
public string MaximumAgeRestriction { get; set; }
|
||||
public bool IncludeUnrated { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
17
gaseous-server/Classes/Auth/Models/SendCodeViewModel.cs
Normal file
17
gaseous-server/Classes/Auth/Models/SendCodeViewModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class SendCodeViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
|
||||
public ICollection<SelectListItem> Providers { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
20
gaseous-server/Classes/Auth/Models/SetPasswordViewModel.cs
Normal file
20
gaseous-server/Classes/Auth/Models/SetPasswordViewModel.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class SetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class UseRecoveryCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
}
|
47
gaseous-server/Classes/Auth/Models/UserViewModel.cs
Normal file
47
gaseous-server/Classes/Auth/Models/UserViewModel.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace Authentication
|
||||
{
|
||||
public class UserViewModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public bool LockoutEnabled { get; set; }
|
||||
public DateTimeOffset? LockoutEnd { get; set; }
|
||||
public List<string> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public string HighestRole {
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
foreach (string role in Roles)
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case "Admin":
|
||||
// there is no higher
|
||||
_highestRole = role;
|
||||
break;
|
||||
case "Gamer":
|
||||
// only one high is Admin, so check for that
|
||||
if (_highestRole != "Admin")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
case "Player":
|
||||
// make sure _highestRole isn't already set to Gamer or Admin
|
||||
if (_highestRole != "Admin" && _highestRole != "Gamer")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_highestRole = "Player";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _highestRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class VerifyAuthenticatorCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[Display(Name = "Remember this browser?")]
|
||||
public bool RememberBrowser { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
23
gaseous-server/Classes/Auth/Models/VerifyCodeViewModel.cs
Normal file
23
gaseous-server/Classes/Auth/Models/VerifyCodeViewModel.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class VerifyCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Provider { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[Display(Name = "Remember this browser?")]
|
||||
public bool RememberBrowser { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Authentication;
|
||||
|
||||
public class VerifyPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
@@ -147,6 +147,50 @@ namespace gaseous_server.Classes
|
||||
return _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command)
|
||||
{
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteCMDDict(Command, dbDict, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
return _ExecuteCMDDict(Command, Parameters, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
return _ExecuteCMDDict(Command, Parameters, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
private List<Dictionary<string, object>> _ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
DataTable dataTable = _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
||||
|
||||
// convert datatable to dictionary
|
||||
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
||||
|
||||
foreach (DataRow dataRow in dataTable.Rows)
|
||||
{
|
||||
Dictionary<string, object?> row = new Dictionary<string, object?>();
|
||||
for (int i = 0; i < dataRow.Table.Columns.Count; i++)
|
||||
{
|
||||
string columnName = dataRow.Table.Columns[i].ColumnName;
|
||||
if (dataRow[i] == System.DBNull.Value)
|
||||
{
|
||||
row.Add(columnName, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
row.Add(columnName, dataRow[i].ToString());
|
||||
}
|
||||
}
|
||||
rows.Add(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
@@ -160,6 +204,35 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public int ExecuteNonQuery(string Command)
|
||||
{
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteNonQuery(Command, dbDict, 30, "");
|
||||
}
|
||||
|
||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
return _ExecuteNonQuery(Command, Parameters, 30, "");
|
||||
}
|
||||
|
||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
return _ExecuteNonQuery(Command, Parameters, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
private int _ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||
return (int)conn.ExecNonQuery(Command, Parameters, Timeout);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteTransactionCMD(List<SQLTransactionItem> CommandList, int Timeout = 60)
|
||||
{
|
||||
object conn;
|
||||
@@ -284,6 +357,47 @@ namespace gaseous_server.Classes
|
||||
return RetTable;
|
||||
}
|
||||
|
||||
public int ExecNonQuery(string SQL, Dictionary< string, object> Parameters, int Timeout)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||
MySqlConnection conn = new MySqlConnection(DBConn);
|
||||
conn.Open();
|
||||
|
||||
MySqlCommand cmd = new MySqlCommand
|
||||
{
|
||||
Connection = conn,
|
||||
CommandText = SQL,
|
||||
CommandTimeout = Timeout
|
||||
};
|
||||
|
||||
foreach (string Parameter in Parameters.Keys)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(Parameter, Parameters[Parameter]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Executing sql: '" + SQL + "'", null, true);
|
||||
if (Parameters.Count > 0)
|
||||
{
|
||||
string dictValues = string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||
}
|
||||
result = cmd.ExecuteNonQuery();
|
||||
} catch (Exception ex) {
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||
Trace.WriteLine("Error executing " + SQL);
|
||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||
}
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Closing database connection", null, true);
|
||||
conn.Close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
||||
{
|
||||
var conn = new MySqlConnection(DBConn);
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
@@ -151,6 +152,202 @@ namespace gaseous_server.Classes.Metadata
|
||||
public AgeRatingTitle RatingTitle { get; set; }
|
||||
public string[] Descriptions { get; set; }
|
||||
}
|
||||
|
||||
public class AgeGroups
|
||||
{
|
||||
public AgeGroups()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static Dictionary<string, List<AgeGroupItem>> AgeGroupings
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, List<AgeGroupItem>>{
|
||||
{
|
||||
"Adult", new List<AgeGroupItem>{ Adult_Item, Mature_Item, Teen_Item, Child_Item }
|
||||
},
|
||||
{
|
||||
"Mature", new List<AgeGroupItem>{ Mature_Item, Teen_Item, Child_Item }
|
||||
},
|
||||
{
|
||||
"Teen", new List<AgeGroupItem>{ Teen_Item, Child_Item }
|
||||
},
|
||||
{
|
||||
"Child", new List<AgeGroupItem>{ Child_Item }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<string, AgeGroupItem> AgeGroupingsFlat
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, AgeGroupItem>{
|
||||
{
|
||||
"Adult", Adult_Item
|
||||
},
|
||||
{
|
||||
"Mature", Mature_Item
|
||||
},
|
||||
{
|
||||
"Teen", Teen_Item
|
||||
},
|
||||
{
|
||||
"Child", Child_Item
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ClassificationBoardItem> ClassificationBoards
|
||||
{
|
||||
get
|
||||
{
|
||||
ClassificationBoardItem boardItem = new ClassificationBoardItem{
|
||||
Board = AgeRatingCategory.ACB,
|
||||
Classifications = new List<AgeRatingTitle>{
|
||||
AgeRatingTitle.ACB_G, AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15, AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC
|
||||
}
|
||||
};
|
||||
|
||||
return new List<ClassificationBoardItem>{
|
||||
new ClassificationBoardItem{
|
||||
Board = AgeRatingCategory.ACB,
|
||||
Classifications = new List<AgeRatingTitle>{
|
||||
AgeRatingTitle.ACB_G,
|
||||
AgeRatingTitle.ACB_M,
|
||||
AgeRatingTitle.ACB_MA15,
|
||||
AgeRatingTitle.ACB_R18,
|
||||
AgeRatingTitle.ACB_RC
|
||||
}
|
||||
},
|
||||
new ClassificationBoardItem{
|
||||
Board = AgeRatingCategory.CERO,
|
||||
Classifications = new List<AgeRatingTitle>{
|
||||
AgeRatingTitle.CERO_A,
|
||||
AgeRatingTitle.CERO_B,
|
||||
AgeRatingTitle.CERO_C,
|
||||
AgeRatingTitle.CERO_D,
|
||||
AgeRatingTitle.CERO_Z
|
||||
}
|
||||
},
|
||||
new ClassificationBoardItem{
|
||||
Board = AgeRatingCategory.CLASS_IND,
|
||||
Classifications = new List<AgeRatingTitle>{
|
||||
AgeRatingTitle.CLASS_IND_L,
|
||||
AgeRatingTitle.CLASS_IND_Ten,
|
||||
AgeRatingTitle.CLASS_IND_Twelve,
|
||||
AgeRatingTitle.CLASS_IND_Fourteen,
|
||||
AgeRatingTitle.CLASS_IND_Sixteen,
|
||||
AgeRatingTitle.CLASS_IND_Eighteen
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
||||
};
|
||||
|
||||
public class AgeGroupItem
|
||||
{
|
||||
public List<IGDB.Models.AgeRatingTitle> ACB { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> CERO { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> CLASS_IND { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> ESRB { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> GRAC { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> PEGI { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> USK { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public List<long> AgeGroupItemValues
|
||||
{
|
||||
get
|
||||
{
|
||||
List<long> values = new List<long>();
|
||||
{
|
||||
foreach (AgeRatingTitle ageRatingTitle in ACB)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in CERO)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in CLASS_IND)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in ESRB)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in GRAC)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in PEGI)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
foreach (AgeRatingTitle ageRatingTitle in USK)
|
||||
{
|
||||
values.Add((long)ageRatingTitle);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassificationBoardItem
|
||||
{
|
||||
public IGDB.Models.AgeRatingCategory Board { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> Classifications { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
396
gaseous-server/Controllers/V1.0/AccountController.cs
Normal file
396
gaseous-server/Controllers/V1.0/AccountController.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AccountController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_logger = loggerFactory.CreateLogger<AccountController>();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("Login")]
|
||||
public async Task<IActionResult> Login(LoginViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// This doesn't count login failures towards account lockout
|
||||
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Login", model.Email + " has logged in, from IP: " + HttpContext.Connection.RemoteIpAddress?.ToString());
|
||||
return Ok(result.ToString());
|
||||
}
|
||||
// if (result.RequiresTwoFactor)
|
||||
// {
|
||||
// return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
// }
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Login", model.Email + " was unable to login due to a locked account. Login attempt from IP: " + HttpContext.Connection.RemoteIpAddress?.ToString());
|
||||
return Unauthorized();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Login", "An unknown error occurred during login by " + model.Email + ". Login attempt from IP: " + HttpContext.Connection.RemoteIpAddress?.ToString());
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
Logging.Log(Logging.LogType.Critical, "Login", "An unknown error occurred during login by " + model.Email + ". Login attempt from IP: " + HttpContext.Connection.RemoteIpAddress?.ToString());
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("LogOff")]
|
||||
public async Task<IActionResult> LogOff()
|
||||
{
|
||||
var userName = User.FindFirstValue(ClaimTypes.Name);
|
||||
await _signInManager.SignOutAsync();
|
||||
if (userName != null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Login", userName + " has logged out");
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Profile/Basic")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> ProfileBasic()
|
||||
{
|
||||
ProfileBasicViewModel profile = new ProfileBasicViewModel();
|
||||
profile.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
ApplicationUser user = await _userManager.FindByIdAsync(profile.UserId);
|
||||
profile.UserName = _userManager.GetUserName(HttpContext.User);
|
||||
profile.EmailAddress = await _userManager.GetEmailAsync(user);
|
||||
profile.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
||||
profile.SecurityProfile = user.SecurityProfile;
|
||||
profile.Roles.Sort();
|
||||
|
||||
return Ok(profile);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Profile/Basic/profile.js")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> ProfileBasicFile()
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user != null)
|
||||
{
|
||||
ProfileBasicViewModel profile = new ProfileBasicViewModel();
|
||||
profile.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
profile.UserName = _userManager.GetUserName(HttpContext.User);
|
||||
profile.EmailAddress = await _userManager.GetEmailAsync(user);
|
||||
profile.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
||||
profile.SecurityProfile = user.SecurityProfile;
|
||||
profile.Roles.Sort();
|
||||
|
||||
string profileString = "var userProfile = " + Newtonsoft.Json.JsonConvert.SerializeObject(profile, Newtonsoft.Json.Formatting.Indented) + ";";
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(profileString);
|
||||
return File(bytes, "text/javascript");
|
||||
}
|
||||
else
|
||||
{
|
||||
string profileString = "var userProfile = null;";
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(profileString);
|
||||
return File(bytes, "text/javascript");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("ChangePassword")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return RedirectToAction("Login");
|
||||
}
|
||||
|
||||
// ChangePasswordAsync changes the user password
|
||||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
|
||||
// The new password did not meet the complexity rules or
|
||||
// the current password is incorrect. Add these errors to
|
||||
// the ModelState and rerender ChangePassword view
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
return Unauthorized(result);
|
||||
}
|
||||
|
||||
// Upon successfully changing the password refresh sign-in cookie
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Users")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> GetAllUsers()
|
||||
{
|
||||
List<UserViewModel> users = new List<UserViewModel>();
|
||||
|
||||
foreach (ApplicationUser rawUser in _userManager.Users)
|
||||
{
|
||||
UserViewModel user = new UserViewModel();
|
||||
user.Id = rawUser.Id;
|
||||
user.EmailAddress = rawUser.NormalizedEmail.ToLower();
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
|
||||
// get roles
|
||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||
if (aUser != null)
|
||||
{
|
||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(aUser);
|
||||
user.Roles = aUserRoles.ToList();
|
||||
|
||||
user.Roles.Sort();
|
||||
}
|
||||
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
return Ok(users);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Users")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> NewUser(RegisterViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
UserName = model.UserName,
|
||||
NormalizedUserName = model.UserName.ToUpper(),
|
||||
Email = model.Email,
|
||||
NormalizedEmail = model.Email.ToUpper()
|
||||
};
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
// add new users to the player role
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "User Management", User.FindFirstValue(ClaimTypes.Name) + " created user " + model.Email + " with password.");
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Users/{UserId}")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> GetUser(string UserId)
|
||||
{
|
||||
ApplicationUser? rawUser = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
if (rawUser != null)
|
||||
{
|
||||
UserViewModel user = new UserViewModel();
|
||||
user.Id = rawUser.Id;
|
||||
user.EmailAddress = rawUser.NormalizedEmail.ToLower();
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
|
||||
// get roles
|
||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
||||
user.Roles = aUserRoles.ToList();
|
||||
|
||||
user.Roles.Sort();
|
||||
|
||||
return Ok(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Route("Users/{UserId}")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> DeleteUser(string UserId)
|
||||
{
|
||||
// get user
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _userManager.DeleteAsync(user);
|
||||
Logging.Log(Logging.LogType.Information, "User Management", User.FindFirstValue(ClaimTypes.Name) + " deleted user " + user.Email);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Users/{UserId}/Roles")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> SetUserRoles(string UserId, string RoleName)
|
||||
{
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
// get roles
|
||||
List<string> userRoles = (await _userManager.GetRolesAsync(user)).ToList();
|
||||
|
||||
// delete all roles
|
||||
foreach (string role in userRoles)
|
||||
{
|
||||
if ((new string[] { "Admin", "Gamer", "Player" }).Contains(role) )
|
||||
{
|
||||
await _userManager.RemoveFromRoleAsync(user, role);
|
||||
}
|
||||
}
|
||||
|
||||
// add only requested roles
|
||||
switch (RoleName)
|
||||
{
|
||||
case "Admin":
|
||||
await _userManager.AddToRoleAsync(user, "Admin");
|
||||
await _userManager.AddToRoleAsync(user, "Gamer");
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
break;
|
||||
case "Gamer":
|
||||
await _userManager.AddToRoleAsync(user, "Gamer");
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
break;
|
||||
case "Player":
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
break;
|
||||
default:
|
||||
await _userManager.AddToRoleAsync(user, RoleName);
|
||||
break;
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Users/{UserId}/SecurityProfile")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> SetUserSecurityProfile(string UserId, SecurityProfileViewModel securityProfile)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
user.SecurityProfile = securityProfile;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Users/{UserId}/Password")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> ResetPassword(string UserId, SetPasswordViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// we can reset the users password
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
if (user != null)
|
||||
{
|
||||
string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
IdentityResult passwordChangeResult = await _userManager.ResetPasswordAsync(user, resetToken, model.NewPassword);
|
||||
if (passwordChangeResult.Succeeded == true)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(passwordChangeResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -9,9 +10,12 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize(Roles = "Admin,Gamer,Player")]
|
||||
public class BackgroundTasksController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<ProcessQueue.QueueItem> GetQueue()
|
||||
@@ -20,10 +24,12 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{TaskType}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public ActionResult<ProcessQueue.QueueItem> ForceRun(ProcessQueue.QueueItemType TaskType, Boolean ForceRun)
|
||||
{
|
||||
foreach (ProcessQueue.QueueItem qi in ProcessQueue.QueueItems)
|
@@ -4,6 +4,7 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -11,9 +12,12 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class BiosController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Classes.Bios.BiosItem> GetBios()
|
||||
@@ -22,6 +26,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
@@ -31,8 +36,10 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("zip/{PlatformId}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -66,8 +73,10 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("{PlatformId}/{BiosName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
@@ -4,6 +4,7 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -11,6 +12,8 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class CollectionsController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
@@ -18,6 +21,7 @@ namespace gaseous_server.Controllers
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Classes.Collections.CollectionItem> GetCollections()
|
||||
@@ -32,6 +36,7 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="Build">Set to true to begin the collection build process</param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
@@ -59,6 +64,7 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}/Roms")]
|
||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||
@@ -82,8 +88,10 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Route("Preview")]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetCollectionRomsPreview(Classes.Collections.CollectionItem Item)
|
||||
@@ -104,6 +112,7 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}/Roms/Zip")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -138,7 +147,9 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public ActionResult NewCollection(Classes.Collections.CollectionItem Item)
|
||||
@@ -160,8 +171,10 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
[Route("{CollectionId}")]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult EditCollection(long CollectionId, Classes.Collections.CollectionItem Item)
|
||||
@@ -183,7 +196,9 @@ namespace gaseous_server.Controllers
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{CollectionId}/AlwaysInclude")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -218,7 +233,9 @@ namespace gaseous_server.Controllers
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{CollectionId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -12,10 +13,13 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class FilterController : ControllerBase
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
@@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
@@ -18,6 +19,8 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class GamesController : ControllerBase
|
||||
{
|
||||
@@ -36,7 +39,7 @@ namespace gaseous_server.Controllers
|
||||
bool sortdescending = false)
|
||||
{
|
||||
|
||||
return Ok(GetGames(name, platform, genre, gamemode, playerperspective, theme, minrating, maxrating, sortdescending));
|
||||
return Ok(GetGames(name, platform, genre, gamemode, playerperspective, theme, minrating, maxrating, "Adult", true, true, sortdescending));
|
||||
}
|
||||
|
||||
public static List<Game> GetGames(
|
||||
@@ -48,6 +51,9 @@ namespace gaseous_server.Controllers
|
||||
string theme = "",
|
||||
int minrating = -1,
|
||||
int maxrating = -1,
|
||||
string ratinggroup = "Adult",
|
||||
bool includenullrating = true,
|
||||
bool sortbynamethe = false,
|
||||
bool sortdescending = false)
|
||||
{
|
||||
string whereClause = "";
|
||||
@@ -170,6 +176,52 @@ namespace gaseous_server.Controllers
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (ratinggroup.Length > 0)
|
||||
{
|
||||
List<long> AgeClassificationsList = new List<long>();
|
||||
foreach (string ratingGroup in ratinggroup.Split(','))
|
||||
{
|
||||
if (AgeGroups.AgeGroupings.ContainsKey(ratingGroup))
|
||||
{
|
||||
List<AgeGroups.AgeGroupItem> ageGroups = AgeGroups.AgeGroupings[ratingGroup];
|
||||
foreach (AgeGroups.AgeGroupItem ageGroup in ageGroups)
|
||||
{
|
||||
AgeClassificationsList.AddRange(ageGroup.AgeGroupItemValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AgeClassificationsList.Count > 0)
|
||||
{
|
||||
tempVal = "(view_AgeRatings.Rating IN (";
|
||||
for (int i = 0; i < AgeClassificationsList.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += ", ";
|
||||
}
|
||||
string themeLabel = "@Rating" + i;
|
||||
tempVal += themeLabel;
|
||||
whereParams.Add(themeLabel, AgeClassificationsList[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
|
||||
tempVal += " OR ";
|
||||
|
||||
if (includenullrating == true)
|
||||
{
|
||||
tempVal += "view_AgeRatings.Rating IS NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
tempVal += "view_AgeRatings.Rating IS NOT NULL";
|
||||
}
|
||||
tempVal += ")";
|
||||
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
}
|
||||
|
||||
// build where clause
|
||||
if (whereClauses.Count > 0)
|
||||
{
|
||||
@@ -199,14 +251,21 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
// order by clause
|
||||
string orderByClause = "ORDER BY `Name` ASC";
|
||||
string orderByField = "Name";
|
||||
if (sortbynamethe == true)
|
||||
{
|
||||
orderByField = "NameThe";
|
||||
}
|
||||
string orderByClause = "ORDER BY `" + orderByField + "` ASC";
|
||||
if (sortdescending == true)
|
||||
{
|
||||
orderByClause = "ORDER BY `Name` DESC";
|
||||
orderByClause = "ORDER BY `" + orderByField + "` DESC";
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.* FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
//string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.* FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
|
||||
string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.*, case when Game.`Name` like 'The %' then CONCAT(trim(substr(Game.`Name` from 4)), ', The') else Game.`Name` end as NameThe FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId LEFT JOIN (SELECT Relation_Game_AgeRatings.GameId, AgeRating.* FROM Relation_Game_AgeRatings JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id) view_AgeRatings ON Game.Id = view_AgeRatings.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
|
||||
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
||||
|
||||
@@ -221,6 +280,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}")]
|
||||
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
||||
@@ -248,6 +308,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/alternativename")]
|
||||
[ProducesResponseType(typeof(List<AlternativeName>), StatusCodes.Status200OK)]
|
||||
@@ -280,6 +341,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/agerating")]
|
||||
[ProducesResponseType(typeof(List<AgeRatings.GameAgeRating>), StatusCodes.Status200OK)]
|
||||
@@ -312,6 +374,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/agerating/{RatingId}/image")]
|
||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||
@@ -392,6 +455,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/artwork")]
|
||||
[ProducesResponseType(typeof(List<Artwork>), StatusCodes.Status200OK)]
|
||||
@@ -422,6 +486,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/artwork/{ArtworkId}")]
|
||||
[ProducesResponseType(typeof(Artwork), StatusCodes.Status200OK)]
|
||||
@@ -457,6 +522,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/artwork/{ArtworkId}/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -512,6 +578,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/cover")]
|
||||
[ProducesResponseType(typeof(Cover), StatusCodes.Status200OK)]
|
||||
@@ -546,6 +613,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/cover/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -586,6 +654,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/genre")]
|
||||
[ProducesResponseType(typeof(List<Genre>), StatusCodes.Status200OK)]
|
||||
@@ -623,6 +692,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/companies")]
|
||||
[ProducesResponseType(typeof(List<Dictionary<string, object>>), StatusCodes.Status200OK)]
|
||||
@@ -667,6 +737,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/companies/{CompanyId}")]
|
||||
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
|
||||
@@ -709,6 +780,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/companies/{CompanyId}/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -753,6 +825,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/roms")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
||||
@@ -773,6 +846,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/roms/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
@@ -801,7 +875,9 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/roms/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -829,7 +905,9 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/roms/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -857,8 +935,10 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("{GameId}/roms/{RomId}/file")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -894,8 +974,10 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("{GameId}/roms/{RomId}/{FileName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -931,6 +1013,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/romgroup/{RomGroupId}")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
@@ -959,7 +1042,9 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/romgroup")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -986,7 +1071,9 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/romgroup/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -1014,7 +1101,9 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/romgroup/{RomGroupId}")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -1042,8 +1131,10 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("{GameId}/romgroup/{RomGroupId}/file")]
|
||||
[Route("{GameId}/romgroup/{RomGroupId}/{filename}")]
|
||||
@@ -1089,6 +1180,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("search")]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
@@ -1127,6 +1219,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/screenshots")]
|
||||
[ProducesResponseType(typeof(List<Screenshot>), StatusCodes.Status200OK)]
|
||||
@@ -1157,6 +1250,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/screenshots/{ScreenshotId}")]
|
||||
[ProducesResponseType(typeof(Screenshot), StatusCodes.Status200OK)]
|
||||
@@ -1190,6 +1284,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/screenshots/{ScreenshotId}/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
@@ -1233,6 +1328,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/videos")]
|
||||
[ProducesResponseType(typeof(List<GameVideo>), StatusCodes.Status200OK)]
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -10,9 +11,12 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public class LibraryController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<GameLibrary.LibraryItem>), StatusCodes.Status200OK)]
|
||||
public ActionResult GetLibraries()
|
||||
@@ -21,6 +25,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet("{LibraryId}")]
|
||||
[ProducesResponseType(typeof(GameLibrary.LibraryItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -37,6 +42,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(GameLibrary.LibraryItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
@@ -58,6 +64,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete("{LibraryId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -10,9 +11,12 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public class LogsController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Logging.LogItem> Logs(long? StartIndex, int PageNumber = 1, int PageSize = 100)
|
@@ -12,15 +12,19 @@ using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class PlatformMapsController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<PlatformMapping.PlatformMapItem>), StatusCodes.Status200OK)]
|
||||
public ActionResult GetPlatformMap(bool ResetToDefault = false)
|
||||
@@ -34,6 +38,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}")]
|
||||
[ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
|
||||
@@ -60,10 +65,12 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> UploadPlatformMap(List<IFormFile> files)
|
||||
{
|
||||
Guid sessionid = Guid.NewGuid();
|
||||
@@ -115,6 +122,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
// [MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
// [Route("{PlatformId}")]
|
||||
// [ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
|
||||
@@ -143,10 +151,12 @@ namespace gaseous_server.Controllers
|
||||
// }
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
[Route("{PlatformId}")]
|
||||
[ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public ActionResult EditPlatformMap(long PlatformId, PlatformMapping.PlatformMapItem Map)
|
||||
{
|
||||
try
|
@@ -9,6 +9,7 @@ using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
@@ -17,10 +18,13 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class PlatformsController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<Platform>), StatusCodes.Status200OK)]
|
||||
public ActionResult Platform()
|
||||
@@ -46,6 +50,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}")]
|
||||
[ProducesResponseType(typeof(Platform), StatusCodes.Status200OK)]
|
||||
@@ -72,6 +77,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}/platformlogo")]
|
||||
[ProducesResponseType(typeof(PlatformLogo), StatusCodes.Status200OK)]
|
||||
@@ -105,6 +111,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}/platformlogo/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
@@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
@@ -18,11 +19,15 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class RomsController : ControllerBase
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static gaseous_server.Classes.Metadata.Games;
|
||||
|
||||
@@ -14,6 +15,8 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class SearchController : Controller
|
||||
{
|
||||
private static IGDBClient igdb = new IGDBClient(
|
||||
@@ -23,6 +26,7 @@ namespace gaseous_server.Controllers
|
||||
);
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("Platform")]
|
||||
[ProducesResponseType(typeof(List<Platform>), StatusCodes.Status200OK)]
|
||||
@@ -45,6 +49,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("Game")]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
@@ -6,6 +6,7 @@ using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
@@ -15,6 +16,8 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]/[action]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class SignaturesController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -22,6 +25,7 @@ namespace gaseous_server.Controllers
|
||||
/// </summary>
|
||||
/// <returns>Number of sources, publishers, games, and rom signatures in the database</returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Models.Signatures_Status Status()
|
||||
@@ -30,6 +34,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Models.Signatures_Games> GetSignature(string md5 = "", string sha1 = "")
|
||||
@@ -44,6 +49,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Models.Signatures_Games> GetByTosecName(string TosecName = "")
|
@@ -4,8 +4,11 @@ using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
@@ -13,9 +16,12 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class SystemController : Controller
|
||||
{
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public SystemInfo GetSystemStatus()
|
||||
@@ -56,6 +62,7 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("Version")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
@@ -64,13 +71,30 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("VersionFile")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public FileContentResult GetSystemVersionAsFile() {
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// get age ratings dictionary
|
||||
Dictionary<int, string> AgeRatingsStrings = new Dictionary<int, string>();
|
||||
foreach(IGDB.Models.AgeRatingTitle ageRatingTitle in Enum.GetValues(typeof(IGDB.Models.AgeRatingTitle)) )
|
||||
{
|
||||
AgeRatingsStrings.Add((int)ageRatingTitle, ageRatingTitle.ToString());
|
||||
}
|
||||
|
||||
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
||||
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";";
|
||||
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
||||
"var FirstRunStatus = " + Config.ReadSetting("FirstRunStatus", "0") + ";" + Environment.NewLine +
|
||||
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions{
|
||||
WriteIndented = true
|
||||
}) + ";" + Environment.NewLine +
|
||||
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeRatings.AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions{
|
||||
WriteIndented = true
|
||||
}) + ";";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
||||
return File(bytes, "text/javascript");
|
||||
}
|
78
gaseous-server/Controllers/V1.1/FirstSetupController.cs
Normal file
78
gaseous-server/Controllers/V1.1/FirstSetupController.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class FirstSetupController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public FirstSetupController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Route("0")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> CreateAdminAccount(Authentication.RegisterViewModel model)
|
||||
{
|
||||
if (Config.ReadSetting("FirstRunStatus", "0") == "0")
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
UserName = model.UserName,
|
||||
NormalizedUserName = model.UserName.ToUpper(),
|
||||
Email = model.Email,
|
||||
NormalizedEmail = model.Email.ToUpper(),
|
||||
SecurityProfile = new SecurityProfileViewModel()
|
||||
};
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
await _userManager.AddToRoleAsync(user, "Gamer");
|
||||
await _userManager.AddToRoleAsync(user, "Admin");
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: true);
|
||||
|
||||
Config.SetSetting("FirstRunStatus", "1");
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
413
gaseous-server/Controllers/V1.1/GamesController.cs
Normal file
413
gaseous-server/Controllers/V1.1/GamesController.cs
Normal file
@@ -0,0 +1,413 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class GamesController: ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public GamesController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Game_v1_1(GameSearchModel model)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
// apply security profile filtering
|
||||
List<string> RemoveAgeGroups = new List<string>();
|
||||
switch (user.SecurityProfile.AgeRestrictionPolicy.MaximumAgeRestriction.ToLower())
|
||||
{
|
||||
case "adult":
|
||||
break;
|
||||
case "mature":
|
||||
RemoveAgeGroups.Add("Adult");
|
||||
break;
|
||||
case "teen":
|
||||
RemoveAgeGroups.Add("Adult");
|
||||
RemoveAgeGroups.Add("Mature");
|
||||
break;
|
||||
case "child":
|
||||
RemoveAgeGroups.Add("Adult");
|
||||
RemoveAgeGroups.Add("Mature");
|
||||
RemoveAgeGroups.Add("Teen");
|
||||
break;
|
||||
}
|
||||
foreach (string RemoveAgeGroup in RemoveAgeGroups)
|
||||
{
|
||||
if (model.GameAgeRating.AgeGroupings.Contains(RemoveAgeGroup))
|
||||
{
|
||||
model.GameAgeRating.AgeGroupings.Remove(RemoveAgeGroup);
|
||||
}
|
||||
}
|
||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == false)
|
||||
{
|
||||
model.GameAgeRating.IncludeUnrated = false;
|
||||
}
|
||||
|
||||
return Ok(GetGames(model));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
public class GameSearchModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<string> Platform { get; set; }
|
||||
public List<string> Genre { get; set; }
|
||||
public List<string> GameMode { get; set; }
|
||||
public List<string> PlayerPerspective { get; set; }
|
||||
public List<string> Theme { get; set; }
|
||||
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
|
||||
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
|
||||
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
||||
|
||||
|
||||
public class GameRatingItem
|
||||
{
|
||||
public int MinimumRating { get; set; } = -1;
|
||||
public int MinimumRatingCount { get; set; } = -1;
|
||||
public int MaximumRating { get; set; } = -1;
|
||||
public int MaximumRatingCount { get; set; } = -1;
|
||||
public bool IncludeUnrated { get; set; } = false;
|
||||
}
|
||||
|
||||
public class GameAgeRatingItem
|
||||
{
|
||||
public List<string> AgeGroupings { get; set; } = new List<string>{ "Child", "Teen", "Mature", "Adult" };
|
||||
public bool IncludeUnrated { get; set; } = true;
|
||||
}
|
||||
|
||||
public class GameSortingItem
|
||||
{
|
||||
public SortField SortBy { get; set; } = SortField.NameThe;
|
||||
public bool SortAscending { get; set; } = true;
|
||||
|
||||
public enum SortField
|
||||
{
|
||||
Name,
|
||||
NameThe,
|
||||
Rating,
|
||||
RatingCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Game> GetGames(GameSearchModel model)
|
||||
{
|
||||
string whereClause = "";
|
||||
string havingClause = "";
|
||||
Dictionary<string, object> whereParams = new Dictionary<string, object>();
|
||||
|
||||
List<string> whereClauses = new List<string>();
|
||||
List<string> havingClauses = new List<string>();
|
||||
|
||||
string tempVal = "";
|
||||
|
||||
if (model.Name.Length > 0)
|
||||
{
|
||||
tempVal = "`Name` LIKE @Name";
|
||||
whereParams.Add("@Name", "%" + model.Name + "%");
|
||||
havingClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.GameRating != null)
|
||||
{
|
||||
List<string> ratingClauses = new List<string>();
|
||||
if (model.GameRating.MinimumRating != -1)
|
||||
{
|
||||
string ratingTempMinVal = "totalRating >= @totalMinRating";
|
||||
whereParams.Add("@totalMinRating", model.GameRating.MinimumRating);
|
||||
ratingClauses.Add(ratingTempMinVal);
|
||||
}
|
||||
|
||||
if (model.GameRating.MaximumRating != -1)
|
||||
{
|
||||
string ratingTempMaxVal = "totalRating <= @totalMaxRating";
|
||||
whereParams.Add("@totalMaxRating", model.GameRating.MaximumRating);
|
||||
ratingClauses.Add(ratingTempMaxVal);
|
||||
}
|
||||
|
||||
if (model.GameRating.MinimumRatingCount != -1)
|
||||
{
|
||||
string ratingTempMinCountVal = "totalRatingCount >= @totalMinRatingCount";
|
||||
whereParams.Add("@totalMinRatingCount", model.GameRating.MinimumRatingCount);
|
||||
ratingClauses.Add(ratingTempMinCountVal);
|
||||
}
|
||||
|
||||
if (model.GameRating.MaximumRatingCount != -1)
|
||||
{
|
||||
string ratingTempMaxCountVal = "totalRatingCount <= @totalMaxRatingCount";
|
||||
whereParams.Add("@totalMaxRatingCount", model.GameRating.MaximumRatingCount);
|
||||
ratingClauses.Add(ratingTempMaxCountVal);
|
||||
}
|
||||
|
||||
// generate rating sub clause
|
||||
string ratingClauseValue = "";
|
||||
if (ratingClauses.Count > 0)
|
||||
{
|
||||
foreach (string ratingClause in ratingClauses)
|
||||
{
|
||||
if (ratingClauseValue.Length > 0)
|
||||
{
|
||||
ratingClauseValue += " AND ";
|
||||
}
|
||||
ratingClauseValue += ratingClause;
|
||||
}
|
||||
}
|
||||
|
||||
string unratedClause = "totalRating IS NOT NULL";
|
||||
if (model.GameRating.IncludeUnrated == true)
|
||||
{
|
||||
unratedClause = "totalRating IS NULL";
|
||||
}
|
||||
|
||||
if (ratingClauseValue.Length > 0)
|
||||
{
|
||||
havingClauses.Add("((" + ratingClauseValue + ") OR " + unratedClause + ")");
|
||||
}
|
||||
}
|
||||
|
||||
if (model.Platform.Count > 0)
|
||||
{
|
||||
tempVal = "Games_Roms.PlatformId IN (";
|
||||
for (int i = 0; i < model.Platform.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += ", ";
|
||||
}
|
||||
string platformLabel = "@Platform" + i;
|
||||
tempVal += platformLabel;
|
||||
whereParams.Add(platformLabel, model.Platform[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.Genre.Count > 0)
|
||||
{
|
||||
tempVal = "Relation_Game_Genres.GenresId IN (";
|
||||
for (int i = 0; i < model.Genre.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string genreLabel = "@Genre" + i;
|
||||
tempVal += genreLabel;
|
||||
whereParams.Add(genreLabel, model.Genre[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.GameMode.Count > 0)
|
||||
{
|
||||
tempVal = "Relation_Game_GameModes.GameModesId IN (";
|
||||
for (int i = 0; i < model.GameMode.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string gameModeLabel = "@GameMode" + i;
|
||||
tempVal += gameModeLabel;
|
||||
whereParams.Add(gameModeLabel, model.GameMode[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.PlayerPerspective.Count > 0)
|
||||
{
|
||||
tempVal = "Relation_Game_PlayerPerspectives.PlayerPerspectivesId IN (";
|
||||
for (int i = 0; i < model.PlayerPerspective.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string playerPerspectiveLabel = "@PlayerPerspective" + i;
|
||||
tempVal += playerPerspectiveLabel;
|
||||
whereParams.Add(playerPerspectiveLabel, model.PlayerPerspective[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.Theme.Count > 0)
|
||||
{
|
||||
tempVal = "Relation_Game_Themes.ThemesId IN (";
|
||||
for (int i = 0; i < model.Theme.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string themeLabel = "@Theme" + i;
|
||||
tempVal += themeLabel;
|
||||
whereParams.Add(themeLabel, model.Theme[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (model.GameAgeRating != null)
|
||||
{
|
||||
if (model.GameAgeRating.AgeGroupings.Count > 0)
|
||||
{
|
||||
List<long> AgeClassificationsList = new List<long>();
|
||||
foreach (string ratingGroup in model.GameAgeRating.AgeGroupings)
|
||||
{
|
||||
if (AgeGroups.AgeGroupings.ContainsKey(ratingGroup))
|
||||
{
|
||||
List<AgeGroups.AgeGroupItem> ageGroups = AgeGroups.AgeGroupings[ratingGroup];
|
||||
foreach (AgeGroups.AgeGroupItem ageGroup in ageGroups)
|
||||
{
|
||||
AgeClassificationsList.AddRange(ageGroup.AgeGroupItemValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AgeClassificationsList.Count > 0)
|
||||
{
|
||||
AgeClassificationsList = new HashSet<long>(AgeClassificationsList).ToList();
|
||||
tempVal = "(view_AgeRatings.Rating IN (";
|
||||
for (int i = 0; i < AgeClassificationsList.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += ", ";
|
||||
}
|
||||
string themeLabel = "@Rating" + i;
|
||||
tempVal += themeLabel;
|
||||
whereParams.Add(themeLabel, AgeClassificationsList[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
|
||||
if (model.GameAgeRating.IncludeUnrated == true)
|
||||
{
|
||||
tempVal += " OR view_AgeRatings.Rating IS NULL";
|
||||
}
|
||||
tempVal += ")";
|
||||
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build where clause
|
||||
if (whereClauses.Count > 0)
|
||||
{
|
||||
whereClause = "WHERE ";
|
||||
for (int i = 0; i < whereClauses.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
whereClause += " AND ";
|
||||
}
|
||||
whereClause += whereClauses[i];
|
||||
}
|
||||
}
|
||||
|
||||
// build having clause
|
||||
if (havingClauses.Count > 0)
|
||||
{
|
||||
havingClause = "HAVING ";
|
||||
for (int i = 0; i < havingClauses.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
havingClause += " AND ";
|
||||
}
|
||||
havingClause += havingClauses[i];
|
||||
}
|
||||
}
|
||||
|
||||
// order by clause
|
||||
string orderByField = "NameThe";
|
||||
string orderByOrder = "ASC";
|
||||
if (model.Sorting != null)
|
||||
{
|
||||
switch(model.Sorting.SortBy)
|
||||
{
|
||||
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
||||
orderByField = "NameThe";
|
||||
break;
|
||||
case GameSearchModel.GameSortingItem.SortField.Name:
|
||||
orderByField = "Name";
|
||||
break;
|
||||
case GameSearchModel.GameSortingItem.SortField.Rating:
|
||||
orderByField = "TotalRating";
|
||||
break;
|
||||
case GameSearchModel.GameSortingItem.SortField.RatingCount:
|
||||
orderByField = "TotalRatingCount";
|
||||
break;
|
||||
default:
|
||||
orderByField = "NameThe";
|
||||
break;
|
||||
}
|
||||
|
||||
if (model.Sorting.SortAscending == true)
|
||||
{
|
||||
orderByOrder = "ASC";
|
||||
}
|
||||
else
|
||||
{
|
||||
orderByOrder = "DESC";
|
||||
}
|
||||
}
|
||||
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.*, case when Game.`Name` like 'The %' then CONCAT(trim(substr(Game.`Name` from 4)), ', The') else Game.`Name` end as NameThe FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId LEFT JOIN (SELECT Relation_Game_AgeRatings.GameId, AgeRating.* FROM Relation_Game_AgeRatings JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id) view_AgeRatings ON Game.Id = view_AgeRatings.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
|
||||
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
//RetVal.Add(Classes.Metadata.Games.GetGame((long)dr["ROMGameId"], false, false));
|
||||
RetVal.Add(Classes.Metadata.Games.GetGame(dr));
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
}
|
65
gaseous-server/Controllers/V1.1/RatingsController.cs
Normal file
65
gaseous-server/Controllers/V1.1/RatingsController.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class RatingsController: ControllerBase
|
||||
{
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[Route("Images/{RatingBoard}/{RatingId}/image.svg")]
|
||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult RatingsImageById(string RatingBoard, int RatingId)
|
||||
{
|
||||
IGDB.Models.AgeRatingTitle RatingTitle = (AgeRatingTitle)RatingId;
|
||||
|
||||
string resourceName = "gaseous_server.Assets.Ratings." + RatingBoard + "." + RatingTitle.ToString() + ".svg";
|
||||
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
string[] resources = assembly.GetManifestResourceNames();
|
||||
if (resources.Contains(resourceName))
|
||||
{
|
||||
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
byte[] filedata = new byte[stream.Length];
|
||||
stream.Read(filedata, 0, filedata.Length);
|
||||
|
||||
string filename = RatingBoard + "-" + RatingTitle.ToString() + ".svg";
|
||||
string contentType = "image/svg+xml";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = filename,
|
||||
Inline = true,
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
return File(filedata, contentType);
|
||||
}
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,8 +7,12 @@ using gaseous_server.SignatureIngestors.XML;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
|
||||
Logging.WriteToDiskOnly = true;
|
||||
Logging.Log(Logging.LogType.Information, "Startup", "Starting Gaseous Server " + Assembly.GetExecutingAssembly().GetName().Version);
|
||||
@@ -117,11 +121,14 @@ builder.Services.AddApiVersioning(config =>
|
||||
config.DefaultApiVersion = new ApiVersion(1, 0);
|
||||
config.AssumeDefaultVersionWhenUnspecified = true;
|
||||
config.ReportApiVersions = true;
|
||||
config.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
||||
new HeaderApiVersionReader("x-api-version"),
|
||||
new MediaTypeApiVersionReader("x-api-version"));
|
||||
});
|
||||
builder.Services.AddApiVersioning(setup =>
|
||||
{
|
||||
setup.ApiVersionReader = new UrlSegmentApiVersionReader();
|
||||
});
|
||||
// builder.Services.AddApiVersioning(setup =>
|
||||
// {
|
||||
// setup.ApiVersionReader = new UrlSegmentApiVersionReader();
|
||||
// });
|
||||
builder.Services.AddVersionedApiExplorer(setup =>
|
||||
{
|
||||
setup.GroupNameFormat = "'v'VVV";
|
||||
@@ -166,6 +173,24 @@ builder.Services.AddSwaggerGen(options =>
|
||||
}
|
||||
});
|
||||
|
||||
options.SwaggerDoc("v1.1", new OpenApiInfo
|
||||
{
|
||||
Version = "v1.1",
|
||||
Title = "Gaseous Server API",
|
||||
Description = "An API for managing the Gaseous Server",
|
||||
TermsOfService = new Uri("https://github.com/gaseous-project/gaseous-server"),
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "GitHub Repository",
|
||||
Url = new Uri("https://github.com/gaseous-project/gaseous-server")
|
||||
},
|
||||
License = new OpenApiLicense
|
||||
{
|
||||
Name = "Gaseous Server License",
|
||||
Url = new Uri("https://github.com/gaseous-project/gaseous-server/blob/main/LICENSE")
|
||||
}
|
||||
});
|
||||
|
||||
// using System.Reflection;
|
||||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||
@@ -173,19 +198,115 @@ builder.Services.AddSwaggerGen(options =>
|
||||
);
|
||||
builder.Services.AddHostedService<TimedHostedService>();
|
||||
|
||||
// identity
|
||||
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequiredLength = 10;
|
||||
options.User.AllowedUserNameCharacters = null;
|
||||
options.User.RequireUniqueEmail = true;
|
||||
options.SignIn.RequireConfirmedPhoneNumber = false;
|
||||
options.SignIn.RequireConfirmedEmail = false;
|
||||
options.SignIn.RequireConfirmedAccount = false;
|
||||
})
|
||||
.AddUserStore<UserStore>()
|
||||
.AddRoleStore<RoleStore>()
|
||||
.AddDefaultTokenProviders()
|
||||
.AddDefaultUI()
|
||||
;
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.Cookie.Name = "Gaseous.Identity";
|
||||
options.ExpireTimeSpan = TimeSpan.FromDays(90);
|
||||
options.SlidingExpiration = true;
|
||||
});
|
||||
// builder.Services.AddIdentityCore<ApplicationUser>(options => {
|
||||
// options.SignIn.RequireConfirmedAccount = false;
|
||||
// options.User.RequireUniqueEmail = true;
|
||||
// options.Password.RequireDigit = false;
|
||||
// options.Password.RequiredLength = 10;
|
||||
// options.Password.RequireNonAlphanumeric = false;
|
||||
// options.Password.RequireUppercase = false;
|
||||
// options.Password.RequireLowercase = false;
|
||||
// });
|
||||
builder.Services.AddScoped<UserStore>();
|
||||
builder.Services.AddScoped<RoleStore>();
|
||||
|
||||
builder.Services.AddTransient<IUserStore<ApplicationUser>, UserStore>();
|
||||
builder.Services.AddTransient<IRoleStore<ApplicationRole>, RoleStore>();
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("Admin", policy => policy.RequireRole("Admin"));
|
||||
options.AddPolicy("Gamer", policy => policy.RequireRole("Gamer"));
|
||||
options.AddPolicy("Player", policy => policy.RequireRole("Player"));
|
||||
});
|
||||
|
||||
// builder.Services.AddControllersWithViews(options =>
|
||||
// {
|
||||
// options.Filters.Add(new Microsoft.AspNetCore.Mvc.ValidateAntiForgeryTokenAttribute());
|
||||
// });
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
//if (app.Environment.IsDevelopment())
|
||||
//{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.SwaggerEndpoint($"/swagger/v1/swagger.json", "v1.0");
|
||||
options.SwaggerEndpoint($"/swagger/v1.1/swagger.json", "v1.1");
|
||||
}
|
||||
);
|
||||
//}
|
||||
|
||||
//app.UseHttpsRedirection();
|
||||
|
||||
app.UseResponseCaching();
|
||||
|
||||
// set up system roles
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var roleManager = scope.ServiceProvider.GetRequiredService<RoleStore>();
|
||||
var roles = new[] { "Admin", "Gamer", "Player" };
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
if (await roleManager.FindByNameAsync(role, CancellationToken.None) == null)
|
||||
{
|
||||
ApplicationRole applicationRole = new ApplicationRole();
|
||||
applicationRole.Name = role;
|
||||
applicationRole.NormalizedName = role.ToUpper();
|
||||
await roleManager.CreateAsync(applicationRole, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
// set up administrator account
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserStore>();
|
||||
if (await userManager.FindByNameAsync("admin@localhost", CancellationToken.None) == null)
|
||||
{
|
||||
ApplicationUser adminUser = new ApplicationUser{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Email = "admin@localhost",
|
||||
NormalizedEmail = "ADMIN@LOCALHOST",
|
||||
EmailConfirmed = true,
|
||||
UserName = "administrator",
|
||||
NormalizedUserName = "ADMINISTRATOR"
|
||||
};
|
||||
|
||||
//set user password
|
||||
PasswordHasher<ApplicationUser> ph = new PasswordHasher<ApplicationUser>();
|
||||
adminUser.PasswordHash = ph.HashPassword(adminUser, "letmein");
|
||||
|
||||
await userManager.CreateAsync(adminUser, CancellationToken.None);
|
||||
await userManager.AddToRoleAsync(adminUser, "Admin", CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseDefaultFiles();
|
||||
@@ -197,6 +318,72 @@ app.UseStaticFiles(new StaticFileOptions
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
// emergency password recovery if environment variable is set
|
||||
// process:
|
||||
// - set the environment variable "recoveraccount" to the email address of the account to be recovered
|
||||
// - when the server starts the password will be reset to a random string and saved in the library
|
||||
// directory with the name RecoverAccount.txt
|
||||
// - user should copy this password and remove the "recoveraccount" environment variable and the
|
||||
// RecoverAccount.txt file
|
||||
// - the server will not start while the RecoverAccount.txt file exists
|
||||
string PasswordRecoveryFile = Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "RecoverAccount.txt");
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("recoveraccount")))
|
||||
{
|
||||
if (File.Exists(PasswordRecoveryFile))
|
||||
{
|
||||
// password has already been set - do nothing and just exit
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Unable to start while recoveraccount environment varibale is set and RecoverAccount.txt file exists.", null, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// generate and save the password to disk
|
||||
int length = 10;
|
||||
string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+";
|
||||
var random = new Random();
|
||||
string password = new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
|
||||
File.WriteAllText(PasswordRecoveryFile, password);
|
||||
|
||||
// reset the password
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserStore>();
|
||||
if (await userManager.FindByNameAsync(Environment.GetEnvironmentVariable("recoveraccount"), CancellationToken.None) != null)
|
||||
{
|
||||
ApplicationUser User = await userManager.FindByEmailAsync(Environment.GetEnvironmentVariable("recoveraccount"), CancellationToken.None);
|
||||
|
||||
//set user password
|
||||
PasswordHasher<ApplicationUser> ph = new PasswordHasher<ApplicationUser>();
|
||||
User.PasswordHash = ph.HashPassword(User, password);
|
||||
|
||||
await userManager.SetPasswordHashAsync(User, User.PasswordHash, CancellationToken.None);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Server Startup", "Password reset complete, remove the recoveraccount environment variable and RecoverAccount.text file to allow server start.", null, true);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Account to recover not found.", null, true);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if RecoverAccount.text file is present
|
||||
if (File.Exists(PasswordRecoveryFile))
|
||||
{
|
||||
// cannot start while password recovery file exists
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Unable to start while RecoverAccount.txt file exists. Remove the file and try again.", null, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// setup library directories
|
||||
Config.LibraryConfiguration.InitLibrary();
|
||||
|
||||
|
585
gaseous-server/Reference/OldAccountController.cs.bak
Normal file
585
gaseous-server/Reference/OldAccountController.cs.bak
Normal file
@@ -0,0 +1,585 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("Account")]
|
||||
[Authorize]
|
||||
public class OldAccountController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OldAccountController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_logger = loggerFactory.CreateLogger<OldAccountController>();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Login
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("Login")]
|
||||
public IActionResult Login(string returnUrl = null)
|
||||
{
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Login
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("Login")]
|
||||
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
|
||||
{
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// This doesn't count login failures towards account lockout
|
||||
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation(1, "User logged in.");
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning(2, "User account locked out.");
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Register
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("Register")]
|
||||
public IActionResult Register(string returnUrl = null)
|
||||
{
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Register
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("Register")]
|
||||
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
|
||||
{
|
||||
// ViewData["ReturnUrl"] = returnUrl;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
UserName = model.UserName,
|
||||
NormalizedUserName = model.UserName.ToUpper(),
|
||||
Email = model.Email,
|
||||
NormalizedEmail = model.Email.ToUpper()
|
||||
};
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
|
||||
// Send an email with this link
|
||||
//var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||
//await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
|
||||
// "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
|
||||
|
||||
// add all users to the member role
|
||||
await _userManager.AddToRoleAsync(user, "Player");
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(3, "User created a new account with password.");
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/LogOff
|
||||
[HttpPost]
|
||||
[Route("LogOff")]
|
||||
public async Task<IActionResult> LogOff()
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
_logger.LogInformation(4, "User logged out.");
|
||||
//return RedirectToAction(nameof(HomeController.Index), "Home");
|
||||
return Ok();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLogin
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("ExternalLogin")]
|
||||
public IActionResult ExternalLogin(string provider, string returnUrl = null)
|
||||
{
|
||||
// Request a redirect to the external login provider.
|
||||
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
|
||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
|
||||
return Challenge(properties, provider);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginCallback
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ExternalLoginCallback")]
|
||||
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
|
||||
{
|
||||
if (remoteError != null)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
|
||||
return View(nameof(Login));
|
||||
}
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||
if (info == null)
|
||||
{
|
||||
return RedirectToAction(nameof(Login));
|
||||
}
|
||||
|
||||
// Sign in the user with this external login provider if the user already has a login.
|
||||
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
// Update any authentication tokens if login succeeded
|
||||
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
|
||||
|
||||
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the user does not have an account, then ask the user to create an account.
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
ViewData["ProviderDisplayName"] = info.ProviderDisplayName;
|
||||
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
|
||||
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLoginConfirmation
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("ExternalLoginConfirmation")]
|
||||
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// Get the information about the user from the external login provider
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||
if (info == null)
|
||||
{
|
||||
return View("ExternalLoginFailure");
|
||||
}
|
||||
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
|
||||
var result = await _userManager.CreateAsync(user);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
result = await _userManager.AddLoginAsync(user, info);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
|
||||
|
||||
// Update any authentication tokens as well
|
||||
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
|
||||
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// GET: /Account/ConfirmEmail
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ConfirmEmail")]
|
||||
public async Task<IActionResult> ConfirmEmail(string userId, string code)
|
||||
{
|
||||
if (userId == null || code == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var result = await _userManager.ConfirmEmailAsync(user, code);
|
||||
return View(result.Succeeded ? "ConfirmEmail" : "Error");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPassword
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ForgotPassword")]
|
||||
public IActionResult ForgotPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ForgotPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("ForgotPassword")]
|
||||
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
|
||||
{
|
||||
// Don't reveal that the user does not exist or is not confirmed
|
||||
return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
|
||||
// Send an email with this link
|
||||
//var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
//var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||
//await _emailSender.SendEmailAsync(model.Email, "Reset Password",
|
||||
// "Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
|
||||
//return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPasswordConfirmation
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ForgotPasswordConfirmation")]
|
||||
public IActionResult ForgotPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPassword
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ResetPassword")]
|
||||
public IActionResult ResetPassword(string code = null)
|
||||
{
|
||||
return code == null ? View("Error") : View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ResetPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("ResetPassword")]
|
||||
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (user == null)
|
||||
{
|
||||
// Don't reveal that the user does not exist
|
||||
return RedirectToAction(nameof(OldAccountController.ResetPasswordConfirmation), "Account");
|
||||
}
|
||||
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToAction(nameof(OldAccountController.ResetPasswordConfirmation), "Account");
|
||||
}
|
||||
AddErrors(result);
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPasswordConfirmation
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("ResetPasswordConfirmation")]
|
||||
public IActionResult ResetPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/SendCode
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("SendCode")]
|
||||
public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
|
||||
{
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
|
||||
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
|
||||
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/SendCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("SendCode")]
|
||||
public async Task<IActionResult> SendCode(SendCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
if (model.SelectedProvider == "Authenticator")
|
||||
{
|
||||
return RedirectToAction(nameof(VerifyAuthenticatorCode), new { ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
|
||||
// Generate the token and send it
|
||||
var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
var message = "Your security code is: " + code;
|
||||
if (model.SelectedProvider == "Email")
|
||||
{
|
||||
await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message);
|
||||
}
|
||||
// else if (model.SelectedProvider == "Phone")
|
||||
// {
|
||||
// await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message);
|
||||
// }
|
||||
|
||||
return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/VerifyCode
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("VerifyCode")]
|
||||
public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
|
||||
{
|
||||
// Require that the user has already logged in via username/password or external login
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/VerifyCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("VerifyCode")]
|
||||
public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// The following code protects for brute force attacks against the two factor codes.
|
||||
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||
// will be locked out for a specified amount of time.
|
||||
var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning(7, "User account locked out.");
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/VerifyAuthenticatorCode
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("VerifyAuthenticatorCode")]
|
||||
public async Task<IActionResult> VerifyAuthenticatorCode(bool rememberMe, string returnUrl = null)
|
||||
{
|
||||
// Require that the user has already logged in via username/password or external login
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return View(new VerifyAuthenticatorCodeViewModel { ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/VerifyAuthenticatorCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("VerifyAuthenticatorCode")]
|
||||
public async Task<IActionResult> VerifyAuthenticatorCode(VerifyAuthenticatorCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// The following code protects for brute force attacks against the two factor codes.
|
||||
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||
// will be locked out for a specified amount of time.
|
||||
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.Code, model.RememberMe, model.RememberBrowser);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning(7, "User account locked out.");
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/UseRecoveryCode
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[Route("UseRecoveryCode")]
|
||||
public async Task<IActionResult> UseRecoveryCode(string returnUrl = null)
|
||||
{
|
||||
// Require that the user has already logged in via username/password or external login
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return View(new UseRecoveryCodeViewModel { ReturnUrl = returnUrl });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/UseRecoveryCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[Route("UseRecoveryCode")]
|
||||
public async Task<IActionResult> UseRecoveryCode(UseRecoveryCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return _userManager.GetUserAsync(HttpContext.User);
|
||||
}
|
||||
|
||||
private IActionResult RedirectToLocal(string returnUrl)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Redirect("/");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
383
gaseous-server/Reference/OldManageController.cs.bak
Normal file
383
gaseous-server/Reference/OldManageController.cs.bak
Normal file
@@ -0,0 +1,383 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("Manage")]
|
||||
[Authorize]
|
||||
public class OldManageController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OldManageController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_logger = loggerFactory.CreateLogger<OldManageController>();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/Index
|
||||
[HttpGet]
|
||||
[Route("Index")]
|
||||
public async Task<IActionResult> Index(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||
: "";
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
var model = new IndexViewModel
|
||||
{
|
||||
HasPassword = await _userManager.HasPasswordAsync(user),
|
||||
PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
|
||||
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
|
||||
Logins = await _userManager.GetLoginsAsync(user),
|
||||
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user),
|
||||
AuthenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user)
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RemoveLogin
|
||||
[HttpPost]
|
||||
[Route("RemoveLogin")]
|
||||
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
|
||||
{
|
||||
ManageMessageId? message = ManageMessageId.Error;
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/AddPhoneNumber
|
||||
[HttpGet]
|
||||
[Route("AddPhoneNumber")]
|
||||
public IActionResult AddPhoneNumber()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/AddPhoneNumber
|
||||
[HttpPost]
|
||||
[Route("AddPhoneNumber")]
|
||||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
// Generate the token and send it
|
||||
var user = await GetCurrentUserAsync();
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
|
||||
//await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
|
||||
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/ResetAuthenticatorKey
|
||||
[HttpPost]
|
||||
[Route("ResetAuthenticatorKey")]
|
||||
public async Task<IActionResult> ResetAuthenticatorKey()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.ResetAuthenticatorKeyAsync(user);
|
||||
_logger.LogInformation(1, "User reset authenticator key.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/GenerateRecoveryCode
|
||||
[HttpPost]
|
||||
[Route("GenerateRecoveryCode")]
|
||||
public async Task<IActionResult> GenerateRecoveryCode()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var codes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 5);
|
||||
_logger.LogInformation(1, "User generated new recovery code.");
|
||||
return View("DisplayRecoveryCodes", new DisplayRecoveryCodesViewModel { Codes = codes });
|
||||
}
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/EnableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[Route("EnableTwoFactorAuthentication")]
|
||||
public async Task<IActionResult> EnableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(1, "User enabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/DisableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[Route("DisableTwoFactorAuthentication")]
|
||||
public async Task<IActionResult> DisableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, false);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(2, "User disabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/VerifyPhoneNumber
|
||||
[HttpGet]
|
||||
[Route("VerifyPhoneNumber")]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
|
||||
{
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber);
|
||||
// Send an SMS to verify the phone number
|
||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/VerifyPhoneNumber
|
||||
[HttpPost]
|
||||
[Route("VerifyPhoneNumber")]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
|
||||
}
|
||||
}
|
||||
// If we got this far, something failed, redisplay the form
|
||||
ModelState.AddModelError(string.Empty, "Failed to verify phone number");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/RemovePhoneNumber
|
||||
[HttpPost]
|
||||
[Route("RemovePhoneNumber")]
|
||||
public async Task<IActionResult> RemovePhoneNumber()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.SetPhoneNumberAsync(user, null);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/ChangePassword
|
||||
[HttpGet]
|
||||
[Route("ChangePassword")]
|
||||
public IActionResult ChangePassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/ChangePassword
|
||||
[HttpPost]
|
||||
[Route("ChangePassword")]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(3, "User changed their password successfully.");
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/SetPassword
|
||||
[HttpGet]
|
||||
[Route("SetPassword")]
|
||||
public IActionResult SetPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/SetPassword
|
||||
[HttpPost]
|
||||
[Route("SetPassword")]
|
||||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//GET: /Manage/ManageLogins
|
||||
[HttpGet]
|
||||
[Route("ManageLogins")]
|
||||
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
: message == ManageMessageId.AddLoginSuccess ? "The external login was added."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: "";
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userLogins = await _userManager.GetLoginsAsync(user);
|
||||
var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
|
||||
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();
|
||||
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
|
||||
return View(new ManageLoginsViewModel
|
||||
{
|
||||
CurrentLogins = userLogins,
|
||||
OtherLogins = otherLogins
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/LinkLogin
|
||||
[HttpPost]
|
||||
[Route("LinkLogin")]
|
||||
public IActionResult LinkLogin(string provider)
|
||||
{
|
||||
// Request a redirect to the external login provider to link a login for the current user
|
||||
var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
|
||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
|
||||
return Challenge(properties, provider);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/LinkLoginCallback
|
||||
[HttpGet]
|
||||
[Route("LinkLoginCallback")]
|
||||
public async Task<ActionResult> LinkLoginCallback()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
|
||||
if (info == null)
|
||||
{
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
var result = await _userManager.AddLoginAsync(user, info);
|
||||
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
AddPhoneSuccess,
|
||||
AddLoginSuccess,
|
||||
ChangePasswordSuccess,
|
||||
SetTwoFactorSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
RemovePhoneSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return _userManager.GetUserAsync(HttpContext.User);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
54
gaseous-server/Support/Database/MySQL/gaseous-1005.sql
Normal file
54
gaseous-server/Support/Database/MySQL/gaseous-1005.sql
Normal file
@@ -0,0 +1,54 @@
|
||||
CREATE TABLE `roles` (
|
||||
`Id` varchar(128) NOT NULL,
|
||||
`Name` varchar(256) NOT NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`Id` varchar(128) NOT NULL,
|
||||
`Email` varchar(256) DEFAULT NULL,
|
||||
`EmailConfirmed` tinyint(1) NOT NULL,
|
||||
`NormalizedEmail` varchar(256) DEFAULT NULL,
|
||||
`PasswordHash` longtext,
|
||||
`SecurityStamp` longtext,
|
||||
`ConcurrencyStamp` longtext,
|
||||
`PhoneNumber` longtext,
|
||||
`PhoneNumberConfirmed` tinyint(1) NOT NULL,
|
||||
`TwoFactorEnabled` tinyint(1) NOT NULL,
|
||||
`LockoutEnd` datetime DEFAULT NULL,
|
||||
`LockoutEnabled` tinyint(1) NOT NULL,
|
||||
`AccessFailedCount` int(11) NOT NULL,
|
||||
`UserName` varchar(256) NOT NULL,
|
||||
`NormalizedUserName` varchar(256) NOT NULL,
|
||||
`SecurityProfile` longtext,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `userclaims` (
|
||||
`Id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`UserId` varchar(128) NOT NULL,
|
||||
`ClaimType` longtext,
|
||||
`ClaimValue` longtext,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `Id` (`Id`),
|
||||
KEY `UserId` (`UserId`),
|
||||
CONSTRAINT `ApplicationUser_Claims` FOREIGN KEY (`UserId`) REFERENCES `users` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
CREATE TABLE `userlogins` (
|
||||
`LoginProvider` varchar(128) NOT NULL,
|
||||
`ProviderKey` varchar(128) NOT NULL,
|
||||
`UserId` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`LoginProvider`,`ProviderKey`,`UserId`),
|
||||
KEY `ApplicationUser_Logins` (`UserId`),
|
||||
CONSTRAINT `ApplicationUser_Logins` FOREIGN KEY (`UserId`) REFERENCES `users` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
CREATE TABLE `userroles` (
|
||||
`UserId` varchar(128) NOT NULL,
|
||||
`RoleId` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`UserId`,`RoleId`),
|
||||
KEY `IdentityRole_Users` (`RoleId`),
|
||||
CONSTRAINT `ApplicationUser_Roles` FOREIGN KEY (`UserId`) REFERENCES `users` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION,
|
||||
CONSTRAINT `IdentityRole_Users` FOREIGN KEY (`RoleId`) REFERENCES `roles` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ;
|
@@ -20,9 +20,11 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="gaseous-signature-parser" Version="2.0.0" />
|
||||
<PackageReference Include="gaseous.IGDB" Version="1.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.2.7" />
|
||||
@@ -43,6 +45,7 @@
|
||||
<None Remove="Support\Database\MySQL\gaseous-1002.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1003.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1004.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1005.sql" />
|
||||
<None Remove="Classes\Metadata\" />
|
||||
<None Remove="Assets\" />
|
||||
<None Remove="Assets\Ratings\" />
|
||||
@@ -114,6 +117,7 @@
|
||||
<Folder Include="Assets\Ratings\USK\" />
|
||||
<Folder Include="Assets\Ratings\GRAC\" />
|
||||
<Folder Include="Assets\Ratings\CLASS_IND\" />
|
||||
<Folder Remove="Reference" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wwwroot\**">
|
||||
@@ -169,5 +173,6 @@
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1003.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1004.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1005.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
BIN
gaseous-server/wwwroot/.DS_Store
vendored
Binary file not shown.
BIN
gaseous-server/wwwroot/images/LoginWallpaper.jpg
Normal file
BIN
gaseous-server/wwwroot/images/LoginWallpaper.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 592 KiB |
5
gaseous-server/wwwroot/images/tick.svg
Normal file
5
gaseous-server/wwwroot/images/tick.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" version="1.1" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="m14.25 8.75c-.5 2.5-2.3849 4.85363-5.03069 5.37991-2.64578.5263-5.33066-.7044-6.65903-3.0523-1.32837-2.34784-1.00043-5.28307.81336-7.27989 1.81379-1.99683 4.87636-2.54771 7.37636-1.54771"/>
|
||||
<polyline points="5.75 7.75,8.25 10.25,14.25 3.75"/>
|
||||
</svg>
|
After Width: | Height: | Size: 579 B |
5
gaseous-server/wwwroot/images/user.svg
Normal file
5
gaseous-server/wwwroot/images/user.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 7C16 9.20914 14.2091 11 12 11C9.79086 11 8 9.20914 8 7C8 4.79086 9.79086 3 12 3C14.2091 3 16 4.79086 16 7Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 14C8.13401 14 5 17.134 5 21H19C19 17.134 15.866 14 12 14Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 590 B |
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.0/System/VersionFile"></script>
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
<link type="text/css" rel="stylesheet" dat-href="/styles/style.css" />
|
||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
||||
<script src="/scripts/moment.js"></script>
|
||||
@@ -38,6 +38,8 @@
|
||||
head.appendChild(newLink);
|
||||
}
|
||||
}
|
||||
|
||||
var userProfile;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -45,24 +47,35 @@
|
||||
<img src="/images/logo.png" alt="Gaseous" id="banner_icon_image" />
|
||||
</div>
|
||||
<div id="banner_header">
|
||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';" class="banner_button">
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" class="banner_button_image" />
|
||||
<span id="banner_system_label">Settings</span>
|
||||
</div>
|
||||
<div id="bannerButtons">
|
||||
<div id="banner_user" onclick="showMenu();" class="banner_button dropdown dropbtn">
|
||||
<img src="/images/user.svg" alt="Account" title="Account" id="banner_user_image" class="banner_button_image" style="position: relative; top: 10px; right: 0px; pointer-events: none;" onclick="showMenu();" />
|
||||
<div id="myDropdown" class="dropdown-content">
|
||||
<div id="banner_user_roles"></div>
|
||||
<a href="#" onclick="showDialog('userprofile');">Profile</a>
|
||||
<a href="#" onclick="userLogoff();">Sign Out</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';" class="banner_button">
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" class="banner_button_image" />
|
||||
<span id="banner_system_label">Settings</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_upload" onclick="showDialog('upload');" class="banner_button">
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image" class="banner_button_image" />
|
||||
<span id="banner_upload_label">Upload</span>
|
||||
</div>
|
||||
<div id="banner_upload" onclick="showDialog('upload');" class="banner_button">
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image" class="banner_button_image" />
|
||||
<span id="banner_upload_label">Upload</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_collections" onclick="window.location.href = '/index.html?page=collections';" class="banner_button">
|
||||
<img src="/images/collections.svg" alt="Collections" title="Collections" id="banner_collections_image" class="banner_button_image" />
|
||||
<span id="banner_collections_label">Collections</span>
|
||||
</div>
|
||||
<div id="banner_collections" onclick="window.location.href = '/index.html?page=collections';" class="banner_button">
|
||||
<img src="/images/collections.svg" alt="Collections" title="Collections" id="banner_collections_image" class="banner_button_image" />
|
||||
<span id="banner_collections_label">Collections</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_library" onclick="window.location.href = '/index.html';" class="banner_button">
|
||||
<img src="/images/library.svg" alt="Library" title="Library" id="banner_library_image" class="banner_button_image" />
|
||||
<span id="banner_library_label">Library</span>
|
||||
<div id="banner_library" onclick="window.location.href = '/index.html';" class="banner_button">
|
||||
<img src="/images/library.svg" alt="Library" title="Library" id="banner_library_image" class="banner_button_image" />
|
||||
<span id="banner_library_label">Library</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous Games</div>
|
||||
@@ -96,18 +109,74 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">var modalVariables = null;
|
||||
|
||||
<script type="text/javascript">
|
||||
var modalVariables = null;
|
||||
|
||||
$(document).ready(function () {
|
||||
var myParam = getQueryString('page', 'string');
|
||||
// redirect if first run status = 0
|
||||
if (FirstRunStatus == 0) {
|
||||
window.location.replace("/pages/first.html");
|
||||
}
|
||||
|
||||
if (!myParam) {
|
||||
myParam = 'home';
|
||||
// redirect if not logged in
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Profile/Basic',
|
||||
'GET',
|
||||
function(result) {
|
||||
console.log("User is logged in");
|
||||
userProfile = result;
|
||||
|
||||
// hide the upload button if it's not permitted
|
||||
var uploadButton = document.getElementById('banner_upload');
|
||||
if (!userProfile.roles.includes("Admin") && !userProfile.roles.includes("Gamer")) {
|
||||
uploadButton.style.display = 'none';
|
||||
}
|
||||
|
||||
// populate page
|
||||
var myParam = getQueryString('page', 'string');
|
||||
|
||||
if (!myParam) {
|
||||
myParam = 'home';
|
||||
}
|
||||
|
||||
$('#content').load('/pages/' + myParam + '.html?v=' + AppVersion);
|
||||
},
|
||||
function(error) {
|
||||
window.location.replace("/pages/login.html");
|
||||
}
|
||||
);
|
||||
|
||||
$('#content').load('/pages/' + myParam + '.html?v=' + AppVersion);
|
||||
});
|
||||
/* When the user clicks on the button,
|
||||
toggle between hiding and showing the dropdown content */
|
||||
function showMenu() {
|
||||
document.getElementById("myDropdown").classList.toggle("show");
|
||||
}
|
||||
|
||||
// Close the dropdown menu if the user clicks outside of it
|
||||
window.onclick = function(event) {
|
||||
if (!event.target.matches('.dropbtn')) {
|
||||
var dropdowns = document.getElementsByClassName("dropdown-content");
|
||||
var i;
|
||||
for (i = 0; i < dropdowns.length; i++) {
|
||||
var openDropdown = dropdowns[i];
|
||||
if (openDropdown.classList.contains('show')) {
|
||||
openDropdown.classList.remove('show');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function userLogoff() {
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/LogOff',
|
||||
'POST',
|
||||
function (result) {
|
||||
location.replace("/index.html");
|
||||
},
|
||||
function (error) {
|
||||
location.replace("/index.html");
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -17,10 +17,17 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var newCollectionButton = document.getElementById('collection_new');
|
||||
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
||||
newCollectionButton.style.display = '';
|
||||
} else {
|
||||
newCollectionButton.style.display = 'none';
|
||||
}
|
||||
|
||||
GetCollections();
|
||||
|
||||
function GetCollections() {
|
||||
ajaxCall('/api/v1.0/Collections', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Collections', 'GET', function (result) {
|
||||
if (result) {
|
||||
var targetDiv = document.getElementById('collection_table_location');
|
||||
targetDiv.innerHTML = '';
|
||||
@@ -47,7 +54,7 @@
|
||||
break;
|
||||
case "Completed":
|
||||
statusText = 'Available';
|
||||
downloadLink = '<a href="/api/v1.0/Collections/' + result[i].id + '/Roms/Zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||
downloadLink = '<a href="/api/v1.1/Collections/' + result[i].id + '/Roms/Zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||
packageSize = formatBytes(result[i].collectionBuiltSizeBytes);
|
||||
break;
|
||||
case "Failed":
|
||||
@@ -58,9 +65,14 @@
|
||||
break;
|
||||
}
|
||||
|
||||
var editButton = '<a href="#" onclick="showDialog(\'collectionedit\', ' + result[i].id + ');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
||||
var editButton = '';
|
||||
var deleteButton = '';
|
||||
|
||||
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
||||
editButton = '<a href="#" onclick="showDialog(\'collectionedit\', ' + result[i].id + ');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
||||
|
||||
var deleteButton = '<a href="#" onclick="showSubDialog(\'collectiondelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
||||
deleteButton = '<a href="#" onclick="showSubDialog(\'collectiondelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
||||
}
|
||||
|
||||
var newRow = [
|
||||
result[i].name,
|
||||
|
@@ -24,7 +24,7 @@
|
||||
|
||||
$('#collection_addgame').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Collections',
|
||||
url: '/api/v1.1/Collections',
|
||||
placeholder: 'Select collection',
|
||||
processResults: function (data) {
|
||||
var arr = [];
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
if (CollectionId != 0) {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections/' + CollectionId + '/AlwaysInclude' + RebuildCollection,
|
||||
'/api/v1.1/Collections/' + CollectionId + '/AlwaysInclude' + RebuildCollection,
|
||||
'PATCH',
|
||||
function (result) {
|
||||
closeSubDialog();
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<script type="text/javascript">
|
||||
function deleteCollection() {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections/' + subModalVariables,
|
||||
'/api/v1.1/Collections/' + subModalVariables,
|
||||
'DELETE',
|
||||
function (result) {
|
||||
GetCollections();
|
||||
|
@@ -136,7 +136,7 @@
|
||||
// setup dropdowns
|
||||
$('#collection_platform').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['platforms'];
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
$('#collection_genres').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['genres'];
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
|
||||
$('#collection_players').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['gamemodes'];
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
|
||||
$('#collection_playerperspectives').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['playerperspectives'];
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
|
||||
$('#collection_themes').select2({
|
||||
ajax: {
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['themes'];
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
|
||||
// edit mode
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections/' + modalVariables,
|
||||
'/api/v1.1/Collections/' + modalVariables,
|
||||
'GET',
|
||||
function(result) {
|
||||
if (result.name) { document.getElementById('collection_name').value = result.name; }
|
||||
@@ -278,7 +278,7 @@
|
||||
// fill select2 controls
|
||||
$.ajax(
|
||||
{
|
||||
url: '/api/v1.0/Filter',
|
||||
url: '/api/v1.1/Filter',
|
||||
type: 'GET',
|
||||
indexValue: result,
|
||||
dataType: 'json',
|
||||
@@ -344,7 +344,7 @@
|
||||
// existing object - save over the top
|
||||
item.id = modalVariables;
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections/' + modalVariables,
|
||||
'/api/v1.1/Collections/' + modalVariables,
|
||||
'PATCH',
|
||||
function(result) {
|
||||
location.reload();
|
||||
@@ -357,7 +357,7 @@
|
||||
} else {
|
||||
// new object
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections',
|
||||
'/api/v1.1/Collections',
|
||||
'POST',
|
||||
function(result) {
|
||||
location.reload();
|
||||
@@ -426,7 +426,7 @@
|
||||
var item = GenerateCollectionItem();
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/Collections/Preview',
|
||||
'/api/v1.1/Collections/Preview',
|
||||
'POST',
|
||||
function(result) {
|
||||
DisplayPreview(result, 'collectionedit_previewbox_content');
|
||||
@@ -579,7 +579,7 @@
|
||||
var gameImage = document.createElement('img');
|
||||
gameImage.className = 'game_tile_image game_tile_image_small';
|
||||
if (gameItem.cover) {
|
||||
gameImage.src = '/api/v1.0/Games/' + gameItem.id + '/cover/image';
|
||||
gameImage.src = '/api/v1.1/Games/' + gameItem.id + '/cover/image';
|
||||
} else {
|
||||
gameImage.src = '/images/unknowngame.png';
|
||||
gameImage.className = 'game_tile_image game_tile_image_small unknown';
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<script type="text/javascript">
|
||||
function deleteLibrary() {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Library/' + subModalVariables,
|
||||
'/api/v1.1/Library/' + subModalVariables,
|
||||
'DELETE',
|
||||
function (result) {
|
||||
drawLibrary();
|
||||
|
@@ -32,7 +32,7 @@
|
||||
$('#newlibrary_defaultplatform').select2({
|
||||
minimumInputLength: 3,
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Platform',
|
||||
url: '/api/v1.1/Search/Platform',
|
||||
data: function (params) {
|
||||
var query = {
|
||||
SearchString: params.term
|
||||
@@ -76,7 +76,7 @@
|
||||
alert("A path must be provided.");
|
||||
} else {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Library?Name=' + encodeURIComponent(libName) + '&DefaultPlatformId=' + libPlatform[0].id + '&Path=' + encodeURIComponent(libPath),
|
||||
'/api/v1.1/Library?Name=' + encodeURIComponent(libName) + '&DefaultPlatformId=' + libPlatform[0].id + '&Path=' + encodeURIComponent(libPath),
|
||||
'POST',
|
||||
function(result) {
|
||||
drawLibrary();
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<script type="text/javascript">
|
||||
function deleteCollection() {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Games/' + gameData.id + '/romgroup/' + subModalVariables,
|
||||
'/api/v1.1/Games/' + gameData.id + '/romgroup/' + subModalVariables,
|
||||
'DELETE',
|
||||
function (result) {
|
||||
loadRoms();
|
||||
|
@@ -105,7 +105,7 @@
|
||||
DisplayWebEmulatorContent(false);
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/PlatformMaps/' + modalVariables,
|
||||
'/api/v1.1/PlatformMaps/' + modalVariables,
|
||||
'GET',
|
||||
function (result) {
|
||||
// set heading
|
||||
@@ -338,7 +338,7 @@
|
||||
console.log(JSON.stringify(item));
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/PlatformMaps/' + modalVariables,
|
||||
'/api/v1.1/PlatformMaps/' + modalVariables,
|
||||
'PATCH',
|
||||
function (result) {
|
||||
loadPlatformMapping();
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
function deleteRom() {
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms/' + modalVariables, 'DELETE', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables, 'DELETE', function (result) {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
@@ -118,7 +118,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms/' + modalVariables, 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables, 'GET', function (result) {
|
||||
romData = result;
|
||||
document.getElementById('modal-heading').innerHTML = result.name;
|
||||
document.getElementById('rominfo_library').innerHTML = result.library.name;
|
||||
@@ -169,7 +169,7 @@
|
||||
$('#properties_fixplatform').select2({
|
||||
minimumInputLength: 3,
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Platform',
|
||||
url: '/api/v1.1/Search/Platform',
|
||||
data: function (params) {
|
||||
var query = {
|
||||
SearchString: params.term
|
||||
@@ -200,7 +200,7 @@
|
||||
minimumInputLength: 3,
|
||||
templateResult: DropDownRenderGameOption,
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Game',
|
||||
url: '/api/v1.1/Search/Game',
|
||||
data: function (params) {
|
||||
fixplatform = $('#properties_fixplatform').select2('data');
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
|
||||
document.getElementById('properties_fixsave').setAttribute("disabled", "disabled");
|
||||
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
29
gaseous-server/wwwroot/pages/dialogs/settingsuserdelete.html
Normal file
29
gaseous-server/wwwroot/pages/dialogs/settingsuserdelete.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<p>Are you sure you want to delete the selected user?</p>
|
||||
<p><strong>Warning:</strong> This cannot be undone!</p>
|
||||
<div style="width: 100%; text-align: center;">
|
||||
<div style="display: inline-block; margin-right: 20px;">
|
||||
<button class="redbutton" value="Delete" onclick="deleteUserCallback();">Delete</button>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-left: 20px;">
|
||||
<button value="Cancel" onclick="closeSubDialog();">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function deleteUserCallback() {
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Users/' + subModalVariables,
|
||||
'DELETE',
|
||||
function(result) {
|
||||
console.log('Deleted user');
|
||||
GetUsers();
|
||||
closeSubDialog();
|
||||
},
|
||||
function(error) {
|
||||
console.log(JSON.stringify(error));
|
||||
GetUsers();
|
||||
closeSubDialog();
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
375
gaseous-server/wwwroot/pages/dialogs/settingsuseredit.html
Normal file
375
gaseous-server/wwwroot/pages/dialogs/settingsuseredit.html
Normal file
@@ -0,0 +1,375 @@
|
||||
<div id="properties_toc">
|
||||
<div id="properties_user_toc_password" name="properties_user_toc_item" onclick="UserSelectTab('password');">Password</div>
|
||||
<div id="properties_user_toc_role" name="properties_user_toc_item" onclick="UserSelectTab('role');">Role</div>
|
||||
<div id="properties_user_toc_age" name="properties_user_toc_item" onclick="UserSelectTab('age');">Content Restrictions</div>
|
||||
<!--<div id="properties_toc_manage" name="properties_toc_item" onclick="SelectTab('manage');">Manage</div>-->
|
||||
</div>
|
||||
|
||||
<div id="properties_bodypanel" style="height: 450px; overflow-y: scroll;">
|
||||
<div id="properties_bodypanel_password" name="properties_user_tab" style="display: none;">
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<th>
|
||||
Password
|
||||
</th>
|
||||
<td>
|
||||
<input type="password" id="settings_users_edit_password" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Confirm password
|
||||
</th>
|
||||
<td>
|
||||
<input type="password" id="settings_users_edit_confirmpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="settings_users_edit_label"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="properties_bodypanel_role" name="properties_user_tab" style="display: none;">
|
||||
<table style="width: 100%;" class="romtable">
|
||||
<tr>
|
||||
<th>
|
||||
|
||||
</th>
|
||||
<th>
|
||||
<input type="radio" name="settings_user_role" id="settings_user_role_player" value="Player"> <label for="settings_user_role_player">Player</label>
|
||||
</th>
|
||||
<th>
|
||||
<input type="radio" name="settings_user_role" id="settings_user_role_gamer" value="Gamer"> <label for="settings_user_role_gamer">Gamer</label>
|
||||
</th>
|
||||
<th>
|
||||
<input type="radio" name="settings_user_role" id="settings_user_role_admin" value="Admin"> <label for="settings_user_role_admin">Administrator</label>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="4"><h3>Games and ROM's</h3></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Play games</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Download ROM images</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Upload ROM images</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Create and delete multidisk packages</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Delete ROM images</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Fix ROM image matches</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="4"><h3>Collections</h3></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Download packages</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Create packages</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Edit packages</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Delete packages</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="4"><h3>Settings</h3></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Download firmware</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">View background tasks</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">View platform mapping</td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Modify platform mapping</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Manually start background tasks</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">View logs</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
<tr class="romrow">
|
||||
<td class="romcell">Manage user accounts</td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"></td>
|
||||
<td class="romcell"><img src="/images/tick.svg" class="banner_button_image" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="properties_bodypanel_age" name="properties_user_tab" style="display: none;">
|
||||
<h3>Classification Restrictions</h3>
|
||||
<div id="properties_bodypanel_age_classification">
|
||||
</div>
|
||||
<input type="checkbox" id="properties_bodypanel_age_includeunclassified"> <label for="properties_bodypanel_age_includeunclassified">Include unclassified titles</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 100%; padding-top: 10px; text-align: right;">
|
||||
<button id="settings_users_edit_okbutton" value="OK" onclick="saveProperties();">OK</button>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/users/' + modalVariables,
|
||||
'GET',
|
||||
function(result) {
|
||||
document.getElementById('modal-heading').innerHTML = result.emailAddress;
|
||||
|
||||
// role page
|
||||
document.getElementById('settings_user_role_' + result.highestRole.toLowerCase()).checked = true;
|
||||
|
||||
// age restriction page
|
||||
var ageRatingsContainer = document.getElementById('properties_bodypanel_age_classification');
|
||||
var ageRatingsTable = document.createElement('table');
|
||||
ageRatingsTable.style.width = '100%';
|
||||
ageRatingsTable.cellSpacing = 0;
|
||||
ageRatingsTable.appendChild(
|
||||
createTableRow(
|
||||
true,
|
||||
[
|
||||
'Highest Allowed Rating',
|
||||
'Included Ratings'
|
||||
],
|
||||
'',
|
||||
''
|
||||
)
|
||||
);
|
||||
for (var ageGroup in AgeRatingGroups) {
|
||||
if (AgeRatingGroups.hasOwnProperty(ageGroup)) {
|
||||
var ratingsValues = '';
|
||||
var classBoards = AgeRatingGroups[ageGroup];
|
||||
|
||||
for (var classBoard in classBoards) {
|
||||
for (var rating in classBoards[classBoard]) {
|
||||
ratingsValues += "<img src='/api/v1.1/Ratings/Images/" + classBoard + "/" + classBoards[classBoard][rating] + "/image.svg' class='rating_image_mini' />";
|
||||
}
|
||||
}
|
||||
|
||||
var radioCheckedState = '';
|
||||
if (result.securityProfile.ageRestrictionPolicy.maximumAgeRestriction.toLowerCase() == ageGroup.toLocaleLowerCase()) {
|
||||
radioCheckedState = "checked='checked'";
|
||||
}
|
||||
|
||||
ageRatingsTable.appendChild(
|
||||
createTableRow(
|
||||
false,
|
||||
[
|
||||
"<input type='radio' id='properties_bodypanel_age_classification_" + ageGroup + "' name='classification_group' " + radioCheckedState + " value='" + ageGroup + "' /> <label for='properties_bodypanel_age_classification_" + ageGroup + "'>" + ageGroup + "</label>",
|
||||
ratingsValues
|
||||
],
|
||||
'romrow',
|
||||
'romcell'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
ageRatingsContainer.appendChild(ageRatingsTable);
|
||||
|
||||
document.getElementById('properties_bodypanel_age_includeunclassified').checked = result.securityProfile.ageRestrictionPolicy.includeUnrated;
|
||||
},
|
||||
function(error) {
|
||||
closeDialog();
|
||||
}
|
||||
);
|
||||
|
||||
function UserSelectTab(TabName) {
|
||||
var tabs = document.getElementsByName('properties_user_tab');
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
if ((tabs[i].id) == ("properties_bodypanel_" + TabName)) {
|
||||
tabs[i].style.display = '';
|
||||
} else {
|
||||
tabs[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
var tocs = document.getElementsByName('properties_user_toc_item');
|
||||
for (var i = 0; i < tocs.length; i++) {
|
||||
if ((tocs[i].id) == ("properties_user_toc_" + TabName)) {
|
||||
tocs[i].className = "properties_toc_item_selected";
|
||||
} else {
|
||||
tocs[i].className = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkPasswordsMatch() {
|
||||
var newPassword = document.getElementById('settings_users_edit_password').value;
|
||||
var conPassword = document.getElementById('settings_users_edit_confirmpassword').value;
|
||||
var errorLabel = document.getElementById('settings_users_edit_label');
|
||||
var submitButton = document.getElementById('settings_users_edit_okbutton');
|
||||
|
||||
if (newPassword.length > 0) {
|
||||
if (newPassword == conPassword) {
|
||||
// check if password meets requirements
|
||||
if (newPassword.length > 10) {
|
||||
errorLabel.innerHTML = "";
|
||||
submitButton.removeAttribute('disabled');
|
||||
return true;
|
||||
} else {
|
||||
errorLabel.innerHTML = "Password should be at least 10 characters long";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "New and confirmed passwords do not match";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "Password will not be changed";
|
||||
submitButton.removeAttribute('disabled');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function saveProperties() {
|
||||
saveRole();
|
||||
}
|
||||
|
||||
function saveRole() {
|
||||
if (checkPasswordsMatch() == true) {
|
||||
// process role
|
||||
var selectedRole = $("input[type='radio'][name='settings_user_role']:checked").val();
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/users/' + modalVariables + '/Roles?RoleName=' + selectedRole,
|
||||
'POST',
|
||||
function(result) {
|
||||
saveSecurityProfile();
|
||||
},
|
||||
function(error) {
|
||||
saveSecurityProfile();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function saveSecurityProfile() {
|
||||
if (checkPasswordsMatch() == true) {
|
||||
// process security profile
|
||||
var securityProfile = {
|
||||
"ageRestrictionPolicy": {
|
||||
"maximumAgeRestriction": $("input[type='radio'][name='classification_group']:checked").val(),
|
||||
"includeUnrated": document.getElementById('properties_bodypanel_age_includeunclassified').checked
|
||||
}
|
||||
};
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/users/' + modalVariables + '/SecurityProfile',
|
||||
'POST',
|
||||
function(result) {
|
||||
savePassword();
|
||||
},
|
||||
function(error) {
|
||||
savePassword();
|
||||
},
|
||||
JSON.stringify(securityProfile)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function savePassword() {
|
||||
console.log("Save Password");
|
||||
if (checkPasswordsMatch() == true) {
|
||||
console.log("Passwords match");
|
||||
var newPassword = document.getElementById('settings_users_edit_password').value;
|
||||
|
||||
if (newPassword.length > 0) {
|
||||
var model = {
|
||||
"newPassword": newPassword,
|
||||
"confirmPassword": newPassword
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Users/' + modalVariables + '/Password',
|
||||
'POST',
|
||||
function(result) {
|
||||
console.log(JSON.stringify(result));
|
||||
savePropertiesCallback();
|
||||
},
|
||||
function(error) {
|
||||
console.log(JSON.stringify(error));
|
||||
savePropertiesCallback();
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
} else {
|
||||
console.log("Password not long enough to change");
|
||||
savePropertiesCallback();
|
||||
}
|
||||
} else {
|
||||
console.log("Passwords don't match");
|
||||
}
|
||||
}
|
||||
|
||||
function savePropertiesCallback() {
|
||||
GetUsers();
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
UserSelectTab('password');
|
||||
</script>
|
88
gaseous-server/wwwroot/pages/dialogs/settingsusernew.html
Normal file
88
gaseous-server/wwwroot/pages/dialogs/settingsusernew.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<h3>New User</h3>
|
||||
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<th>
|
||||
Email
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" id="settings_users_new_username" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Password
|
||||
</th>
|
||||
<td>
|
||||
<input type="password" id="settings_users_new_password" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Confirm password
|
||||
</th>
|
||||
<td>
|
||||
<input type="password" id="settings_users_new_confirmpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="settings_users_new_label"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right; padding-top: 10px;">
|
||||
<button value="OK" id="settings_users_new_okbutton" disabled="disabled" onclick="createUser();">OK</button><button value="Cancel" onclick="closeSubDialog();">Cancel</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
function checkPasswordsMatch() {
|
||||
var userNameVal = document.getElementById('settings_users_new_username').value;
|
||||
var newPassword = document.getElementById('settings_users_new_password').value;
|
||||
var conPassword = document.getElementById('settings_users_new_confirmpassword').value;
|
||||
var errorLabel = document.getElementById('settings_users_new_label');
|
||||
var submitButton = document.getElementById('settings_users_new_okbutton');
|
||||
|
||||
if (userNameVal.includes("@")) {
|
||||
if (newPassword == conPassword) {
|
||||
// check if password meets requirements
|
||||
if (newPassword.length > 10) {
|
||||
errorLabel.innerHTML = "";
|
||||
submitButton.removeAttribute('disabled');
|
||||
} else {
|
||||
errorLabel.innerHTML = "Password should be at least 10 characters long";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "New and confirmed passwords do not match";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "Email address is invalid";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
|
||||
function createUser() {
|
||||
var model = {
|
||||
"userName": document.getElementById('settings_users_new_username').value,
|
||||
"email": document.getElementById('settings_users_new_username').value,
|
||||
"password": document.getElementById('settings_users_new_password').value,
|
||||
"confirmPassword": document.getElementById('settings_users_new_confirmpassword').value
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Users',
|
||||
'POST',
|
||||
function(result) {
|
||||
GetUsers();
|
||||
closeSubDialog();
|
||||
},
|
||||
function(error) {
|
||||
GetUsers();
|
||||
closeSubDialog();
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
</script>
|
@@ -28,7 +28,7 @@
|
||||
document.getElementById('upload_platformoverride').innerHTML = "<option value='0' selected='selected'>Automatic Platform</option>";
|
||||
|
||||
var myDropzone = new Dropzone("div#upload_target", {
|
||||
url: "/api/v1.0/Roms",
|
||||
url: "/api/v1.1/Roms",
|
||||
autoProcessQueue: true,
|
||||
uploadMultiple: true,
|
||||
paramName: myParamName,
|
||||
@@ -84,7 +84,7 @@
|
||||
$('#upload_platformoverride').select2({
|
||||
minimumInputLength: 3,
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Platform',
|
||||
url: '/api/v1.1/Search/Platform',
|
||||
data: function (params) {
|
||||
var query = {
|
||||
SearchString: params.term
|
||||
@@ -125,6 +125,6 @@
|
||||
}
|
||||
console.log(queryString);
|
||||
|
||||
myDropzone.options.url = "/api/v1.0/Roms" + queryString;
|
||||
myDropzone.options.url = "/api/v1.1/Roms" + queryString;
|
||||
});
|
||||
</script>
|
122
gaseous-server/wwwroot/pages/dialogs/userprofile.html
Normal file
122
gaseous-server/wwwroot/pages/dialogs/userprofile.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<div id="properties_toc">
|
||||
<div id="properties_profile_toc_general" name="properties_profile_toc_item" onclick="ProfileSelectTab('general');">Account</div>
|
||||
</div>
|
||||
<div id="properties_bodypanel">
|
||||
<div id="properties_bodypanel_general" name="properties_profile_tab" style="display: none;">
|
||||
<h3>Reset Password</h3>
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<th>Old Password</th>
|
||||
<td><input type="password" id="profile_oldpassword" style="width: 95%;" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>New Password</th>
|
||||
<td><input type="password" id="profile_newpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Confirm Password</th>
|
||||
<td><input type="password" id="profile_confirmpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="profile_passwordnotice"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;">
|
||||
<button id="profile_resetpassword" value="Reset Password" disabled="disabled" onclick="ResetPassword();">Reset Password</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById('modal-heading').innerHTML = userProfile.emailAddress;
|
||||
|
||||
function ProfileSelectTab(TabName) {
|
||||
var tabs = document.getElementsByName('properties_profile_tab');
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
if ((tabs[i].id) == ("properties_bodypanel_" + TabName)) {
|
||||
tabs[i].style.display = '';
|
||||
} else {
|
||||
tabs[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
var tocs = document.getElementsByName('properties_profile_toc_item');
|
||||
for (var i = 0; i < tocs.length; i++) {
|
||||
if ((tocs[i].id) == ("properties_profile_toc_" + TabName)) {
|
||||
tocs[i].className = "properties_toc_item_selected";
|
||||
} else {
|
||||
tocs[i].className = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkPasswordsMatch() {
|
||||
var oldPassword = document.getElementById('profile_oldpassword').value;
|
||||
var newPassword = document.getElementById('profile_newpassword').value;
|
||||
var conPassword = document.getElementById('profile_confirmpassword').value;
|
||||
var errorLabel = document.getElementById('profile_passwordnotice');
|
||||
var submitButton = document.getElementById('profile_resetpassword');
|
||||
|
||||
// make sure the new password is not the same as the old one
|
||||
if (newPassword == oldPassword) {
|
||||
errorLabel.innerHTML = "New password should not match the old password";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
} else {
|
||||
if (newPassword == conPassword) {
|
||||
// check if password meets requirements
|
||||
if (newPassword.length > 10) {
|
||||
errorLabel.innerHTML = "";
|
||||
submitButton.removeAttribute('disabled');
|
||||
} else {
|
||||
errorLabel.innerHTML = "Password should be at least 10 characters long";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "New and confirmed passwords do not match";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ResetPassword() {
|
||||
var oldPassword = document.getElementById('profile_oldpassword').value;
|
||||
var newPassword = document.getElementById('profile_newpassword').value;
|
||||
var conPassword = document.getElementById('profile_confirmpassword').value;
|
||||
|
||||
var model = {
|
||||
"OldPassword": oldPassword,
|
||||
"NewPassword": newPassword,
|
||||
"ConfirmPassword": conPassword
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/ChangePassword',
|
||||
'POST',
|
||||
function(result) {
|
||||
ResetPasswordCallback(result);
|
||||
},
|
||||
function(error) {
|
||||
ResetPasswordCallback(error);
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
|
||||
function ResetPasswordCallback(result) {
|
||||
var errorLabel = document.getElementById('profile_passwordnotice');
|
||||
|
||||
if (result.succeeded == false) {
|
||||
errorLabel.innerHTML = result.errors.description;
|
||||
} else {
|
||||
document.getElementById('profile_oldpassword').value = '';
|
||||
document.getElementById('profile_newpassword').value = '';
|
||||
document.getElementById('profile_confirmpassword').value = '';
|
||||
document.getElementById('profile_resetpassword').setAttribute('disabled', 'disabled');
|
||||
errorLabel.innerHTML = "Password changed.";
|
||||
}
|
||||
}
|
||||
|
||||
ProfileSelectTab('general');
|
||||
</script>
|
@@ -15,7 +15,7 @@
|
||||
var emuBios = '';
|
||||
var emuBackground = '';
|
||||
|
||||
ajaxCall('/api/v1.0/Games/' + gameId, 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) {
|
||||
gameData = result;
|
||||
|
||||
// load artwork
|
||||
@@ -27,22 +27,22 @@
|
||||
} else {
|
||||
if (result.cover) {
|
||||
var bg = document.getElementById('bgImage');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.0/Games/' + gameId + '/cover/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/cover/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
}
|
||||
}
|
||||
|
||||
if (result.cover) {
|
||||
emuBackground = '/api/v1.0/Games/' + gameId + '/cover/image';
|
||||
emuBackground = '/api/v1.1/Games/' + gameId + '/cover/image';
|
||||
}
|
||||
|
||||
emuGameTitle = gameData.name;
|
||||
});
|
||||
|
||||
ajaxCall('/api/v1.0/Bios/' + platformId, 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Bios/' + platformId, 'GET', function (result) {
|
||||
if (result.length == 0) {
|
||||
emuBios = '';
|
||||
} else {
|
||||
emuBios = '/api/v1.0/Bios/zip/' + platformId;
|
||||
emuBios = '/api/v1.1/Bios/zip/' + platformId;
|
||||
}
|
||||
|
||||
switch (getQueryString('engine', 'string')) {
|
||||
@@ -59,7 +59,7 @@
|
||||
artworksPosition = 0;
|
||||
}
|
||||
var bg = document.getElementById('bgImage');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.0/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
167
gaseous-server/wwwroot/pages/first.html
Normal file
167
gaseous-server/wwwroot/pages/first.html
Normal file
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
<link type="text/css" rel="stylesheet" dat-href="/styles/style.css" />
|
||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
||||
<script src="/scripts/moment.js"></script>
|
||||
<link href="/styles/select2.min.css" rel="stylesheet" />
|
||||
<link href="/styles/dropzone.min.css" rel="stylesheet" type="text/css" />
|
||||
<script src="/scripts/jquery.lazy.min.js"></script>
|
||||
<script src="/scripts/jquery.lazy.plugins.min.js"></script>
|
||||
<script src="/scripts/select2.min.js"></script>
|
||||
<script src="/scripts/dropzone.min.js"></script>
|
||||
<script src="/scripts/simpleUpload.min.js"></script>
|
||||
<script src="/scripts/main.js" type="text/javascript"></script>
|
||||
<script src="/scripts/filterformating.js" type="text/javascript"></script>
|
||||
<script src="/scripts/gamesformating.js" type="text/javascript"></script>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<title>Gaseous Games</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
|
||||
// update links
|
||||
var headLinks = document.getElementsByTagName('link');
|
||||
for (var i = 0; i < headLinks.length; i++) {
|
||||
if (headLinks[i].getAttribute('dat-href') && headLinks[i].rel == "stylesheet") {
|
||||
var newLink = document.createElement('link');
|
||||
newLink.rel = "stylesheet";
|
||||
newLink.href = headLinks[i].getAttribute('dat-href') + '?v=' + AppVersion;
|
||||
newLink.type = "text/css";
|
||||
|
||||
headLinks[i].parentElement.removeChild(headLinks[i]);
|
||||
head.appendChild(newLink);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="bgImage" style="background-image: url('/images/LoginWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
|
||||
<div id="bgImage_Opacity"></div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div class="loginwindow" id="first_welcome">
|
||||
<div id="welcomeform" class="loginwindow-content">
|
||||
<img src="/images/logo.png" style="display: block; margin: 20px auto;" />
|
||||
|
||||
<div id="loginwindow_header_label" style="display: block; text-align: center;">Gaseous Games</div>
|
||||
|
||||
<button type="button" value="Get Started" onclick="document.getElementById('first_welcome').style.display = 'none'; document.getElementById('first_newadmin').style.display = '';" style="margin-top: 50px; width: 100%; font-size: 16px; border-radius: 10px; padding-top: 10px; padding-bottom: 10px;">Get Started</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loginwindow" id="first_newadmin" style="display: none;">
|
||||
<div id="loginform" class="loginwindow-content">
|
||||
<img src="/images/logo.png" style="display: block; margin: 20px auto;" />
|
||||
|
||||
<div id="loginwindow_header_label" style="display: block; text-align: center;">Gaseous Games</div>
|
||||
|
||||
<table style="width: 100%; margin-top: 20px;" cellpadding="5px">
|
||||
<tr>
|
||||
<td colspan="2" style="font-size: 18px;">Create your account.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td><input type="email" id="login_email" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>New Password</th>
|
||||
<td><input type="password" id="login_password" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Confirm Password</th>
|
||||
<td><input type="password" id="login_confirmpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="login_passwordnotice"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="padding-top: 20px;">
|
||||
<button id="login_createaccount" type="button" value="Create Account" onclick="registerAccount();" disabled="disabled" style="margin-top: 10px; width: 100%; font-size: 16px; border-radius: 10px; padding-top: 10px; padding-bottom: 10px;">Create Account</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings_photocredit">
|
||||
Wallpaper by <a href="https://unsplash.com/@spideyjoey" class="romlink">Joey Kwok</a> / <a href="https://unsplash.com/photos/a-room-filled-with-arcade-machines-and-neon-lights-jbIsTd7rdd8" class="romlink">Unsplash</a>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// redirect if first run status != 0 as 0 indicates that first run needs to be run
|
||||
if (FirstRunStatus != 0) {
|
||||
window.location.replace("/");
|
||||
}
|
||||
|
||||
function checkPasswordsMatch() {
|
||||
var emailAddress = document.getElementById('login_email').value;
|
||||
var newPassword = document.getElementById('login_password').value;
|
||||
var conPassword = document.getElementById('login_confirmpassword').value;
|
||||
var errorLabel = document.getElementById('login_passwordnotice');
|
||||
var submitButton = document.getElementById('login_createaccount');
|
||||
|
||||
// make sure email address is valid
|
||||
if (!emailAddress.includes("@")) {
|
||||
errorLabel.innerHTML = "Please enter a valid email address";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
} else {
|
||||
if (newPassword == conPassword) {
|
||||
// check if password meets requirements
|
||||
if (newPassword.length > 10) {
|
||||
errorLabel.innerHTML = " ";
|
||||
submitButton.removeAttribute('disabled');
|
||||
} else {
|
||||
errorLabel.innerHTML = "Password should be at least 10 characters long";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
} else {
|
||||
errorLabel.innerHTML = "New and confirmed passwords do not match";
|
||||
submitButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function registerAccount() {
|
||||
var emailAddress = document.getElementById('login_email').value;
|
||||
var newPassword = document.getElementById('login_password').value;
|
||||
var conPassword = document.getElementById('login_confirmpassword').value;
|
||||
|
||||
var model = {
|
||||
"userName": emailAddress,
|
||||
"email": emailAddress,
|
||||
"password": newPassword,
|
||||
"confirmPassword": conPassword
|
||||
};
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/FirstSetup/0',
|
||||
'POST',
|
||||
function(result){
|
||||
loginCallback(result);
|
||||
},
|
||||
function(error){
|
||||
loginCallback(error);
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
|
||||
function loginCallback(result) {
|
||||
switch(result.status) {
|
||||
case 200:
|
||||
window.location.replace('/index.html');
|
||||
break;
|
||||
default:
|
||||
// login failed
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
@@ -94,7 +94,7 @@
|
||||
var artworksTimer = null;
|
||||
var selectedScreenshot = 0;
|
||||
|
||||
ajaxCall('/api/v1.0/Games/' + gameId, 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) {
|
||||
// populate games page
|
||||
gameData = result;
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
// get alt name
|
||||
var gameTitleAltLabel = document.getElementById('gametitle_alts');
|
||||
if (result.alternativeNames) {
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/alternativename', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/alternativename', 'GET', function (result) {
|
||||
var altNames = '';
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
if (altNames.length > 0) {
|
||||
@@ -161,7 +161,7 @@
|
||||
} else {
|
||||
var bg = document.getElementById('bgImage');
|
||||
if (result.cover) {
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.0/Games/' + gameId + '/cover/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/cover/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
} else {
|
||||
var randomInt = randomIntFromInterval(1, 3);
|
||||
bg.setAttribute('style', 'background-image: url("/images/gamebg' + randomInt + '.jpg"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
@@ -175,7 +175,7 @@
|
||||
var gameDeveloperLoaded = false;
|
||||
var gamePublisherLoaded = false;
|
||||
if (result.involvedCompanies) {
|
||||
ajaxCall('/api/v1.0/games/' + gameId + '/companies', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/games/' + gameId + '/companies', 'GET', function (result) {
|
||||
var lstDevelopers = [];
|
||||
var lstPublishers = [];
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
var gameImage = document.createElement('img');
|
||||
gameImage.className = 'game_cover_image';
|
||||
if (result.cover) {
|
||||
gameImage.src = '/api/v1.0/Games/' + result.id + '/cover/image';
|
||||
gameImage.src = '/api/v1.1/Games/' + result.id + '/cover/image';
|
||||
} else {
|
||||
gameImage.src = '/images/unknowngame.png';
|
||||
gameImage.className = 'game_cover_image unknown';
|
||||
@@ -240,7 +240,7 @@
|
||||
var gameRatings = document.createElement('div');
|
||||
for (var i = 0; i < result.ageRatings.ids.length; i++) {
|
||||
var ratingImage = document.createElement('img');
|
||||
ratingImage.src = '/api/v1.0/Games/' + result.id + '/agerating/' + result.ageRatings.ids[i] + '/image';
|
||||
ratingImage.src = '/api/v1.1/Games/' + result.id + '/agerating/' + result.ageRatings.ids[i] + '/image';
|
||||
ratingImage.className = 'rating_image';
|
||||
gameRatings.appendChild(ratingImage);
|
||||
}
|
||||
@@ -252,7 +252,7 @@
|
||||
// load genres
|
||||
var gameSummaryGenres = document.getElementById('gamesumarry_genres');
|
||||
if (result.genres) {
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/genre', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/genre', 'GET', function (result) {
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var genreLabel = document.createElement('span');
|
||||
genreLabel.className = 'gamegenrelabel';
|
||||
@@ -281,7 +281,7 @@
|
||||
var screenshotItem = document.createElement('div');
|
||||
screenshotItem.id = 'gamescreenshots_gallery_' + imageIndex;
|
||||
screenshotItem.setAttribute('name', 'gamescreenshots_gallery_item');
|
||||
screenshotItem.setAttribute('style', 'background-image: url("/api/v1.0/Games/' + gameId + '/screenshots/' + result.screenshots.ids[i] + '/image"); background-position: center; background-repeat: no-repeat; background-size: contain;)');
|
||||
screenshotItem.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/screenshots/' + result.screenshots.ids[i] + '/image"); background-position: center; background-repeat: no-repeat; background-size: contain;)');
|
||||
screenshotItem.setAttribute('imageid', imageIndex);
|
||||
screenshotItem.setAttribute('imagetype', 0);
|
||||
screenshotItem.className = 'gamescreenshots_gallery_item';
|
||||
@@ -293,7 +293,7 @@
|
||||
|
||||
// load videos
|
||||
if (result.videos) {
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/videos', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/videos', 'GET', function (result) {
|
||||
var gameScreenshots_vGallery = document.getElementById('gamescreenshots_gallery_panel');
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var vScreenshotItem = document.createElement('div');
|
||||
@@ -360,7 +360,7 @@
|
||||
}
|
||||
|
||||
var gameRoms = document.getElementById('gamesummaryroms');
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms', 'GET', function (result) {
|
||||
if (result.gameRomItems) {
|
||||
var gameRomItems = result.gameRomItems;
|
||||
var mediaGroups = result.mediaGroups;
|
||||
@@ -391,14 +391,14 @@
|
||||
if (result.gameRomItems[i].emulator) {
|
||||
if (gameRomItems[i].emulator.type) {
|
||||
if (gameRomItems[i].emulator.type.length > 0) {
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItems[i].emulator.type + '&core=' + gameRomItems[i].emulator.core + '&platformid=' + gameRomItems[i].platform.id + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.0/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + encodeURIComponent(gameRomItems[i].name)) + '" class="romstart">Launch</a>';
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItems[i].emulator.type + '&core=' + gameRomItems[i].emulator.core + '&platformid=' + gameRomItems[i].platform.id + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.1/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + encodeURIComponent(gameRomItems[i].name)) + '" class="romstart">Launch</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newRow = [
|
||||
['<input type="checkbox" name="rom_checkbox" data-gameid="' + gameData.id + '" data-platformid="' + gameRomItems[i].platformId + '" data-romid="' + gameRomItems[i].id + '" onclick="handleChecks();" />', 'rom_checkbox_box_hidden', 'rom_edit_checkbox'],
|
||||
'<a href="/api/v1.0/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + encodeURIComponent(gameRomItems[i].name) + '" class="romlink">' + gameRomItems[i].name + '</a>',
|
||||
'<a href="/api/v1.1/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + encodeURIComponent(gameRomItems[i].name) + '" class="romlink">' + gameRomItems[i].name + '</a>',
|
||||
formatBytes(gameRomItems[i].size, 2),
|
||||
gameRomItems[i].romTypeMedia,
|
||||
gameRomItems[i].mediaLabel,
|
||||
@@ -436,7 +436,7 @@
|
||||
if (gameRomItem.platformId == mediaGroup.platformId) {
|
||||
if (gameRomItem.emulator) {
|
||||
if (gameRomItem.emulator.type.length > 0) {
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItem.emulator.type + '&core=' + gameRomItem.emulator.core + '&platformid=' + gameRomItem.platform.id + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.0/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip') + '" class="romstart">Launch</a>';
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItem.emulator.type + '&core=' + gameRomItem.emulator.core + '&platformid=' + gameRomItem.platform.id + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip') + '" class="romstart">Launch</a>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -459,7 +459,7 @@
|
||||
break;
|
||||
case "Completed":
|
||||
statusText = 'Available';
|
||||
downloadLink = '<a href="/api/v1.0/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '.zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||
downloadLink = '<a href="/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '.zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||
packageSize = formatBytes(mediaGroup.size);
|
||||
launchButtonContent = launchButton;
|
||||
break;
|
||||
@@ -525,7 +525,7 @@
|
||||
artworksPosition = 0;
|
||||
}
|
||||
var bg = document.getElementById('bgImage');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.0/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
artworksTimer = setTimeout(rotateBackground, 60000);
|
||||
}
|
||||
}
|
||||
@@ -677,7 +677,7 @@
|
||||
minimumInputLength: 3,
|
||||
placeholder: "Platform",
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Platform',
|
||||
url: '/api/v1.1/Search/Platform',
|
||||
data: function (params) {
|
||||
var query = {
|
||||
SearchString: params.term
|
||||
@@ -709,7 +709,7 @@
|
||||
templateResult: DropDownRenderGameOption,
|
||||
placeholder: "Game",
|
||||
ajax: {
|
||||
url: '/api/v1.0/Search/Game',
|
||||
url: '/api/v1.1/Search/Game',
|
||||
data: function (params) {
|
||||
fixplatform = $('#rom_edit_fixplatform').select2('data');
|
||||
|
||||
@@ -762,7 +762,7 @@
|
||||
if (rom_checks[i].checked == true) {
|
||||
var romId = rom_checks[i].getAttribute('data-romid');
|
||||
remapCallCounter += 1;
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms/' + romId + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + romId + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
remapTitlesCallback();
|
||||
}, function (result) {
|
||||
remapTitlesCallback();
|
||||
@@ -804,7 +804,7 @@
|
||||
if (rom_checks[i].checked == true) {
|
||||
var romId = rom_checks[i].getAttribute('data-romid');
|
||||
remapCallCounter += 1;
|
||||
ajaxCall('/api/v1.0/Games/' + gameId + '/roms/' + romId, 'DELETE', function (result) {
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + romId, 'DELETE', function (result) {
|
||||
remapTitlesCallback();
|
||||
});
|
||||
}
|
||||
@@ -846,7 +846,7 @@
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/Games/' + gameId + '/romgroup?PlatformId=' + platformId,
|
||||
'/api/v1.1/Games/' + gameId + '/romgroup?PlatformId=' + platformId,
|
||||
'POST',
|
||||
function (result) {
|
||||
DisplayROMCheckboxes(false);
|
||||
|
@@ -8,10 +8,10 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
ajaxCall('/api/v1.0/Filter', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Filter', 'GET', function (result) {
|
||||
var filterElement = document.getElementById('games_filter');
|
||||
formatFilterPanel(filterElement, result);
|
||||
|
||||
executeFilter();
|
||||
executeFilter1_1();
|
||||
});
|
||||
</script>
|
128
gaseous-server/wwwroot/pages/login.html
Normal file
128
gaseous-server/wwwroot/pages/login.html
Normal file
@@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
<link type="text/css" rel="stylesheet" dat-href="/styles/style.css" />
|
||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
||||
<script src="/scripts/moment.js"></script>
|
||||
<link href="/styles/select2.min.css" rel="stylesheet" />
|
||||
<link href="/styles/dropzone.min.css" rel="stylesheet" type="text/css" />
|
||||
<script src="/scripts/jquery.lazy.min.js"></script>
|
||||
<script src="/scripts/jquery.lazy.plugins.min.js"></script>
|
||||
<script src="/scripts/select2.min.js"></script>
|
||||
<script src="/scripts/dropzone.min.js"></script>
|
||||
<script src="/scripts/simpleUpload.min.js"></script>
|
||||
<script src="/scripts/main.js" type="text/javascript"></script>
|
||||
<script src="/scripts/filterformating.js" type="text/javascript"></script>
|
||||
<script src="/scripts/gamesformating.js" type="text/javascript"></script>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<title>Gaseous Games</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
|
||||
// update links
|
||||
var headLinks = document.getElementsByTagName('link');
|
||||
for (var i = 0; i < headLinks.length; i++) {
|
||||
if (headLinks[i].getAttribute('dat-href') && headLinks[i].rel == "stylesheet") {
|
||||
var newLink = document.createElement('link');
|
||||
newLink.rel = "stylesheet";
|
||||
newLink.href = headLinks[i].getAttribute('dat-href') + '?v=' + AppVersion;
|
||||
newLink.type = "text/css";
|
||||
|
||||
headLinks[i].parentElement.removeChild(headLinks[i]);
|
||||
head.appendChild(newLink);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="bgImage" style="background-image: url('/images/LoginWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
|
||||
<div id="bgImage_Opacity"></div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div class="loginwindow">
|
||||
<div id="loginform" class="loginwindow-content">
|
||||
<img src="/images/logo.png" style="display: block; margin: 20px auto;" />
|
||||
|
||||
<div id="loginwindow_header_label" style="display: block; text-align: center;">Gaseous Games</div>
|
||||
|
||||
<table style="width: 100%; margin-top: 20px;" cellpadding="5px">
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td><input type="email" id="login_email" style="width: 95%;" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Password</th>
|
||||
<td><input type="password" id="login_password" style="width: 95%;" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="checkbox" id="login_rememberme"> <label for="login_rememberme">Remember Me</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="padding-top: 20px;">
|
||||
<button type="button" value="Sign In" onclick="UserLogin();" style="margin-top: 10px; width: 100%; font-size: 16px; border-radius: 10px; padding-top: 10px; padding-bottom: 10px;">Sign In</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings_photocredit">
|
||||
Wallpaper by <a href="https://unsplash.com/@spideyjoey" class="romlink">Joey Kwok</a> / <a href="https://unsplash.com/photos/a-room-filled-with-arcade-machines-and-neon-lights-jbIsTd7rdd8" class="romlink">Unsplash</a>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// redirect if logged in
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Profile/Basic',
|
||||
'GET',
|
||||
function(result) {
|
||||
// user is signed in - redirect to main page
|
||||
window.location.replace("/");
|
||||
},
|
||||
function(error) {
|
||||
// user is not signed in - do nothing
|
||||
}
|
||||
);
|
||||
|
||||
function UserLogin() {
|
||||
var loginObj = {
|
||||
"email": document.getElementById('login_email').value,
|
||||
"password": document.getElementById('login_password').value,
|
||||
"rememberMe": document.getElementById('login_rememberme').checked
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Login',
|
||||
'POST',
|
||||
function(result) {
|
||||
loginCallback(result);
|
||||
},
|
||||
function(error) {
|
||||
loginCallback(error);
|
||||
},
|
||||
JSON.stringify(loginObj)
|
||||
);
|
||||
|
||||
function loginCallback(result) {
|
||||
switch(result.status) {
|
||||
case 200:
|
||||
window.location.replace('/index.html');
|
||||
break;
|
||||
default:
|
||||
// login failed
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
@@ -6,10 +6,11 @@
|
||||
<div id="properties_toc" class="settings_toc">
|
||||
<div class="filter_header">Settings</div>
|
||||
<div id="properties_toc_system" name="properties_toc_item" onclick="SelectTab('system');">System</div>
|
||||
<div id="properties_toc_settings" name="properties_toc_item" onclick="SelectTab('settings');">Settings</div>
|
||||
<div id="properties_toc_mapping" name="properties_toc_item" onclick="SelectTab('mapping');">Platform Mapping</div>
|
||||
<div id="properties_toc_settings" name="properties_toc_item" onclick="SelectTab('settings');" style="display: none;">Settings</div>
|
||||
<div id="properties_toc_users" name="properties_toc_item" onclick="SelectTab('users');" style="display: none;">Users</div>
|
||||
<div id="properties_toc_mapping" name="properties_toc_item" onclick="SelectTab('mapping');" style="display: none;">Platform Mapping</div>
|
||||
<div id="properties_toc_bios" name="properties_toc_item" onclick="SelectTab('bios');">Firmware</div>
|
||||
<div id="properties_toc_logs" name="properties_toc_item" onclick="SelectTab('logs');">Logs</div>
|
||||
<div id="properties_toc_logs" name="properties_toc_item" onclick="SelectTab('logs');" style="display: none;">Logs</div>
|
||||
<div id="properties_toc_about" name="properties_toc_item" onclick="SelectTab('about');">About</div>
|
||||
</div>
|
||||
<div id="properties_bodypanel">
|
||||
@@ -23,6 +24,16 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
if (userProfile.roles.includes("Admin")) {
|
||||
document.getElementById('properties_toc_settings').style.display = '';
|
||||
document.getElementById('properties_toc_users').style.display = '';
|
||||
document.getElementById('properties_toc_mapping').style.display = '';
|
||||
document.getElementById('properties_toc_logs').style.display = '';
|
||||
}
|
||||
if (userProfile.roles.includes("Gamer")) {
|
||||
document.getElementById('properties_toc_mapping').style.display = '';
|
||||
}
|
||||
|
||||
var myParam = getQueryString('sub', 'string');
|
||||
|
||||
var selectedTab = '';
|
||||
|
@@ -8,7 +8,7 @@
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
ajaxCall('/api/v1.0/Bios', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Bios', 'GET', function (result) {
|
||||
result.sort((a, b) => a.platformname.charCodeAt(0) - b.platformname.charCodeAt(0));
|
||||
|
||||
var lastPlatform = '';
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
var biosFilename = document.createElement('a');
|
||||
biosFilename.href = '/api/v1.0/Bios/' + result[i].platformid + '/' + result[i].filename;
|
||||
biosFilename.href = '/api/v1.1/Bios/' + result[i].platformid + '/' + result[i].filename;
|
||||
biosFilename.innerHTML = result[i].filename;
|
||||
biosFilename.className = 'romlink';
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
availableText.className = 'greentext';
|
||||
|
||||
biosFilename = document.createElement('a');
|
||||
biosFilename.href = '/api/v1.0/Bios/' + result[i].platformid + '/' + result[i].filename;
|
||||
biosFilename.href = '/api/v1.1/Bios/' + result[i].platformid + '/' + result[i].filename;
|
||||
biosFilename.innerHTML = result[i].filename;
|
||||
biosFilename.className = 'romlink';
|
||||
} else {
|
||||
|
@@ -26,7 +26,7 @@
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/Logs' + apiQuery,
|
||||
'/api/v1.1/Logs' + apiQuery,
|
||||
'GET',
|
||||
function (result) {
|
||||
var newTable = document.getElementById('settings_events_table');
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
<p>This list is pre-populated with some of the more common platforms. New platforms will appear in this list as titles are added.</p>
|
||||
|
||||
<p><button value="Export to JSON" onclick="DownloadJSON();">Export to JSON</button><button id="importjson" value="Import JSON">Import JSON</button><button value="Reset to Default" onclick="loadPlatformMapping(true);">Reset to Default</button></p>
|
||||
<p id="settings_mapping_import" style="display: none;"><button value="Export to JSON" onclick="DownloadJSON();">Export to JSON</button><button id="importjson" value="Import JSON">Import JSON</button><button value="Reset to Default" onclick="loadPlatformMapping(true);">Reset to Default</button></p>
|
||||
|
||||
<input id='uploadjson' type='file' name='files' hidden/>
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
if (userProfile.roles.includes("Admin")) {
|
||||
document.getElementById('settings_mapping_import').style.display = '';
|
||||
}
|
||||
|
||||
function loadPlatformMapping(Overwrite) {
|
||||
var queryString = '';
|
||||
if (Overwrite == true) {
|
||||
@@ -22,7 +26,7 @@
|
||||
}
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.0/PlatformMaps' + queryString,
|
||||
'/api/v1.1/PlatformMaps' + queryString,
|
||||
'GET',
|
||||
function (result) {
|
||||
var newTable = document.getElementById('settings_mapping_table');
|
||||
@@ -47,8 +51,15 @@
|
||||
hasWebEmulator = 'Yes';
|
||||
}
|
||||
|
||||
var platformLink = '';
|
||||
if (userProfile.roles.includes("Admin")) {
|
||||
platformLink = '<a href="#/" onclick="ShowPlatformMappingDialog(' + result[i].igdbId + ');" class="romlink">' + result[i].igdbName + '</a>';
|
||||
} else {
|
||||
platformLink = result[i].igdbName;
|
||||
}
|
||||
|
||||
var newRow = [
|
||||
'<a href="#/" onclick="ShowPlatformMappingDialog(' + result[i].igdbId + ');" class="romlink">' + result[i].igdbName + '</a>',
|
||||
platformLink,
|
||||
result[i].extensions.supportedFileExtensions.join(', '),
|
||||
result[i].extensions.uniqueFileExtensions.join(', '),
|
||||
hasWebEmulator
|
||||
@@ -61,7 +72,7 @@
|
||||
}
|
||||
|
||||
function DownloadJSON() {
|
||||
window.open('/api/v1.0/PlatformMaps', '_blank');
|
||||
window.open('/api/v1.1/PlatformMaps', '_blank');
|
||||
}
|
||||
|
||||
document.getElementById('importjson').addEventListener('click', openDialog);
|
||||
@@ -71,7 +82,7 @@
|
||||
}
|
||||
|
||||
$('#uploadjson').change(function () {
|
||||
$(this).simpleUpload("/api/v1.0/PlatformMaps", {
|
||||
$(this).simpleUpload("/api/v1.1/PlatformMaps", {
|
||||
start: function (file) {
|
||||
//upload started
|
||||
console.log("JSON upload started");
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<script type="text/javascript">
|
||||
function drawLibrary() {
|
||||
ajaxCall(
|
||||
'/api/v1.0/Library',
|
||||
'/api/v1.1/Library',
|
||||
'GET',
|
||||
function (result) {
|
||||
var newTable = document.getElementById('settings_libraries');
|
||||
|
@@ -26,7 +26,7 @@
|
||||
<div id="system_signatures"></div>
|
||||
|
||||
<script type="text/javascript">function SystemLoadStatus() {
|
||||
ajaxCall('/api/v1.0/BackgroundTasks', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/BackgroundTasks', 'GET', function (result) {
|
||||
var newTable = document.createElement('table');
|
||||
newTable.className = 'romtable';
|
||||
newTable.setAttribute('cellspacing', 0);
|
||||
@@ -91,8 +91,10 @@
|
||||
var itemInterval = result[i].interval;
|
||||
var nextRunTime = moment(result[i].nextRunTime).fromNow();
|
||||
var startButton = '';
|
||||
if (result[i].allowManualStart == true && result[i].itemState != "Running") {
|
||||
startButton = "<span id='startProcess' class='romstart' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
|
||||
if (userProfile.roles.includes("Admin")) {
|
||||
if (result[i].allowManualStart == true && result[i].itemState != "Running") {
|
||||
startButton = "<span id='startProcess' class='romstart' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
|
||||
}
|
||||
}
|
||||
|
||||
if (result[i].allowManualStart == false && result[i].removeWhenStopped == true) {
|
||||
@@ -119,7 +121,7 @@
|
||||
}
|
||||
|
||||
function SystemLoadSystemStatus() {
|
||||
ajaxCall('/api/v1.0/System', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/System', 'GET', function (result) {
|
||||
if (result) {
|
||||
var totalLibrarySpace = 0;
|
||||
|
||||
@@ -234,7 +236,7 @@
|
||||
}
|
||||
|
||||
function SystemSignaturesStatus() {
|
||||
ajaxCall('/api/v1.0/Signatures/Status', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/Signatures/Status', 'GET', function (result) {
|
||||
var newTable = document.createElement('table');
|
||||
newTable.className = 'romtable';
|
||||
newTable.setAttribute('cellspacing', 0);
|
||||
@@ -257,7 +259,7 @@
|
||||
}
|
||||
|
||||
function StartProcess(itemType) {
|
||||
ajaxCall('/api/v1.0/BackgroundTasks/' + itemType + '?ForceRun=true', 'GET', function (result) {
|
||||
ajaxCall('/api/v1.1/BackgroundTasks/' + itemType + '?ForceRun=true', 'GET', function (result) {
|
||||
SystemLoadStatus();
|
||||
});
|
||||
}
|
||||
|
99
gaseous-server/wwwroot/pages/settings/users.html
Normal file
99
gaseous-server/wwwroot/pages/settings/users.html
Normal file
@@ -0,0 +1,99 @@
|
||||
<div id="gametitle">
|
||||
<h1 id="gametitle_label">Users</h1>
|
||||
</div>
|
||||
|
||||
<button id="settings_users_new" value="New User" style="float: right;" onclick="showSubDialog('settingsusernew');">New User</button>
|
||||
|
||||
<div id="settings_users_table_container">
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function GetUsers() {
|
||||
var targetDiv = document.getElementById('settings_users_table_container');
|
||||
targetDiv.innerHTML = '';
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Account/Users',
|
||||
'GET',
|
||||
function(result) {
|
||||
var newTable = document.createElement('table');
|
||||
newTable.className = 'romtable';
|
||||
newTable.style.width = '100%';
|
||||
newTable.cellSpacing = 0;
|
||||
|
||||
newTable.appendChild(
|
||||
createTableRow(
|
||||
true,
|
||||
[
|
||||
'Email',
|
||||
'Role',
|
||||
'Age Restriction',
|
||||
''
|
||||
],
|
||||
'',
|
||||
''
|
||||
)
|
||||
);
|
||||
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var roleDiv = document.createElement('div');
|
||||
// for (var r = 0; r < result[i].roles.length; r++) {
|
||||
// var roleItem = document.createElement('div');
|
||||
// roleItem.className = 'dropdownroleitem';
|
||||
// roleItem.innerHTML = result[i].roles[r].toUpperCase();
|
||||
// var colorVal = intToRGB(hashCode(result[i].roles[r]));
|
||||
// roleItem.style.backgroundColor = '#' + colorVal;
|
||||
// roleItem.style.borderColor = '#' + colorVal;
|
||||
// roleDiv.appendChild(roleItem);
|
||||
// }
|
||||
|
||||
var roleItem = CreateBadge(result[i].highestRole);
|
||||
roleDiv.appendChild(roleItem);
|
||||
|
||||
var ageRestrictionPolicyDescription = document.createElement('div');
|
||||
if (result[i].securityProfile != null) {
|
||||
if (result[i].securityProfile.ageRestrictionPolicy != null) {
|
||||
var IncludeUnratedText = '';
|
||||
if (result[i].securityProfile.ageRestrictionPolicy.includeUnrated == true) {
|
||||
IncludeUnratedText = " + Unclassified titles";
|
||||
}
|
||||
|
||||
var restrictionText = result[i].securityProfile.ageRestrictionPolicy.maximumAgeRestriction + IncludeUnratedText;
|
||||
|
||||
ageRestrictionPolicyDescription = CreateBadge(restrictionText);
|
||||
}
|
||||
}
|
||||
|
||||
var editButton = '';
|
||||
|
||||
var deleteButton = '';
|
||||
|
||||
if (userProfile.userId != result[i].id) {
|
||||
editButton = '<a href="#" onclick="showDialog(\'settingsuseredit\', \'' + result[i].id + '\');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
||||
|
||||
deleteButton = '<a href="#" onclick="showSubDialog(\'settingsuserdelete\', \'' + result[i].id + '\');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
||||
}
|
||||
|
||||
newTable.appendChild(
|
||||
createTableRow(
|
||||
false,
|
||||
[
|
||||
result[i].emailAddress,
|
||||
roleDiv,
|
||||
ageRestrictionPolicyDescription,
|
||||
'<div style="text-align: right;">' + editButton + deleteButton + '</div>'
|
||||
],
|
||||
'romrow',
|
||||
'romcell'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
targetDiv.appendChild(newTable);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
GetUsers();
|
||||
</script>
|
@@ -171,7 +171,7 @@ function buildFilterPanelItem(filterType, itemString, friendlyItemString, tags)
|
||||
filterPanelItemCheckBoxItem.className = 'filter_panel_item_checkbox';
|
||||
filterPanelItemCheckBoxItem.name = 'filter_' + filterType;
|
||||
filterPanelItemCheckBoxItem.setAttribute('filter_id', itemString);
|
||||
filterPanelItemCheckBoxItem.setAttribute('oninput' , 'executeFilter();');
|
||||
filterPanelItemCheckBoxItem.setAttribute('oninput' , 'executeFilter1_1();');
|
||||
if (checkState == true) {
|
||||
filterPanelItemCheckBoxItem.checked = true;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ function executeFilterDelayed() {
|
||||
filterExecutor = null;
|
||||
}
|
||||
|
||||
filterExecutor = setTimeout(executeFilter, 1000);
|
||||
filterExecutor = setTimeout(executeFilter1_1, 1000);
|
||||
}
|
||||
|
||||
function executeFilter() {
|
||||
@@ -299,4 +299,82 @@ function buildFilterTag(tags) {
|
||||
}
|
||||
|
||||
return boundingDiv;
|
||||
}
|
||||
|
||||
function executeFilter1_1() {
|
||||
console.log("Execute filter 1.1");
|
||||
var minUserRating = -1;
|
||||
var minUserRatingInput = document.getElementById('filter_panel_userrating_min');
|
||||
if (minUserRatingInput.value) {
|
||||
minUserRating = minUserRatingInput.value;
|
||||
}
|
||||
setCookie(minUserRatingInput.id, minUserRatingInput.value);
|
||||
|
||||
var maxUserRating = -1;
|
||||
var maxUserRatingInput = document.getElementById('filter_panel_userrating_max');
|
||||
if (maxUserRatingInput.value) {
|
||||
maxUserRating = maxUserRatingInput.value;
|
||||
}
|
||||
setCookie(maxUserRatingInput.id, maxUserRatingInput.value);
|
||||
|
||||
// build filter model
|
||||
var model = {
|
||||
"Name": document.getElementById('filter_panel_search').value,
|
||||
"Platform": GetFilterQuery1_1('platform'),
|
||||
"Genre": GetFilterQuery1_1('genre'),
|
||||
"GameMode": GetFilterQuery1_1('gamemmode'),
|
||||
"PlayerPerspective": GetFilterQuery1_1('playerperspective'),
|
||||
"Theme": GetFilterQuery1_1('theme'),
|
||||
"GameRating": {
|
||||
"MinimumRating": minUserRating,
|
||||
"MinimumRatingCount": -1,
|
||||
"MaximumRating": maxUserRating,
|
||||
"MaximumRatingCount": -1,
|
||||
"IncludeUnrated": true
|
||||
},
|
||||
"GameAgeRating": {
|
||||
"AgeGroupings": [
|
||||
"Child",
|
||||
"Teen",
|
||||
"Mature",
|
||||
"Adult"
|
||||
],
|
||||
"IncludeUnrated": true
|
||||
},
|
||||
"Sorting": {
|
||||
"SortBy": "NameThe",
|
||||
"SortAscenting": true
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Search model = ' + JSON.stringify(model));
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/Games',
|
||||
'POST',
|
||||
function (result) {
|
||||
var gameElement = document.getElementById('games_library');
|
||||
formatGamesPanel(gameElement, result);
|
||||
},
|
||||
function (error) {
|
||||
console.log('An error occurred: ' + JSON.stringify(error));
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
|
||||
function GetFilterQuery1_1(filterName) {
|
||||
var Filters = document.getElementsByName('filter_' + filterName);
|
||||
var selections = [];
|
||||
|
||||
for (var i = 0; i < Filters.length; i++) {
|
||||
if (Filters[i].checked) {
|
||||
setCookie(Filters[i].id, true);
|
||||
selections.push(Filters[i].getAttribute('filter_id'));
|
||||
} else {
|
||||
setCookie(Filters[i].id, false);
|
||||
}
|
||||
}
|
||||
|
||||
return selections;
|
||||
}
|
@@ -20,7 +20,7 @@ function renderGameIcon(gameObject, showTitle, showRatings) {
|
||||
var gameImage = document.createElement('img');
|
||||
gameImage.className = 'game_tile_image lazy';
|
||||
if (gameObject.cover) {
|
||||
gameImage.setAttribute('data-src', '/api/v1.0/Games/' + gameObject.id + '/cover/image');
|
||||
gameImage.setAttribute('data-src', '/api/v1.1/Games/' + gameObject.id + '/cover/image');
|
||||
} else {
|
||||
gameImage.src = '/images/unknowngame.png';
|
||||
gameImage.className = 'game_tile_image unknown';
|
||||
@@ -40,7 +40,7 @@ function renderGameIcon(gameObject, showTitle, showRatings) {
|
||||
ratingsSection.id = 'ratings_section';
|
||||
for (var i = 0; i < gameObject.ageRatings.ids.length; i++) {
|
||||
var ratingImage = document.createElement('img');
|
||||
ratingImage.src = '/api/v1.0/Games/' + gameObject.id + '/agerating/' + gameObject.ageRatings.ids[i] + '/image';
|
||||
ratingImage.src = '/api/v1.1/Games/' + gameObject.id + '/agerating/' + gameObject.ageRatings.ids[i] + '/image';
|
||||
ratingImage.className = 'rating_image_mini';
|
||||
ratingsSection.appendChild(ratingImage);
|
||||
}
|
||||
|
@@ -373,4 +373,19 @@ function LoadEditableTableData(TableName, Headers, Values) {
|
||||
|
||||
eTable.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
function CreateBadge(BadgeText, ColourOverride) {
|
||||
var badgeItem = document.createElement('div');
|
||||
badgeItem.className = 'dropdownroleitem';
|
||||
badgeItem.innerHTML = BadgeText.toUpperCase();
|
||||
var colorVal = intToRGB(hashCode(BadgeText));
|
||||
if (!ColourOverride) {
|
||||
badgeItem.style.backgroundColor = '#' + colorVal;
|
||||
badgeItem.style.borderColor = '#' + colorVal;
|
||||
} else {
|
||||
badgeItem.style.backgroundColor = ColourOverride;
|
||||
badgeItem.style.borderColor = ColourOverride;
|
||||
}
|
||||
return badgeItem;
|
||||
}
|
@@ -30,12 +30,12 @@ h3 {
|
||||
.modal {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 1; /* Sit on top */
|
||||
z-index: 100; /* Sit on top */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
overflow: none; /* Enable scroll if needed */
|
||||
background-color: rgb(0,0,0); /* Fallback color */
|
||||
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||
backdrop-filter: blur(8px);
|
||||
@@ -47,9 +47,10 @@ h3 {
|
||||
/* Modal Content/Box */
|
||||
.modal-content {
|
||||
background-color: #383838;
|
||||
margin: 15% auto; /* 15% from the top and centered */
|
||||
margin: 10% auto; /* 15% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 700px; /* Could be more or less, depending on screen size */
|
||||
min-height: 358px;
|
||||
}
|
||||
@@ -58,6 +59,7 @@ h3 {
|
||||
margin: 20% auto; /* 20% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 300px; /* Could be more or less, depending on screen size */
|
||||
min-height: 110px;
|
||||
}
|
||||
@@ -205,7 +207,7 @@ h3 {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
input[type='text'], input[type='number'] {
|
||||
input[type='text'], input[type='number'], input[type="email"], input[type="password"] {
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
@@ -409,7 +411,7 @@ input[id='filter_panel_userrating_max'] {
|
||||
display: inline-block;
|
||||
max-width: 32px;
|
||||
max-height: 32px;
|
||||
margin-right: 2px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#gamescreenshots {
|
||||
@@ -621,14 +623,14 @@ th {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div[name="properties_toc_item"] {
|
||||
div[name="properties_toc_item"],div[name="properties_user_toc_item"],div[name="properties_profile_toc_item"] {
|
||||
padding: 10px;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #2b2b2b;
|
||||
}
|
||||
|
||||
div[name="properties_toc_item"]:hover {
|
||||
div[name="properties_toc_item"]:hover,div[name="properties_user_toc_item"]:hover,div[name="properties_profile_toc_item"]:hover {
|
||||
background-color: #2b2b2b;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -965,4 +967,98 @@ button:disabled {
|
||||
|
||||
.romGroupTitles {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.loginwindow {
|
||||
position: fixed; /* Stay in place */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
/*background-color: rgb(0,0,0); /* Fallback color */
|
||||
/*background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||
/*backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);*/
|
||||
filter: drop-shadow(5px 5px 10px #000);
|
||||
-webkit-filter: drop-shadow(5px 5px 10px #000);
|
||||
}
|
||||
|
||||
/* Modal Content/Box */
|
||||
.loginwindow-content {
|
||||
position: relative;
|
||||
background-color: #383838;
|
||||
margin: 15% auto; /* 15% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 350px; /* Could be more or less, depending on screen size */
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
#loginwindow_header_label {
|
||||
font-family: Commodore64;
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
font-size: 24pt;
|
||||
vertical-align: top;
|
||||
/*color: #edeffa;*/
|
||||
color: #7c70da;
|
||||
}
|
||||
|
||||
/* The container <div> - needed to position the dropdown content */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Dropdown Content (Hidden by Default) */
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #f1f1f1;
|
||||
min-width: 160px;
|
||||
/* box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); */
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
top: 40px;
|
||||
filter: drop-shadow(5px 5px 10px #000);
|
||||
-webkit-filter: drop-shadow(5px 5px 10px #000);
|
||||
}
|
||||
|
||||
/* Links inside the dropdown */
|
||||
.dropdown-content a, .dropdown-content span {
|
||||
color: black;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-content span {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
/* Change color of dropdown links on hover */
|
||||
.dropdown-content a:hover {background-color: #ddd;}
|
||||
|
||||
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
|
||||
.show {display:block;}
|
||||
|
||||
.dropdownroleitem {
|
||||
text-transform: capitalize;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
background-color: red;
|
||||
border-color: red;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
padding: 3px 6px;
|
||||
display: inline-block;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
Reference in New Issue
Block a user