From 3a66ffd864257c05ebdb8727cb6e2ed22be3a0bc Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Tue, 11 Feb 2025 19:51:14 +0000 Subject: [PATCH] fixes to PR - use multicolumn primary key on UserMissionData - simplification of GetUserMissionData and SetOrUpdateUserMissionData also: - AuthenticateUser endpoint compatible with games that use e-mail as login - using option to disable loading non SoD data also for achievements --- .../Common/AuthenticationController.cs | 6 +- src/Controllers/Common/ContentController.cs | 2 +- src/Model/UserMissionData.cs | 4 +- src/Services/AchievementStoreSingleton.cs | 16 +++-- src/Services/MissionService.cs | 62 ++++++++----------- 5 files changed, 42 insertions(+), 48 deletions(-) diff --git a/src/Controllers/Common/AuthenticationController.cs b/src/Controllers/Common/AuthenticationController.cs index 78f1838..3fc5548 100644 --- a/src/Controllers/Common/AuthenticationController.cs +++ b/src/Controllers/Common/AuthenticationController.cs @@ -87,12 +87,14 @@ public class AuthenticationController : Controller { [Route("v3/AuthenticationWebService.asmx/AuthenticateUser")] [DecryptRequest("username")] [DecryptRequest("password")] - public bool AuthenticateUser() { + public bool AuthenticateUser([FromForm] string apiKey) { String username = Request.Form["username"]; String password = Request.Form["password"]; // Authenticate the user - User? user = ctx.Users.FirstOrDefault(e => e.Username == username); + User? user = (ClientVersion.GetVersion(apiKey) <= ClientVersion.Max_OldJS) + ? ctx.Users.FirstOrDefault(e => e.Email == username) + : ctx.Users.FirstOrDefault(e => e.Username == username); if (user is null || new PasswordHasher().VerifyHashedPassword(null, user.Password, password) != PasswordVerificationResult.Success) { return false; } diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index ea98d23..6b0a2d9 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -2135,7 +2135,7 @@ public class ContentController : Controller { [HttpPost] // [Produces("application/xml")] [Route("MissionWebService.asmx/GetMission")] // old ("step") missions - used by MB and WoJS lands - public IActionResult GetMission([FromForm] int gameId, [FromForm] int type) { + public IActionResult GetMission([FromForm] int gameId, [FromForm] string name) { if (gameId == 1) return Ok(XmlUtil.ReadResourceXmlString("missions.step_missions_wojs_al")); if (gameId == 5) return Ok(XmlUtil.ReadResourceXmlString("missions.step_missions_mb")); return Ok(); diff --git a/src/Model/UserMissionData.cs b/src/Model/UserMissionData.cs index db3d7fc..1a971b9 100644 --- a/src/Model/UserMissionData.cs +++ b/src/Model/UserMissionData.cs @@ -1,11 +1,11 @@ using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; namespace sodoff.Model { + [PrimaryKey(nameof(VikingId), nameof(WorldId), nameof(MissionId))] public class UserMissionData { - [Key] - public int Id { get; set; } public int VikingId { get; set; } public int WorldId { get; set; } public int MissionId { get; set; } diff --git a/src/Services/AchievementStoreSingleton.cs b/src/Services/AchievementStoreSingleton.cs index 240c817..cb19b78 100644 --- a/src/Services/AchievementStoreSingleton.cs +++ b/src/Services/AchievementStoreSingleton.cs @@ -1,10 +1,12 @@ using sodoff.Schema; using sodoff.Model; using sodoff.Util; +using sodoff.Configuration; using System.Reflection; using System.Xml; using System.Xml.Linq; using System.Collections.ObjectModel; +using Microsoft.Extensions.Options; namespace sodoff.Services { public class AchievementStoreSingleton { @@ -34,7 +36,7 @@ namespace sodoff.Services { int dragonAdultMinXP; int dragonTitanMinXP; - public AchievementStoreSingleton() { + public AchievementStoreSingleton(IOptions config) { ArrayOfUserRank allranks = XmlUtil.DeserializeXml(XmlUtil.ReadResourceXmlString("ranks.allranks_sod")); foreach (var pointType in Enum.GetValues()) { ranks[pointType] = allranks.UserRank.Where(r => r.PointTypeID == pointType).ToArray(); @@ -46,11 +48,13 @@ namespace sodoff.Services { } achievementsTasks[ClientVersion.Min_SoD] = new AchievementTasks("achievements.achievementtaskinfo_sod"); - achievementsTasks[ClientVersion.MaM] = new AchievementTasks("achievements.achievementtaskinfo_mam"); - achievementsTasks[ClientVersion.MB] = new AchievementTasks("achievements.achievementtaskinfo_mb"); - achievementsTasks[ClientVersion.EMD] = new AchievementTasks("achievements.achievementtaskinfo_emd"); - achievementsTasks[ClientVersion.SS] = new AchievementTasks("achievements.achievementtaskinfo_ss"); - achievementsTasks[ClientVersion.WoJS] = new AchievementTasks("achievements.achievementtaskinfo_wojs"); + if (config.Value.LoadNonSoDData) { + achievementsTasks[ClientVersion.MaM] = new AchievementTasks("achievements.achievementtaskinfo_mam"); + achievementsTasks[ClientVersion.MB] = new AchievementTasks("achievements.achievementtaskinfo_mb"); + achievementsTasks[ClientVersion.EMD] = new AchievementTasks("achievements.achievementtaskinfo_emd"); + achievementsTasks[ClientVersion.SS] = new AchievementTasks("achievements.achievementtaskinfo_ss"); + achievementsTasks[ClientVersion.WoJS] = new AchievementTasks("achievements.achievementtaskinfo_wojs"); + } dragonAdultMinXP = ranks[AchievementPointTypes.DragonXP][10].Value; dragonTitanMinXP = ranks[AchievementPointTypes.DragonXP][20].Value; diff --git a/src/Services/MissionService.cs b/src/Services/MissionService.cs index f32f27c..b2671e0 100644 --- a/src/Services/MissionService.cs +++ b/src/Services/MissionService.cs @@ -54,24 +54,25 @@ public class MissionService { return mission; } - public Schema.UserMissionData GetUserMissionData(Viking viking, int worldId) - { - Schema.UserMissionData umdRes = new Schema.UserMissionData(); + public Schema.UserMissionData GetUserMissionData(Viking viking, int worldId) { + Schema.UserMissionData umdRes = new(); // instantiate schema lists and int lists - List userMissionsCompletedIds = new List(); - List missions = new List(); - List steps = new List(); - List tasks = new List(); + List userMissionsCompletedIds = new(); + List missions = new(); // get all initiated missions List vikingUmds = viking.UserMissions.Where(e => e.WorldId == worldId).ToList(); - foreach (Model.UserMissionData mission in vikingUmds) - { - tasks.Add(mission.TaskId); - steps.Add(new UserMissionDataMissionStep { StepId = mission.StepId, TaskId = tasks.ToArray() }); - missions.Add(new UserMissionDataMission { MissionId = mission.MissionId, Step = steps.ToArray() }); + foreach (Model.UserMissionData mission in vikingUmds) { + missions.Add(new UserMissionDataMission { + MissionId = mission.MissionId, + Step = new UserMissionDataMissionStep[] { new UserMissionDataMissionStep { + // NOTE: we store in database only last StepId and TaskId – this is different behavior than og + StepId = mission.StepId, + TaskId = new int[] {mission.TaskId} + }} + }); } // add completed mission id's to usermissionscompletedids @@ -104,37 +105,24 @@ public class MissionService { return new UserBadge { BadgeId = completedBadgeIds.ToArray() }; } - public Model.UserMissionData SetOrUpdateUserMissionData(Viking viking, int worldId, int missionId, int stepId, int taskId) - { + public void SetOrUpdateUserMissionData(Viking viking, int worldId, int missionId, int stepId, int taskId) { // find any existing records of this mission - Model.UserMissionData? existingMission = viking.UserMissions.Where(e => e.WorldId == worldId) + Model.UserMissionData? missionData = viking.UserMissions.Where(e => e.WorldId == worldId) .Where(e => e.MissionId == missionId) .FirstOrDefault(); - if (existingMission != null) - { - // update taskid and stepid - existingMission.StepId = stepId; - existingMission.TaskId = taskId; - ctx.SaveChanges(); - - return existingMission; + if (missionData != null) { + missionData.StepId = stepId; + missionData.TaskId = taskId; + } else { + viking.UserMissions.Add(new Model.UserMissionData() { + WorldId = worldId, + MissionId = missionId, + StepId = stepId, + TaskId = taskId + }); } - - // add mission data to db - - Model.UserMissionData missionData = new Model.UserMissionData() - { - WorldId = worldId, - MissionId = missionId, - StepId = stepId, - TaskId = taskId - }; - - viking.UserMissions.Add(missionData); ctx.SaveChanges(); - - return missionData; } public bool SetUserMissionCompleted(Viking viking, int worldId, int missionId, bool isCompleted)