diff --git a/gaseous-server/Classes/Collections.cs b/gaseous-server/Classes/Collections.cs index 7c665fc..3faa4e7 100644 --- a/gaseous-server/Classes/Collections.cs +++ b/gaseous-server/Classes/Collections.cs @@ -220,7 +220,7 @@ namespace gaseous_server.Classes } } else { // get all platforms to pull from - Dictionary FilterDict = Filters.Filter(AgeRatings.AgeGroups.AgeRestrictionGroupings.Adult, true); + Dictionary> FilterDict = Filters.Filter(AgeRatings.AgeGroups.AgeRestrictionGroupings.Adult, true); List filteredPlatforms = (List)FilterDict["platforms"]; foreach (Filters.FilterItem filterItem in filteredPlatforms) { platforms.Add(Platforms.GetPlatform(filterItem.Id)); @@ -499,7 +499,7 @@ namespace gaseous_server.Classes if (File.Exists(gameRomItem.Path)) { Logging.Log(Logging.LogType.Information, "Collections", "Copying ROM: " + gameRomItem.Name); - File.Copy(gameRomItem.Path, Path.Combine(ZipGamePath, gameRomItem.Name)); + File.Copy(gameRomItem.Path, Path.Combine(ZipGamePath, gameRomItem.Name), true); } } } diff --git a/gaseous-server/Classes/Filters.cs b/gaseous-server/Classes/Filters.cs index cbc07e1..f2fc304 100644 --- a/gaseous-server/Classes/Filters.cs +++ b/gaseous-server/Classes/Filters.cs @@ -7,11 +7,11 @@ namespace gaseous_server.Classes { public class Filters { - public static Dictionary Filter(Metadata.AgeRatings.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction, bool IncludeUnrated) + public static Dictionary> Filter(Metadata.AgeRatings.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction, bool IncludeUnrated) { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - Dictionary FilterSet = new Dictionary(); + Dictionary> FilterSet = new Dictionary>(); // platforms List platforms = new List(); @@ -81,22 +81,24 @@ namespace gaseous_server.Classes FilterSet.Add("themes", themes); // age groups - List agegroupings = new List(); + List agegroupings = new List(); sql = "SELECT view_Games.Id, view_Games.AgeGroupId, COUNT(view_Games.Id) AS GameCount FROM view_Games WHERE (" + ageRestriction_Generic + ") GROUP BY view_Games.AgeGroupId ORDER BY view_Games.AgeGroupId DESC;"; dbResponse = db.ExecuteCMD(sql); foreach (DataRow dr in dbResponse.Rows) { - FilterAgeGrouping filterAgeGrouping = new FilterAgeGrouping(); + FilterItem filterAgeGrouping = new FilterItem(); if (dr["AgeGroupId"] == DBNull.Value) { - filterAgeGrouping.Id = (long)AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified; - filterAgeGrouping.AgeGroup = AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified; + filterAgeGrouping.Id = (int)(long)AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified; + filterAgeGrouping.Name = AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified.ToString(); } else { - filterAgeGrouping.Id = (long)(AgeRatings.AgeGroups.AgeRestrictionGroupings)dr["AgeGroupId"]; - filterAgeGrouping.AgeGroup = (AgeRatings.AgeGroups.AgeRestrictionGroupings)dr["AgeGroupId"]; + long ageGroupLong = (long)dr["AgeGroupId"]; + AgeRatings.AgeGroups.AgeRestrictionGroupings ageGroup = (AgeRatings.AgeGroups.AgeRestrictionGroupings)ageGroupLong; + filterAgeGrouping.Id = ageGroupLong; + filterAgeGrouping.Name = ageGroup.ToString(); } filterAgeGrouping.GameCount = (int)(long)dr["GameCount"]; agegroupings.Add(filterAgeGrouping); @@ -117,6 +119,11 @@ namespace gaseous_server.Classes public class FilterItem { + public FilterItem() + { + + } + public FilterItem(DataRow dr) { this.Id = (long)dr["Id"]; @@ -130,22 +137,5 @@ namespace gaseous_server.Classes public int GameCount { get; set; } } - - public class FilterAgeGrouping - { - public long Id { get; set; } - - public AgeRatings.AgeGroups.AgeRestrictionGroupings AgeGroup { get ; set; } - - public string Name - { - get - { - return this.AgeGroup.ToString(); - } - } - - public int GameCount { get; set; } - } } } \ No newline at end of file diff --git a/gaseous-server/Classes/ImportGames.cs b/gaseous-server/Classes/ImportGames.cs index c643227..843be99 100644 --- a/gaseous-server/Classes/ImportGames.cs +++ b/gaseous-server/Classes/ImportGames.cs @@ -690,25 +690,32 @@ namespace gaseous_server.Classes IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(sig.Flags.IGDBPlatformId); IGDB.Models.Game determinedGame = new Game(); - if (determinedPlatform == null) + try { - if (library.DefaultPlatformId == 0) + if (determinedPlatform == null) { - determinedPlatform = new IGDB.Models.Platform(); - determinedGame = SearchForGame(sig.Game.Name, sig.Flags.IGDBPlatformId); + if (library.DefaultPlatformId == 0) + { + determinedPlatform = new IGDB.Models.Platform(); + determinedGame = SearchForGame(sig.Game.Name, sig.Flags.IGDBPlatformId); + } + else + { + determinedPlatform = Platforms.GetPlatform(library.DefaultPlatformId); + determinedGame = SearchForGame(sig.Game.Name, library.DefaultPlatformId); + } } else { - determinedPlatform = Platforms.GetPlatform(library.DefaultPlatformId); - determinedGame = SearchForGame(sig.Game.Name, library.DefaultPlatformId); + determinedGame = SearchForGame(sig.Game.Name, (long)determinedPlatform.Id); } - } - else - { - determinedGame = SearchForGame(sig.Game.Name, (long)determinedPlatform.Id); - } - StoreROM(library, hash, determinedGame, determinedPlatform, sig, LibraryFile); + StoreROM(library, hash, determinedGame, determinedPlatform, sig, LibraryFile); + } + catch (Exception ex) + { + Logging.Log(Logging.LogType.Warning, "Library Scan", " An error occurred while matching orphaned file: " + LibraryFile + ". Skipping.", ex); + } } } StatusCount += 1; @@ -720,6 +727,7 @@ namespace gaseous_server.Classes // check all roms to see if their local file still exists Logging.Log(Logging.LogType.Information, "Library Scan", "Checking library files exist on disk"); + StatusCount = 0; if (dtRoms.Rows.Count > 0) { for (var i = 0; i < dtRoms.Rows.Count; i++) @@ -728,6 +736,7 @@ namespace gaseous_server.Classes string romPath = (string)dtRoms.Rows[i]["Path"]; gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType romMetadataSource = (gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType)(int)dtRoms.Rows[i]["MetadataSource"]; + SetStatus(StatusCount, dtRoms.Rows.Count, "Processing file " + romPath); Logging.Log(Logging.LogType.Information, "Library Scan", " Processing ROM at path " + romPath); if (File.Exists(romPath)) @@ -751,6 +760,8 @@ namespace gaseous_server.Classes deleteDict.Add("libraryid", library.Id); db.ExecuteCMD(deleteSql, deleteDict); } + + StatusCount += 1; } } diff --git a/gaseous-server/Classes/Logging.cs b/gaseous-server/Classes/Logging.cs index b72437b..69f1514 100644 --- a/gaseous-server/Classes/Logging.cs +++ b/gaseous-server/Classes/Logging.cs @@ -109,8 +109,25 @@ namespace gaseous_server.Classes callingProcess = ""; } + string callingUser; + try + { + if (CallContext.GetData("CallingUser").ToString() == null) + { + callingUser = ""; + } + else + { + callingUser = CallContext.GetData("CallingUser").ToString(); + } + } + catch + { + callingUser = ""; + } + Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate; INSERT INTO ServerLogs (EventTime, EventType, Process, Message, Exception, CorrelationId, CallingProcess) VALUES (@EventTime, @EventType, @Process, @Message, @Exception, @correlationid, @callingprocess);"; + string sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate; INSERT INTO ServerLogs (EventTime, EventType, Process, Message, Exception, CorrelationId, CallingProcess, CallingUser) VALUES (@EventTime, @EventType, @Process, @Message, @Exception, @correlationid, @callingprocess, @callinguser);"; Dictionary dbDict = new Dictionary(); dbDict.Add("EventRententionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1)); dbDict.Add("EventTime", logItem.EventTime); @@ -120,6 +137,7 @@ namespace gaseous_server.Classes dbDict.Add("Exception", Common.ReturnValueIfNull(logItem.ExceptionValue, "").ToString()); dbDict.Add("correlationid", correlationId); dbDict.Add("callingprocess", callingProcess); + dbDict.Add("callinguser", callingUser); try { @@ -238,6 +256,15 @@ namespace gaseous_server.Classes } } + if (model.CallingUser != null) + { + if (model.CallingUser.Length > 0) + { + dbDict.Add("callingUser", model.CallingUser); + whereClauses.Add("CallingUser = @callingUser"); + } + } + // compile WHERE clause string whereClause = ""; if (whereClauses.Count > 0) @@ -252,7 +279,8 @@ namespace gaseous_server.Classes { whereClause = "WHERE " + whereClause; } - sql = "SELECT * FROM ServerLogs " + whereClause + " ORDER BY Id DESC LIMIT @PageSize OFFSET @PageNumber;"; + + sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;"; } else { @@ -260,7 +288,8 @@ namespace gaseous_server.Classes { whereClause = "AND " + whereClause; } - sql = "SELECT * FROM ServerLogs WHERE Id < @StartIndex " + whereClause + " ORDER BY Id DESC LIMIT @PageSize OFFSET @PageNumber;"; + + sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id WHERE ServerLogs.Id < @StartIndex " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;"; } DataTable dataTable = db.ExecuteCMD(sql, dbDict); @@ -276,7 +305,8 @@ namespace gaseous_server.Classes Message = (string)row["Message"], ExceptionValue = (string)row["Exception"], CorrelationId = (string)Common.ReturnValueIfNull(row["CorrelationId"], ""), - CallingProcess = (string)Common.ReturnValueIfNull(row["CallingProcess"], "") + CallingProcess = (string)Common.ReturnValueIfNull(row["CallingProcess"], ""), + CallingUser = (string)Common.ReturnValueIfNull(row["Email"], "") }; logs.Add(log); @@ -301,6 +331,7 @@ namespace gaseous_server.Classes public string Process { get; set; } = ""; public string CorrelationId { get; set; } = ""; public string? CallingProcess { get; set; } = ""; + public string? CallingUser { get; set; } = ""; private string _Message = ""; public string Message { @@ -327,6 +358,7 @@ namespace gaseous_server.Classes public string? SearchText { get; set; } public string? CorrelationId { get; set; } public string? CallingProcess { get; set; } + public string? CallingUser { get; set; } } } } diff --git a/gaseous-server/Controllers/V1.1/FirstSetupController.cs b/gaseous-server/Controllers/V1.1/FirstSetupController.cs index f78376c..edf7a7c 100644 --- a/gaseous-server/Controllers/V1.1/FirstSetupController.cs +++ b/gaseous-server/Controllers/V1.1/FirstSetupController.cs @@ -52,15 +52,22 @@ namespace gaseous_server.Controllers NormalizedEmail = model.Email.ToUpper(), SecurityProfile = new SecurityProfileViewModel() }; + Logging.Log(Logging.LogType.Information, "First Run", "Creating new account " + model.Email); var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { + Logging.Log(Logging.LogType.Information, "First Run", "Creation of " + model.Email + " successful."); + Logging.Log(Logging.LogType.Information, "First Run", "Adding Player role to " + model.Email); await _userManager.AddToRoleAsync(user, "Player"); + Logging.Log(Logging.LogType.Information, "First Run", "Adding Gamer role to " + model.Email); await _userManager.AddToRoleAsync(user, "Gamer"); + Logging.Log(Logging.LogType.Information, "First Run", "Adding Admin role to " + model.Email); await _userManager.AddToRoleAsync(user, "Admin"); + Logging.Log(Logging.LogType.Information, "First Run", "Signing in as " + model.Email); await _signInManager.SignInAsync(user, isPersistent: true); + Logging.Log(Logging.LogType.Information, "First Run", "Setting first run state to 1"); Config.SetSetting("FirstRunStatus", "1"); return Ok(result); diff --git a/gaseous-server/ProcessQueue.cs b/gaseous-server/ProcessQueue.cs index de4d121..7b22b3e 100644 --- a/gaseous-server/ProcessQueue.cs +++ b/gaseous-server/ProcessQueue.cs @@ -148,6 +148,7 @@ namespace gaseous_server CallingQueueItem = this }; + // clean up Classes.ImportGame.DeleteOrphanedDirectories(Config.LibraryConfiguration.LibraryImportDirectory); _SaveLastRunTime = true; diff --git a/gaseous-server/Program.cs b/gaseous-server/Program.cs index 531c983..5e80110 100644 --- a/gaseous-server/Program.cs +++ b/gaseous-server/Program.cs @@ -297,20 +297,6 @@ using (var scope = app.Services.CreateScope()) } } - - - -app.Use(async (context, next) => -{ - // set the correlation id - string correlationId = Guid.NewGuid().ToString(); - CallContext.SetData("CorrelationId", correlationId); - CallContext.SetData("CallingProcess", context.Request.Method + ": " + context.Request.Path); - - context.Response.Headers.Add("x-correlation-id", correlationId.ToString()); - await next(); -}); - app.UseAuthorization(); app.UseDefaultFiles(); @@ -322,6 +308,28 @@ app.UseStaticFiles(new StaticFileOptions app.MapControllers(); +app.Use(async (context, next) => +{ + // set the correlation id + string correlationId = Guid.NewGuid().ToString(); + CallContext.SetData("CorrelationId", correlationId); + CallContext.SetData("CallingProcess", context.Request.Method + ": " + context.Request.Path); + + string userIdentity; + try + { + userIdentity = context.User.Claims.Where(x=>x.Type==System.Security.Claims.ClaimTypes.NameIdentifier).FirstOrDefault().Value; + } + catch + { + userIdentity = ""; + } + CallContext.SetData("CallingUser", userIdentity); + + context.Response.Headers.Add("x-correlation-id", correlationId.ToString()); + await next(); +}); + // emergency password recovery if environment variable is set // process: // - set the environment variable "recoveraccount" to the email address of the account to be recovered diff --git a/gaseous-server/Support/Database/MySQL/gaseous-1010.sql b/gaseous-server/Support/Database/MySQL/gaseous-1010.sql new file mode 100644 index 0000000..5e25351 --- /dev/null +++ b/gaseous-server/Support/Database/MySQL/gaseous-1010.sql @@ -0,0 +1,23 @@ +CREATE OR REPLACE VIEW `view_Games` AS +SELECT + a.*, b.AgeGroupId +FROM + view_GamesWithRoms a + INNER JOIN + (SELECT + view_GamesWithRoms.Id, + MAX((SELECT + AgeGroupId + FROM + ClassificationMap + WHERE + RatingId = AgeRating.Rating)) AgeGroupId + FROM + view_GamesWithRoms + LEFT JOIN Relation_Game_AgeRatings ON view_GamesWithRoms.Id = Relation_Game_AgeRatings.GameId + LEFT JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id + GROUP BY Id) b ON a.Id = b.Id +ORDER BY NameThe; + +ALTER TABLE `ServerLogs` +ADD COLUMN `CallingUser` VARCHAR(255) NULL AFTER `CallingProcess`; \ No newline at end of file diff --git a/gaseous-server/gaseous-server.csproj b/gaseous-server/gaseous-server.csproj index 869bf0c..c62d8d5 100644 --- a/gaseous-server/gaseous-server.csproj +++ b/gaseous-server/gaseous-server.csproj @@ -50,6 +50,7 @@ + @@ -182,5 +183,6 @@ + diff --git a/gaseous-server/wwwroot/pages/settings/logs.html b/gaseous-server/wwwroot/pages/settings/logs.html index d1a4fcc..e0292b0 100644 --- a/gaseous-server/wwwroot/pages/settings/logs.html +++ b/gaseous-server/wwwroot/pages/settings/logs.html @@ -139,18 +139,25 @@ for (var i = 0; i < result.length; i++) { lastStartIndex = result[i].id; + console.log(result[i]); + + var surroundingRow = document.createElement('tbody'); + surroundingRow.setAttribute('colspan', 4); + surroundingRow.className = 'logs_table_row_' + result[i].eventType; + var newRow = [ - //result[i].id, moment(result[i].eventTime).format("YYYY-MM-DD h:mm:ss a"), result[i].eventType, result[i].process, result[i].message ]; - newTable.appendChild(createTableRow(false, newRow, 'logs_table_row_' + result[i].eventType, 'romcell logs_table_cell')); + surroundingRow.appendChild(createTableRow(false, newRow, '', 'romcell logs_table_cell')); + // exception + var exceptionString = ''; if (result[i].exceptionValue) { - var exceptionString = "

Exception

" + syntaxHighlight(JSON.stringify(result[i].exceptionValue, null, 2)).replace(/\\n/g, "
") + "
"; + exceptionString = "Exception
" + syntaxHighlight(JSON.stringify(result[i].exceptionValue, null, 2)).replace(/\\n/g, "
") + "
"; var exRow = document.createElement('tr'); var leadCell = document.createElement('td'); exRow.appendChild(leadCell); @@ -158,8 +165,59 @@ exCell.colSpan = '3'; exCell.innerHTML = exceptionString; exRow.appendChild(exCell); - newTable.appendChild(exRow); + surroundingRow.appendChild(exRow); } + + // calling process + var infoRow = document.createElement('tr'); + + var infoRowEmptyCell = document.createElement('td'); + infoRowEmptyCell.className = 'romcell'; + + var infoRowDataCell = document.createElement('td'); + infoRowDataCell.className = 'romcell'; + infoRowDataCell.setAttribute('colspan', 3); + infoRowDataCell.innerHTML = 'Calling process: ' + result[i].callingProcess; + + infoRow.appendChild(infoRowEmptyCell); + infoRow.appendChild(infoRowDataCell); + surroundingRow.appendChild(infoRow); + + // initiated by user + if (result[i].callingUser) { + if (result[i].callingUser.length > 0) { + var infoRow3 = document.createElement('tr'); + + var infoRowEmptyCell3 = document.createElement('td'); + infoRowEmptyCell3.className = 'romcell'; + + var infoRowDataCell3 = document.createElement('td'); + infoRowDataCell3.className = 'romcell'; + infoRowDataCell3.setAttribute('colspan', 3); + infoRowDataCell3.innerHTML = 'User: ' + result[i].callingUser + ""; + + infoRow3.appendChild(infoRowEmptyCell3); + infoRow3.appendChild(infoRowDataCell3); + surroundingRow.appendChild(infoRow3); + } + } + + // correlation id + var infoRow2 = document.createElement('tr'); + + var infoRowEmptyCell2 = document.createElement('td'); + infoRowEmptyCell2.className = 'romcell'; + + var infoRowDataCell2 = document.createElement('td'); + infoRowDataCell2.className = 'romcell'; + infoRowDataCell2.setAttribute('colspan', 3); + infoRowDataCell2.innerHTML = 'Correlation Id: ' + result[i].correlationId + ""; + + infoRow2.appendChild(infoRowEmptyCell2); + infoRow2.appendChild(infoRowDataCell2); + surroundingRow.appendChild(infoRow2); + + newTable.appendChild(surroundingRow); } }, function (error) {