diff --git a/gaseous-server/Classes/Favourites.cs b/gaseous-server/Classes/Favourites.cs new file mode 100644 index 0000000..9d09be0 --- /dev/null +++ b/gaseous-server/Classes/Favourites.cs @@ -0,0 +1,58 @@ +using IGDB.Models; + +namespace gaseous_server.Classes +{ + public class Favourites + { + public bool GetFavourite(string userid, long GameId) + { + Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); + string sql = "SELECT * FROM Favourites WHERE UserId=@userid AND GameId=@gameid"; + Dictionary dbDict = new Dictionary{ + { "userid", userid }, + { "gameid", GameId} + }; + + if (db.ExecuteCMD(sql, dbDict).Rows.Count > 0) + { + return true; + } + else + { + return false; + } + } + + public bool SetFavourite(string userid, long GameId, bool Favourite) + { + bool CurrentFavourite = GetFavourite(userid, GameId); + if (CurrentFavourite == Favourite) + { + return Favourite; + } + else + { + Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); + string sql; + Dictionary dbDict = new Dictionary{ + { "userid", userid }, + { "gameid", GameId} + }; + + if (CurrentFavourite == true) + { + // delete existing value + sql = "DELETE FROM Favourites WHERE UserId=@userid AND GameId=@gameid"; + } + else + { + // insert new value + sql = "INSERT INTO Favourites (UserId, GameId) VALUES (@userid, @gameid)"; + } + db.ExecuteNonQuery(sql, dbDict); + + return Favourite; + } + } + } +} \ No newline at end of file diff --git a/gaseous-server/Classes/Metadata/Games.cs b/gaseous-server/Classes/Metadata/Games.cs index 3212e93..8476b6a 100644 --- a/gaseous-server/Classes/Metadata/Games.cs +++ b/gaseous-server/Classes/Metadata/Games.cs @@ -566,6 +566,7 @@ namespace gaseous_server.Classes.Metadata public double? TotalRating { get; set; } public int? TotalRatingCount { get; set; } public bool HasSavedGame { get; set; } = false; + public bool IsFavourite { get; set; } = false; public DateTimeOffset? FirstReleaseDate { get; set; } public IGDB.IdentityOrValue Cover { get; set; } public IGDB.IdentitiesOrValues Artworks { get; set; } diff --git a/gaseous-server/Controllers/V1.0/GamesController.cs b/gaseous-server/Controllers/V1.0/GamesController.cs index b1067b3..1997e8b 100644 --- a/gaseous-server/Controllers/V1.0/GamesController.cs +++ b/gaseous-server/Controllers/V1.0/GamesController.cs @@ -611,6 +611,81 @@ namespace gaseous_server.Controllers } } + + [MapToApiVersion("1.0")] + [MapToApiVersion("1.1")] + [HttpGet] + [Route("{GameId}/favourite")] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GameGetFavouriteAsync(long GameId) + { + try + { + IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false); + + if (gameObject != null) + { + var user = await _userManager.GetUserAsync(User); + + if (user != null) + { + Favourites favourites = new Favourites(); + return Ok(favourites.GetFavourite(user.Id, GameId)); + } + else + { + return NotFound(); + } + } + else + { + return NotFound(); + } + } + catch + { + return NotFound(); + } + } + + [MapToApiVersion("1.0")] + [MapToApiVersion("1.1")] + [HttpPost] + [Route("{GameId}/favourite")] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GameSetFavouriteAsync(long GameId, bool favourite) + { + try + { + IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false); + + if (gameObject != null) + { + var user = await _userManager.GetUserAsync(User); + + if (user != null) + { + Favourites favourites = new Favourites(); + return Ok(favourites.SetFavourite(user.Id, GameId, favourite)); + } + else + { + return NotFound(); + } + } + else + { + return NotFound(); + } + } + catch + { + return NotFound(); + } + } + [MapToApiVersion("1.0")] [MapToApiVersion("1.1")] [HttpGet] diff --git a/gaseous-server/Controllers/V1.1/GamesController.cs b/gaseous-server/Controllers/V1.1/GamesController.cs index ea73046..8bcc3f5 100644 --- a/gaseous-server/Controllers/V1.1/GamesController.cs +++ b/gaseous-server/Controllers/V1.1/GamesController.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Scripting; using static gaseous_server.Classes.Metadata.AgeRatings; using Asp.Versioning; +using Humanizer; namespace gaseous_server.Controllers.v1_1 { @@ -148,6 +149,7 @@ namespace gaseous_server.Controllers.v1_1 public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem(); public GameSortingItem Sorting { get; set; } = new GameSortingItem(); public bool HasSavedGame { get; set; } + public bool IsFavourite { get; set; } public class GameRatingItem @@ -213,6 +215,12 @@ namespace gaseous_server.Controllers.v1_1 whereClauses.Add(hasSavesTemp); } + if (model.IsFavourite == true) + { + string isFavTemp = "Favourite = 1"; + havingClauses.Add(isFavTemp); + } + if (model.MinimumReleaseYear != -1) { string releaseTempMinVal = "FirstReleaseDate >= @minreleasedate"; @@ -488,7 +496,11 @@ SELECT DISTINCT Game.AgeGroupId, Game.RomCount, RomSavedStates.RomSaveCount, - RomGroupSavedStates.MediaGroupSaveCount + RomGroupSavedStates.MediaGroupSaveCount, + CASE + WHEN Favourites.UserId IS NULL THEN 0 + ELSE 1 + END AS Favourite FROM (SELECT DISTINCT Game.*, @@ -533,7 +545,9 @@ FROM 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; + Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId + LEFT JOIN + Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause; List RetVal = new List(); DataTable dbResponse = db.ExecuteCMD(sql, whereParams); @@ -563,6 +577,14 @@ FROM { retMinGame.HasSavedGame = false; } + if ((int)dbResponse.Rows[i]["Favourite"] == 0) + { + retMinGame.IsFavourite = false; + } + else + { + retMinGame.IsFavourite = true; + } RetVal.Add(retMinGame); } diff --git a/gaseous-server/Support/Database/MySQL/gaseous-1021.sql b/gaseous-server/Support/Database/MySQL/gaseous-1021.sql new file mode 100644 index 0000000..ba12ec2 --- /dev/null +++ b/gaseous-server/Support/Database/MySQL/gaseous-1021.sql @@ -0,0 +1,8 @@ +CREATE TABLE `Favourites` ( + `UserId` varchar(45) NOT NULL, + `GameId` bigint(20) NOT NULL, + PRIMARY KEY (`UserId`,`GameId`), + KEY `idx_GameId` (`GameId`), + KEY `idx_UserId` (`UserId`), + CONSTRAINT `ApplicationUser_Favourite` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION +); diff --git a/gaseous-server/gaseous-server.csproj b/gaseous-server/gaseous-server.csproj index 2bb2bb1..97cc403 100644 --- a/gaseous-server/gaseous-server.csproj +++ b/gaseous-server/gaseous-server.csproj @@ -63,6 +63,7 @@ + @@ -106,5 +107,6 @@ + \ No newline at end of file diff --git a/gaseous-server/wwwroot/images/favourite-empty.svg b/gaseous-server/wwwroot/images/favourite-empty.svg new file mode 100644 index 0000000..e67d4a2 --- /dev/null +++ b/gaseous-server/wwwroot/images/favourite-empty.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/gaseous-server/wwwroot/images/favourite-filled.svg b/gaseous-server/wwwroot/images/favourite-filled.svg new file mode 100644 index 0000000..f4c2825 --- /dev/null +++ b/gaseous-server/wwwroot/images/favourite-filled.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/gaseous-server/wwwroot/pages/game.html b/gaseous-server/wwwroot/pages/game.html index 867f33c..3256988 100644 --- a/gaseous-server/wwwroot/pages/game.html +++ b/gaseous-server/wwwroot/pages/game.html @@ -72,6 +72,12 @@ Total Play Time - + +
+
+ +
+
@@ -128,8 +134,6 @@ var selectedScreenshot = 0; ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) { - console.log(result); - // populate games page gameData = result; @@ -290,6 +294,27 @@ } }); + // load favourites + ajaxCall('/api/v1.1/games/' + gameId + '/favourite', 'GET', function (result) { + var gameFavButton = document.getElementById('gamestatistics_favourite_button'); + var gameFavIcon = document.createElement('img'); + gameFavIcon.id = "gamestatistics_favourite"; + gameFavIcon.className = "favouriteicon"; + gameFavIcon.title = "Favourite"; + gameFavIcon.alt = "Favourite"; + + if (result == true) { + gameFavIcon.setAttribute("src", '/images/favourite-filled.svg'); + gameFavIcon.setAttribute('onclick', "SetGameFavourite(false);"); + } else { + gameFavIcon.setAttribute("src", '/images/favourite-empty.svg'); + gameFavIcon.setAttribute('onclick', "SetGameFavourite(true);"); + } + + gameFavButton.innerHTML = ''; + gameFavButton.appendChild(gameFavIcon); + }); + // load release date var gameSummaryRelease = document.getElementById('gamesummary_firstrelease'); if (result.firstReleaseDate) { @@ -503,7 +528,6 @@ if (result.length == 0) { mediaGroup.style.display = 'none'; } else { - console.log(result); mediaGroup.style.display = ''; mediaGroupDiv.innerHTML = ''; var mgTable = document.createElement('table'); @@ -999,12 +1023,9 @@ $('#rom_edit_fixplatform').on('select2:select', function (e) { var platformData = e.params.data; - console.log(platformData); var gameValue = $('#rom_edit_fixgame').select2('data'); if (gameValue) { - console.log(gameValue[0]); - setRomFixGameDropDown(); } }); @@ -1170,4 +1191,30 @@ JSON.stringify(romIds) ); } + + function SetGameFavourite(status) { + ajaxCall( + '/api/v1.1/games/' + gameId + '/favourite?favourite=' + status, + 'POST', + function (result) { + var gameFavButton = document.getElementById('gamestatistics_favourite_button'); + var gameFavIcon = document.createElement('img'); + gameFavIcon.id = "gamestatistics_favourite"; + gameFavIcon.className = "favouriteicon"; + gameFavIcon.title = "Favourite"; + gameFavIcon.alt = "Favourite"; + + if (result == true) { + gameFavIcon.setAttribute("src", '/images/favourite-filled.svg'); + gameFavIcon.setAttribute('onclick', "SetGameFavourite(false);"); + } else { + gameFavIcon.setAttribute("src", '/images/favourite-empty.svg'); + gameFavIcon.setAttribute('onclick', "SetGameFavourite(true);"); + } + + gameFavButton.innerHTML = ''; + gameFavButton.appendChild(gameFavIcon); + } + ); + } \ No newline at end of file diff --git a/gaseous-server/wwwroot/scripts/filterformating.js b/gaseous-server/wwwroot/scripts/filterformating.js index 58267bc..f0cc3ca 100644 --- a/gaseous-server/wwwroot/scripts/filterformating.js +++ b/gaseous-server/wwwroot/scripts/filterformating.js @@ -55,6 +55,11 @@ function formatFilterPanel(containerElement, result) { "id": "savestatesavailable", "name": "Game has save states avaialble", "gameCount": 0 + }, + { + "id": "favourite", + "name": "Favourite", + "gameCount": 0 } ], true, true); @@ -531,6 +536,7 @@ function executeFilter1_1(pageNumber, pageSize) { model = { "Name": document.getElementById('filter_panel_search').value, "HasSavedGame": document.getElementById('filter_panel_item_settings_checkbox_savestatesavailable').checked, + "isFavourite": document.getElementById('filter_panel_item_settings_checkbox_favourite').checked, "Platform": GetFilterQuery1_1('platform'), "Genre": GetFilterQuery1_1('genre'), "GameMode": GetFilterQuery1_1('gamemode'), @@ -554,6 +560,7 @@ function executeFilter1_1(pageNumber, pageSize) { "SortAscending": orderByDirection } }; + console.log(model); existingSearchModel = model; } else { diff --git a/gaseous-server/wwwroot/scripts/gamesformating.js b/gaseous-server/wwwroot/scripts/gamesformating.js index 994ba50..f76ffba 100644 --- a/gaseous-server/wwwroot/scripts/gamesformating.js +++ b/gaseous-server/wwwroot/scripts/gamesformating.js @@ -330,6 +330,14 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification, gameImageBox.appendChild(gameSaveIcon); } + // add favourite game icon + if (gameObject.isFavourite == true) { + var gameFavIcon = document.createElement('img'); + gameFavIcon.src = '/images/favourite-filled.svg'; + gameFavIcon.className = classes['game_tile_box_favouritegame favouriteicon']; + gameImageBox.appendChild(gameFavIcon); + } + if (gameObject.totalRating || displayClassification == true) { var gameImageRatingBanner = document.createElement('div'); gameImageRatingBanner.className = classes['game_tile_box_ratingbanner']; @@ -380,6 +388,7 @@ function getViewModeClasses(listView) { "game_tile_image lazy": "game_tile_image lazy", "game_tile_image unknown": "game_tile_image unknown", "game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame savedstateicon", + "game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame favouriteicon", "game_tile_box_ratingbanner": "game_tile_box_ratingbanner", "rating_image_overlay": "rating_image_overlay", "game_tile_label": "game_tile_label" @@ -393,6 +402,7 @@ function getViewModeClasses(listView) { "game_tile_image lazy": "game_tile_image_row lazy", "game_tile_image unknown": "game_tile_image_row unknown", "game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame_row savedstateicon", + "game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame_row favouriteicon", "game_tile_box_ratingbanner": "game_tile_box_ratingbanner_row", "rating_image_overlay": "rating_image_overlay_row", "game_tile_label": "game_tile_label_row" diff --git a/gaseous-server/wwwroot/styles/style.css b/gaseous-server/wwwroot/styles/style.css index 778bedf..233540a 100644 --- a/gaseous-server/wwwroot/styles/style.css +++ b/gaseous-server/wwwroot/styles/style.css @@ -671,6 +671,18 @@ input[name='filter_panel_range_max'] { right: 10px; } +.game_tile_box_favouritegame { + position: absolute; + top: 1px; + left: 5px; +} + +.game_tile_box_favouritegame_row { + position: absolute; + top: 30%; + right: 10px; +} + .game_tile_image { max-width: 200px; min-width: 150px; @@ -930,6 +942,31 @@ iframe { padding: 3px; } +#gamestatistics_favourite { + float: right; +} + +#gamestatistics_favourite_button { + margin: 5px; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 2px; + padding-right: 7px; + width: 30px; + height: 30px; + text-align: center; + background-color: rgba(56, 56, 56, 0.3); + border-radius: 5px; + border-style: solid; + border-color: transparent; + border-width: 0px; + cursor: pointer; +} + +#gamestatistics_favourite_button:hover { + background-color: rgba(56, 56, 56, 0.9); +} + #gamesummarytext_label { } @@ -969,6 +1006,14 @@ table .romrow:nth-child(odd) { cursor: pointer; } +.favouriteicon { + height: 24px; + width: 24px; + margin-top: 4px; + cursor: pointer; + filter: invert(11%) sepia(100%) saturate(6854%) hue-rotate(359deg) brightness(103%) contrast(122%) drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); +} + th { text-align: left; padding: 5px;