Add authentication support (#185)

This commit is contained in:
Michael Green
2023-11-25 14:50:44 +11:00
committed by GitHub
parent 2ade60c551
commit 3d2f94681a
88 changed files with 6187 additions and 124 deletions

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

View File

@@ -0,0 +1,53 @@
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
{
[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()
{
return ProcessQueue.QueueItems;
}
[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)
{
if (qi.AllowManualStart == true)
{
if (TaskType == qi.ItemType)
{
if (ForceRun == true)
{
qi.ForceExecute();
}
return qi;
}
}
}
return NotFound();
}
}
}

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
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
{
[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()
{
return Classes.Bios.GetBios();
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{PlatformId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public List<Classes.Bios.BiosItem> GetBios(long PlatformId, bool AvailableOnly = true)
{
return Classes.Bios.GetBios(PlatformId, AvailableOnly);
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpHead]
[Route("zip/{PlatformId}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetBiosCompressed(long PlatformId)
{
try
{
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platform.Slug);
string tempFile = Path.GetTempFileName();
using (FileStream zipFile = System.IO.File.Create(tempFile))
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
{
foreach (string file in Directory.GetFiles(biosPath))
{
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
}
}
var stream = new FileStream(tempFile, FileMode.Open);
return File(stream, "application/zip", platform.Slug + ".zip");
}
catch
{
return NotFound();
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpHead]
[Route("{PlatformId}/{BiosName}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult BiosFile(long PlatformId, string BiosName)
{
try
{
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios(PlatformId, true))
{
if (biosItem.filename == BiosName)
{
if (System.IO.File.Exists(biosItem.biosPath))
{
string filename = Path.GetFileName(biosItem.biosPath);
string filepath = biosItem.biosPath;
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
string contentType = "application/octet-stream";
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = false,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("Cache-Control", "public, max-age=604800");
return File(filedata, contentType);
}
else
{
return NotFound();
}
}
}
return NotFound();
}
catch
{
return NotFound();
}
}
}
}

View File

@@ -0,0 +1,255 @@
using System;
using System.Collections.Generic;
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
{
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
[Authorize]
public class CollectionsController : Controller
{
/// <summary>
/// Gets all ROM collections
/// </summary>
/// <returns></returns>
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public List<Classes.Collections.CollectionItem> GetCollections()
{
return Classes.Collections.GetCollections();
}
/// <summary>
/// Gets a specific ROM collection
/// </summary>
/// <param name="CollectionId"></param>
/// <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)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetCollection(long CollectionId, bool Build = false)
{
try
{
if (Build == true)
{
Classes.Collections.StartCollectionItemBuild(CollectionId);
}
return Ok(Classes.Collections.GetCollection(CollectionId));
}
catch
{
return NotFound();
}
}
/// <summary>
/// Gets the contents of the specified ROM collection
/// </summary>
/// <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)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetCollectionRoms(long CollectionId)
{
try
{
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
return Ok(Classes.Collections.GetCollectionContent(collectionItem));
}
catch
{
return NotFound();
}
}
/// <summary>
/// Gets a preview of the provided collection item
/// </summary>
/// <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)
{
try
{
return Ok(Classes.Collections.GetCollectionContent(Item));
}
catch (Exception ex)
{
return NotFound(ex);
}
}
/// <summary>
/// Gets ROM collection in zip format
/// </summary>
/// <param name="CollectionId"></param>
/// <returns></returns>
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{CollectionId}/Roms/Zip")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetCollectionRomsZip(long CollectionId)
{
try
{
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, CollectionId + ".zip");
if (System.IO.File.Exists(ZipFilePath))
{
var stream = new FileStream(ZipFilePath, FileMode.Open);
return File(stream, "application/zip", collectionItem.Name + ".zip");
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
/// <summary>
/// Creates a new ROM collection
/// </summary>
/// <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)
{
try
{
return Ok(Classes.Collections.NewCollection(Item));
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
/// <summary>
/// Edits an existing collection
/// </summary>
/// <param name="CollectionId"></param>
/// <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)
{
try
{
return Ok(Classes.Collections.EditCollection(CollectionId, Item, true));
}
catch
{
return NotFound();
}
}
/// <summary>
/// Edits an existing collection
/// </summary>
/// <param name="CollectionId"></param>
/// <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)]
public ActionResult EditCollectionAlwaysInclude(long CollectionId, [FromQuery]bool Rebuild, [FromBody]Collections.CollectionItem.AlwaysIncludeItem Inclusion)
{
try
{
Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
bool ItemFound = false;
foreach (Collections.CollectionItem.AlwaysIncludeItem includeItem in collectionItem.AlwaysInclude)
{
if (includeItem.PlatformId == Inclusion.PlatformId && includeItem.GameId == Inclusion.GameId)
{
ItemFound = true;
}
}
if (ItemFound == false)
{
collectionItem.AlwaysInclude.Add(Inclusion);
}
return Ok(Classes.Collections.EditCollection(CollectionId, collectionItem, Rebuild));
}
catch
{
return NotFound();
}
}
/// <summary>
/// Deletes the specified ROM collection
/// </summary>
/// <param name="CollectionId"></param>
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpDelete]
[Authorize(Roles = "Admin,Gamer")]
[Route("{CollectionId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult DeleteCollection(long CollectionId)
{
try
{
Classes.Collections.DeleteCollection(CollectionId);
return Ok();
}
catch
{
return NotFound();
}
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Data;
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;
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")]
public Dictionary<string, object> Filter()
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
Dictionary<string, object> FilterSet = new Dictionary<string, object>();
// platforms
List<FilterPlatform> platforms = new List<FilterPlatform>();
//string sql = "SELECT Platform.Id, Platform.Abbreviation, Platform.AlternativeName, Platform.`Name`, Platform.PlatformLogo, (SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.PlatformId = Platform.Id) AS RomCount FROM Platform HAVING RomCount > 0 ORDER BY `Name`";
string sql = "SELECT Platform.Id, Platform.Abbreviation, Platform.AlternativeName, Platform.`Name`, Platform.PlatformLogo, (SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.PlatformId = Platform.Id) AS RomCount, (SELECT COUNT(*) AS GameCount FROM (SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Games_Roms.PlatformId FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId) Game WHERE Game.PlatformId = Platform.Id) AS GameCount FROM Platform HAVING RomCount > 0 ORDER BY `Name`";
DataTable dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
FilterPlatform platformItem = new FilterPlatform(Classes.Metadata.Platforms.GetPlatform((long)dr["id"]));
platformItem.RomCount = (int)(long)dr["RomCount"];
platformItem.GameCount = (int)(long)dr["GameCount"];
platforms.Add(platformItem);
}
FilterSet.Add("platforms", platforms);
// genres
List<Genre> genres = new List<Genre>();
sql = "SELECT DISTINCT Relation_Game_Genres.GenresId AS id, Genre.`Name` FROM Relation_Game_Genres JOIN Genre ON Relation_Game_Genres.GenresId = Genre.Id WHERE Relation_Game_Genres.GameId IN (SELECT DISTINCT GameId FROM Games_Roms) ORDER BY `Name`;";
dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
genres.Add(Classes.Metadata.Genres.GetGenres((long)dr["id"]));
}
FilterSet.Add("genres", genres);
// game modes
List<GameMode> gameModes = new List<GameMode>();
sql = "SELECT DISTINCT Relation_Game_GameModes.GameModesId AS id, GameMode.`Name` FROM Relation_Game_GameModes JOIN GameMode ON Relation_Game_GameModes.GameModesId = GameMode.Id WHERE Relation_Game_GameModes.GameId IN (SELECT DISTINCT GameId FROM Games_Roms) ORDER BY `Name`;";
dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
gameModes.Add(Classes.Metadata.GameModes.GetGame_Modes((long)dr["id"]));
}
FilterSet.Add("gamemodes", gameModes);
// player perspectives
List<PlayerPerspective> playerPerspectives = new List<PlayerPerspective>();
sql = "SELECT DISTINCT Relation_Game_PlayerPerspectives.PlayerPerspectivesId AS id, PlayerPerspective.`Name` FROM Relation_Game_PlayerPerspectives JOIN PlayerPerspective ON Relation_Game_PlayerPerspectives.PlayerPerspectivesId = PlayerPerspective.Id WHERE Relation_Game_PlayerPerspectives.GameId IN (SELECT DISTINCT GameId FROM Games_Roms) ORDER BY `Name`;";
dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
playerPerspectives.Add(Classes.Metadata.PlayerPerspectives.GetGame_PlayerPerspectives((long)dr["id"]));
}
FilterSet.Add("playerperspectives", playerPerspectives);
// themes
List<Theme> themes = new List<Theme>();
sql = "SELECT DISTINCT Relation_Game_Themes.ThemesId AS id, Theme.`Name` FROM Relation_Game_Themes JOIN Theme ON Relation_Game_Themes.ThemesId = Theme.Id WHERE Relation_Game_Themes.GameId IN (SELECT DISTINCT GameId FROM Games_Roms) ORDER BY `Name`;";
dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
themes.Add(Classes.Metadata.Themes.GetGame_Themes((long)dr["id"]));
}
FilterSet.Add("themes", themes);
return FilterSet;
}
public class FilterPlatform : IGDB.Models.Platform
{
public FilterPlatform(Platform platform)
{
var properties = platform.GetType().GetProperties();
foreach (var prop in properties)
{
if (prop.GetGetMethod() != null)
{
this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(platform));
}
}
}
public int RomCount { get; set; }
public int GameCount { get; set; }
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
using System;
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
{
[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()
{
return Ok(GameLibrary.GetLibraries);
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet("{LibraryId}")]
[ProducesResponseType(typeof(GameLibrary.LibraryItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetLibrary(int LibraryId)
{
try
{
return Ok(GameLibrary.GetLibrary(LibraryId));
}
catch
{
return NotFound();
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpPost]
[ProducesResponseType(typeof(GameLibrary.LibraryItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public ActionResult AddLibrary(string Name, string Path, long DefaultPlatformId)
{
try
{
return Ok(GameLibrary.AddLibrary(Name, Path, DefaultPlatformId));
}
catch (GameLibrary.PathExists exPE)
{
return Conflict("Path already used in another library");
}
catch (GameLibrary.PathNotFound exPNF)
{
return NotFound("Path not found");
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpDelete("{LibraryId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult DelLibrary(int LibraryId)
{
try
{
GameLibrary.DeleteLibrary(LibraryId);
return Ok();
}
catch (GameLibrary.CannotDeleteDefaultLibrary exCDDL)
{
return BadRequest(exCDDL.ToString());
}
catch (GameLibrary.LibraryNotFound exLNF)
{
return NotFound(exLNF.ToString());
}
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
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
{
[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)
{
return Logging.GetLogs(StartIndex, PageNumber, PageSize);
}
}
}

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using gaseous_server.Classes.Metadata;
using gaseous_server.Models;
using gaseous_server.Classes;
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)
{
if (ResetToDefault == true)
{
PlatformMapping.ExtractPlatformMap(true);
}
return Ok(PlatformMapping.PlatformMap);
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{PlatformId}")]
[ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult PlatformMap(long PlatformId)
{
try
{
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
if (platformMapItem != null)
{
return Ok(platformMapItem);
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
[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();
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
long size = files.Sum(f => f.Length);
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
foreach (IFormFile formFile in files)
{
if (formFile.Length > 0)
{
Guid FileId = Guid.NewGuid();
string filePath = Path.Combine(workPath, Path.GetFileName(formFile.FileName));
if (!Directory.Exists(workPath))
{
Directory.CreateDirectory(workPath);
}
using (var stream = System.IO.File.Create(filePath))
{
await formFile.CopyToAsync(stream);
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
UploadedFile.Add("id", FileId.ToString());
UploadedFile.Add("originalname", Path.GetFileName(formFile.FileName));
UploadedFile.Add("fullpath", filePath);
UploadedFiles.Add(UploadedFile);
}
}
}
// Process uploaded files
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
{
Models.PlatformMapping.ExtractPlatformMap((string)UploadedFile["fullpath"]);
}
if (Directory.Exists(workPath))
{
Directory.Delete(workPath, true);
}
return Ok(new { count = files.Count, size });
}
// [MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpPost]
// [Route("{PlatformId}")]
// [ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
// [ProducesResponseType(StatusCodes.Status404NotFound)]
// [ProducesResponseType(StatusCodes.Status409Conflict)]
// public ActionResult NewPlatformMap(long PlatformId, PlatformMapping.PlatformMapItem Map)
// {
// try
// {
// PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
// if (platformMapItem != null)
// {
// return Conflict();
// }
// else
// {
// PlatformMapping.WritePlatformMap(Map, false, false);
// return Ok(PlatformMapping.GetPlatformMap(PlatformId));
// }
// }
// catch
// {
// return NotFound();
// }
// }
[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
{
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
if (platformMapItem != null)
{
PlatformMapping.WritePlatformMap(Map, true, false);
return Ok(PlatformMapping.GetPlatformMap(PlatformId));
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
}
}

View File

@@ -0,0 +1,155 @@
using System;
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 gaseous_server.Models;
using IGDB.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.Scripting;
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()
{
return Ok(PlatformsController.GetPlatforms());
}
public static List<Platform> GetPlatforms()
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT * FROM Platform WHERE Id IN (SELECT DISTINCT PlatformId FROM Games_Roms) ORDER BY `Name` ASC;";
List<Platform> RetVal = new List<Platform>();
DataTable dbResponse = db.ExecuteCMD(sql);
foreach (DataRow dr in dbResponse.Rows)
{
RetVal.Add(Classes.Metadata.Platforms.GetPlatform((long)dr["id"]));
}
return RetVal;
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{PlatformId}")]
[ProducesResponseType(typeof(Platform), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult Platform(long PlatformId)
{
try
{
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
if (platformObject != null)
{
return Ok(platformObject);
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{PlatformId}/platformlogo")]
[ProducesResponseType(typeof(PlatformLogo), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult PlatformLogo(long PlatformId)
{
try
{
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
if (platformObject != null)
{
IGDB.Models.PlatformLogo logoObject = PlatformLogos.GetPlatformLogo(platformObject.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
if (logoObject != null)
{
return Ok(logoObject);
}
else
{
return NotFound();
}
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("{PlatformId}/platformlogo/image")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult PlatformLogoImage(long PlatformId)
{
try
{
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
string logoFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), "Logo_Medium.png");
if (System.IO.File.Exists(logoFilePath))
{
string filename = "Logo.png";
string filepath = logoFilePath;
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
string contentType = "image/png";
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = true,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
else
{
return NotFound();
}
}
catch
{
return NotFound();
}
}
}
}

View File

@@ -0,0 +1,91 @@
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
{
[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)]
public async Task<IActionResult> UploadRom(List<IFormFile> files, long? OverridePlatformId = null)
{
Guid sessionid = Guid.NewGuid();
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
long size = files.Sum(f => f.Length);
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
foreach (IFormFile formFile in files)
{
if (formFile.Length > 0)
{
Guid FileId = Guid.NewGuid();
string filePath = Path.Combine(workPath, Path.GetFileName(formFile.FileName));
if (!Directory.Exists(workPath))
{
Directory.CreateDirectory(workPath);
}
using (var stream = System.IO.File.Create(filePath))
{
await formFile.CopyToAsync(stream);
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
UploadedFile.Add("id", FileId.ToString());
UploadedFile.Add("originalname", Path.GetFileName(formFile.FileName));
UploadedFile.Add("fullpath", filePath);
UploadedFiles.Add(UploadedFile);
}
}
}
// get override platform if specified
IGDB.Models.Platform? OverridePlatform = null;
if (OverridePlatformId != null)
{
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
}
// Process uploaded files
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
{
Classes.ImportGame.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
}
if (Directory.Exists(workPath))
{
Directory.Delete(workPath, true);
}
return Ok(new { count = files.Count, size });
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
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;
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(
// Found in Twitch Developer portal for your app
Config.IGDB.ClientId,
Config.IGDB.Secret
);
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("Platform")]
[ProducesResponseType(typeof(List<Platform>), StatusCodes.Status200OK)]
public async Task<ActionResult> SearchPlatform(string SearchString)
{
List<Platform> RetVal = await _SearchForPlatform(SearchString);
return Ok(RetVal);
}
private static async Task<List<Platform>> _SearchForPlatform(string SearchString)
{
string searchBody = "";
searchBody += "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
searchBody += "where name ~ *\"" + SearchString + "\"*;";
// get Platform metadata
var results = await igdb.QueryAsync<Platform>(IGDBClient.Endpoints.Platforms, query: searchBody);
return results.ToList();
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("Game")]
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
{
List<Game> RetVal = await _SearchForGame(PlatformId, SearchString);
return Ok(RetVal);
}
private static async Task<List<Game>> _SearchForGame(long PlatformId, string SearchString)
{
string searchBody = "";
searchBody += "fields cover.*,first_release_date,name,platforms,slug; ";
searchBody += "search \"" + SearchString + "\";";
searchBody += "where platforms = (" + PlatformId + ");";
// get Platform metadata
var results = await igdb.QueryAsync<Game>(IGDBClient.Endpoints.Games, query: searchBody);
return results.ToList();
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
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
namespace gaseous_server.Controllers
{
[ApiController]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
[Authorize]
public class SignaturesController : ControllerBase
{
/// <summary>
/// Get the current signature counts from the database
/// </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()
{
return new Models.Signatures_Status();
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public List<Models.Signatures_Games> GetSignature(string md5 = "", string sha1 = "")
{
if (md5.Length > 0)
{
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
} else
{
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
}
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public List<Models.Signatures_Games> GetByTosecName(string TosecName = "")
{
if (TosecName.Length > 0)
{
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
} else
{
return null;
}
}
private List<Models.Signatures_Games> _GetSignature(string sqlWhere, string searchString)
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT view_Signatures_Games.*, Signatures_Roms.Id AS romid, Signatures_Roms.Name AS romname, Signatures_Roms.Size, Signatures_Roms.CRC, Signatures_Roms.MD5, Signatures_Roms.SHA1, Signatures_Roms.DevelopmentStatus, Signatures_Roms.Attributes, Signatures_Roms.RomType, Signatures_Roms.RomTypeMedia, Signatures_Roms.MediaLabel, Signatures_Roms.MetadataSource FROM Signatures_Roms INNER JOIN view_Signatures_Games ON Signatures_Roms.GameId = view_Signatures_Games.Id WHERE " + sqlWhere;
Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("searchString", searchString);
DataTable sigDb = db.ExecuteCMD(sql, dbDict);
List<Models.Signatures_Games> GamesList = new List<Models.Signatures_Games>();
foreach (DataRow sigDbRow in sigDb.Rows)
{
Models.Signatures_Games gameItem = new Models.Signatures_Games
{
Game = new Models.Signatures_Games.GameItem
{
Id = (Int32)sigDbRow["Id"],
Name = (string)sigDbRow["Name"],
Description = (string)sigDbRow["Description"],
Year = (string)sigDbRow["Year"],
Publisher = (string)sigDbRow["Publisher"],
Demo = (Models.Signatures_Games.GameItem.DemoTypes)(int)sigDbRow["Demo"],
System = (string)sigDbRow["Platform"],
SystemVariant = (string)sigDbRow["SystemVariant"],
Video = (string)sigDbRow["Video"],
Country = (string)sigDbRow["Country"],
Language = (string)sigDbRow["Language"],
Copyright = (string)sigDbRow["Copyright"]
},
Rom = new Models.Signatures_Games.RomItem
{
Id = (Int32)sigDbRow["romid"],
Name = (string)sigDbRow["romname"],
Size = (Int64)sigDbRow["Size"],
Crc = (string)sigDbRow["CRC"],
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
RomType = (RomSignatureObject.Game.Rom.RomTypes)(int)sigDbRow["RomType"],
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
MediaLabel = (string)sigDbRow["MediaLabel"],
SignatureSource = (gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType)(Int32)sigDbRow["MetadataSource"]
}
};
GamesList.Add(gameItem);
}
return GamesList;
}
}
}

View File

@@ -0,0 +1,142 @@
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 gaseous_server.Classes;
using gaseous_server.Classes.Metadata;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
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()
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
SystemInfo ReturnValue = new SystemInfo();
// disk size
List<SystemInfo.PathItem> Disks = new List<SystemInfo.PathItem>();
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
{
Disks.Add(GetDisk(libraryItem.Path));
}
ReturnValue.Paths = Disks;
// database size
string sql = "SELECT table_schema, SUM(data_length + index_length) FROM information_schema.tables WHERE table_schema = '" + Config.DatabaseConfiguration.DatabaseName + "'";
DataTable dbResponse = db.ExecuteCMD(sql);
ReturnValue.DatabaseSize = (long)(System.Decimal)dbResponse.Rows[0][1];
// platform statistics
sql = "SELECT Platform.`name`, grc.Count, grs.Size FROM Platform INNER JOIN (SELECT Platform.`name` AS `Name`, SUM(grs.Size) AS Size FROM Platform JOIN Games_Roms AS grs ON (grs.PlatformId = Platform.Id) GROUP BY Platform.`name`) grs ON (grs.`Name` = Platform.`name`) INNER JOIN (SELECT Platform.`name` AS `Name`, COUNT(grc.Size) AS Count FROM Platform JOIN Games_Roms AS grc ON (grc.PlatformId = Platform.Id) GROUP BY Platform.`name`) grc ON (grc.`Name` = Platform.`name`) ORDER BY Platform.`name`;";
dbResponse = db.ExecuteCMD(sql);
ReturnValue.PlatformStatistics = new List<SystemInfo.PlatformStatisticsItem>();
foreach (DataRow dr in dbResponse.Rows)
{
SystemInfo.PlatformStatisticsItem platformStatisticsItem = new SystemInfo.PlatformStatisticsItem
{
Platform = (string)dr["name"],
RomCount = (long)dr["Count"],
TotalSize = (long)(System.Decimal)dr["Size"]
};
ReturnValue.PlatformStatistics.Add(platformStatisticsItem);
}
return ReturnValue;
}
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("Version")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Version GetSystemVersion() {
return Assembly.GetExecutingAssembly().GetName().Version;
}
[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() + "\";" + 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");
}
private SystemInfo.PathItem GetDisk(string Path)
{
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
LibraryPath = Path,
SpaceUsed = Common.DirSize(new DirectoryInfo(Path)),
SpaceAvailable = new DriveInfo(Path).AvailableFreeSpace,
TotalSpace = new DriveInfo(Path).TotalSize
};
return pathItem;
}
public class SystemInfo
{
public Version ApplicationVersion {
get
{
return Assembly.GetExecutingAssembly().GetName().Version;
}
}
public List<PathItem>? Paths { get; set; }
public long DatabaseSize { get; set; }
public List<PlatformStatisticsItem>? PlatformStatistics { get; set; }
public class PathItem
{
public string LibraryPath { get; set; }
public long SpaceUsed { get; set; }
public long SpaceAvailable { get; set; }
public long TotalSpace { get; set; }
}
public class PlatformStatisticsItem
{
public string Platform { get; set; }
public long RomCount { get; set; }
public long TotalSize { get; set; }
}
}
}
}