From e3314ae1f1b772d1e781de756a10f76893398893 Mon Sep 17 00:00:00 2001 From: rpaciorek Date: Thu, 31 Aug 2023 19:01:55 +0000 Subject: [PATCH] Viking session via ActionFilter (#29) --- src/Attributes/VikingSession.cs | 52 +++-- .../Common/AchievementController.cs | 34 +-- src/Controllers/Common/ContentController.cs | 202 ++++++------------ src/Controllers/Common/ItemStoreController.cs | 17 +- .../Common/MembershipController.cs | 12 +- src/Controllers/Common/ProfileController.cs | 23 +- src/Controllers/Common/RatingController.cs | 3 +- 7 files changed, 140 insertions(+), 203 deletions(-) diff --git a/src/Attributes/VikingSession.cs b/src/Attributes/VikingSession.cs index 5edcc05..a74534d 100644 --- a/src/Attributes/VikingSession.cs +++ b/src/Attributes/VikingSession.cs @@ -1,37 +1,63 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; - using sodoff.Model; -using sodoff.Controllers.Common; namespace sodoff.Attributes; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class VikingSession : Attribute, IAsyncActionFilter { + public enum Modes { VIKING, USER, VIKING_OR_USER }; + + public string ApiToken { get; set; } = "apiToken"; + public Modes Mode { get; set; } = Modes.VIKING; + public bool UseLock = false; + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { - DBContext ctx = ((AchievementController)context.Controller).ctx; + DBContext ctx = context.HttpContext.RequestServices.GetService(typeof(DBContext)) as DBContext; - if (!context.HttpContext.Request.Form.ContainsKey("apiToken")) { + // get session from apiToken + + if (!context.HttpContext.Request.Form.ContainsKey(ApiToken)) { context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 }; return; } - Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == context.HttpContext.Request.Form["apiToken"].ToString()); - if (session?.VikingId is null) { + Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == context.HttpContext.Request.Form[ApiToken].ToString()); + + // get viking / user id from session + + string? userVikingId = null; + if (Mode == Modes.VIKING || (Mode == Modes.VIKING_OR_USER && session?.UserId is null) ) { + userVikingId = session?.VikingId; + } else { + userVikingId = session?.UserId; + } + + if (userVikingId is null) { context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 }; return; } - // NOTE: we can't refer to session.Viking here, because it may cause to ignore modifications from the threads we are waiting for - // we can use session.Viking only after vikingMutex.WaitOne() + // call next (with lock if requested) - Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + session.VikingId); - try { - vikingMutex.WaitOne(); + if (UseLock) { + // NOTE: we can't refer to session.User / session.Viking here, + // because it may cause to ignore modifications from the threads we are waiting for + // we can use its only after vikingMutex.WaitOne() + + Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + userVikingId); + try { + vikingMutex.WaitOne(); + context.ActionArguments["user"] = session.User; + context.ActionArguments["viking"] = session.Viking; + await next(); + } finally { + vikingMutex.ReleaseMutex(); + } + } else { + context.ActionArguments["user"] = session.User; context.ActionArguments["viking"] = session.Viking; await next(); - } finally { - vikingMutex.ReleaseMutex(); } } } diff --git a/src/Controllers/Common/AchievementController.cs b/src/Controllers/Common/AchievementController.cs index ce32aa7..d846a20 100644 --- a/src/Controllers/Common/AchievementController.cs +++ b/src/Controllers/Common/AchievementController.cs @@ -20,14 +20,8 @@ public class AchievementController : Controller { [HttpPost] [Produces("application/xml")] [Route("AchievementWebService.asmx/GetPetAchievementsByUserID")] - public IActionResult GetPetAchievementsByUserID([FromForm] string apiToken, [FromForm] string userId) { - // TODO: check session - - Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Id == userId); - if (viking is null) { - return null; - } - + [VikingSession(UseLock=false)] + public IActionResult GetPetAchievementsByUserID(Viking viking, [FromForm] string userId) { List dragonsAchievement = new List(); foreach (Dragon dragon in viking.Dragons) { dragonsAchievement.Add( @@ -68,12 +62,8 @@ public class AchievementController : Controller { [HttpPost] [Route("AchievementWebService.asmx/SetDragonXP")] // used by dragonrescue-import - public IActionResult SetDragonXP([FromForm] string apiToken, [FromForm] string dragonId, [FromForm] int value) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return Unauthorized(); - } - + [VikingSession] + public IActionResult SetDragonXP(Viking viking, [FromForm] string dragonId, [FromForm] int value) { Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.EntityId == dragonId); if (dragon is null) { return Conflict("Dragon not found"); @@ -87,12 +77,8 @@ public class AchievementController : Controller { [HttpPost] [Route("AchievementWebService.asmx/SetPlayerXP")] // used by dragonrescue-import - public IActionResult SetDragonXP([FromForm] string apiToken, [FromForm] int type, [FromForm] int value) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return Unauthorized(); - } - + [VikingSession] + public IActionResult SetDragonXP(Viking viking, [FromForm] int type, [FromForm] int value) { if (!Enum.IsDefined(typeof(AchievementPointTypes), type)) { return Conflict("Invalid XP type"); } @@ -138,7 +124,7 @@ public class AchievementController : Controller { [Produces("application/xml")] [Route("AchievementWebService.asmx/SetAchievementAndGetReward")] [Route("AchievementWebService.asmx/SetUserAchievementAndGetReward")] - [VikingSession()] + [VikingSession(UseLock=true)] public IActionResult SetAchievementAndGetReward(Viking viking, [FromForm] int achievementID) { var rewards = achievementService.ApplyAchievementRewardsByID(viking, achievementID); @@ -151,7 +137,7 @@ public class AchievementController : Controller { [Produces("application/xml")] [Route("V2/AchievementWebService.asmx/SetUserAchievementTask")] [DecryptRequest("achievementTaskSetRequest")] - [VikingSession()] + [VikingSession(UseLock=true)] public IActionResult SetUserAchievementTask(Viking viking) { AchievementTaskSetRequest request = XmlUtil.DeserializeXml(Request.Form["achievementTaskSetRequest"]); @@ -178,9 +164,9 @@ public class AchievementController : Controller { [HttpPost] [Produces("application/xml")] [Route("AchievementWebService.asmx/SetAchievementByEntityIDs")] - public IActionResult SetAchievementByEntityIDs([FromForm] string apiToken, [FromForm] int achievementID) { + [VikingSession] + public IActionResult SetAchievementByEntityIDs(Viking viking, [FromForm] int achievementID) { // TODO: This is a placeholder - Viking? viking = ctx.Sessions.FirstOrDefault(x => x.ApiToken == apiToken).Viking; return Ok(new AchievementReward[1] { new AchievementReward { Amount = 25, diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index ed2b550..2eb4609 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -31,7 +31,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetDefaultNameSuggestion")] - public IActionResult GetDefaultNameSuggestion([FromForm] string apiToken) { + [VikingSession(Mode=VikingSession.Modes.VIKING_OR_USER, UseLock=false)] + public IActionResult GetDefaultNameSuggestion(User? user, Viking? viking) { string[] adjs = { //Adjectives used to generate suggested names "Adventurous", "Active", "Alert", "Attentive", "Beautiful", "Berkian", "Berserker", "Bold", "Brave", @@ -60,13 +61,8 @@ public class ContentController : Controller { "Zealous", "Zealot" }; - Session? session = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken); - if (session is null) - return Unauthorized(); - - User? user = session.User; if (user is null) - user = session.Viking?.User; + user = viking.User; string uname = user.Username; Random choice = new Random(); //Randomizer for selecting random adjectives @@ -87,13 +83,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/ValidateName")] - public IActionResult ValidateName([FromForm] string apiToken,[FromForm] string nameValidationRequest) { - User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.User; - if (user is null) { - // TODO: better error handling than just replying not unique - return Ok(new NameValidationResponse { Result = NameValidationResult.NotUnique }); - } - + public IActionResult ValidateName([FromForm] string nameValidationRequest) { // Check if name populated NameValidationRequest request = XmlUtil.DeserializeXml(nameValidationRequest); @@ -173,15 +163,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetCommonInventory")] - public IActionResult GetCommonInventory([FromForm] string apiToken) { - // TODO: what is the difference between this and v2? this can be called with user apiToken and v2 not? maybe it should be unified? - User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.User; - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (user is null && viking is null) { - return Ok(); - } - - List userItemData; + [VikingSession(Mode=VikingSession.Modes.VIKING_OR_USER, UseLock=false)] + public IActionResult GetCommonInventory(User? user, Viking? viking) { if (viking != null) { return Ok( inventoryService.GetCommonInventoryData(viking) ); } else { @@ -205,22 +188,17 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetCommonInventory")] - public IActionResult GetCommonInventoryV2([FromForm] string apiToken) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null || viking.Inventory is null) return Ok(); - + [VikingSession(UseLock=false)] + public IActionResult GetCommonInventoryV2(Viking viking) { return Ok(inventoryService.GetCommonInventoryData(viking)); } [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetCommonInventory")] - public IActionResult SetCommonInventory([FromForm] string apiToken, [FromForm] string commonInventoryRequestXml) { + [VikingSession] + public IActionResult SetCommonInventory(Viking viking, [FromForm] string commonInventoryRequestXml) { CommonInventoryRequest[] request = XmlUtil.DeserializeXml(commonInventoryRequestXml); - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null || viking.Inventory is null) return Ok(); - - // Set inventory items List responseItems = new(); // SetCommonInventory can remove any number of items from the inventory, this checks if it's possible @@ -268,8 +246,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/UseInventory")] - public IActionResult UseInventory([FromForm] string apiToken, [FromForm] int userInventoryId, [FromForm] int numberOfUses) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + [VikingSession] + public IActionResult UseInventory(Viking viking, [FromForm] int userInventoryId, [FromForm] int numberOfUses) { InventoryItem? item = viking.Inventory.InventoryItems.FirstOrDefault(e => e.Id == userInventoryId); if (item is null) return Ok(false); @@ -289,27 +267,11 @@ public class ContentController : Controller { return Ok(new DateTime(DateTime.Now.Ticks)); } - [HttpPost] - [Produces("application/xml")] - [Route("ItemStoreWebService.asmx/GetItem")] // NOTE: Should be in a separate controler, but it's inventory related, so I'll leave it here for now - public IActionResult GetItem([FromForm] int itemId) { - if (itemId == 0) // For a null item, return an empty item - return Ok(new ItemData()); - return Ok(itemService.GetItem(itemId)); - } - [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/SetAvatar")] - public IActionResult SetAvatar([FromForm] string apiToken, [FromForm] string contentXML) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return Ok(new SetAvatarResult { - Success = false, - StatusCode = AvatarValidationResult.Error - }); - } - + [VikingSession] + public IActionResult SetAvatar(Viking viking, [FromForm] string contentXML) { AvatarData avatarData = XmlUtil.DeserializeXml(contentXML); foreach (AvatarDataPart part in avatarData.Part) { if (part.PartType == "Version") { @@ -331,22 +293,17 @@ public class ContentController : Controller { ctx.SaveChanges(); return Ok(new SetAvatarResult { - Success = true, - DisplayName = viking.Name, - StatusCode = AvatarValidationResult.Valid - }); + Success = true, + DisplayName = viking.Name, + StatusCode = AvatarValidationResult.Valid + }); } [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/CreatePet")] - public IActionResult CreatePet([FromForm] string apiToken, [FromForm] string request) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - // TODO: result for invalid session - return Ok(); - } - + [VikingSession] + public IActionResult CreatePet(Viking viking, [FromForm] string request) { RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); // TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything @@ -406,14 +363,9 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("v3/ContentWebService.asmx/SetRaisedPet")] - public IActionResult SetRaisedPet([FromForm] string apiToken, [FromForm] string request, [FromForm] bool? import) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - // TODO: result for invalid session - return Ok(); - } - - RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); + [VikingSession] + public IActionResult SetRaisedPet(Viking viking, [FromForm] string request, [FromForm] bool? import) { + RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); // Find the dragon Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetRequest.RaisedPetData.RaisedPetID); @@ -437,13 +389,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetSelectedPet")] - public IActionResult SetSelectedPet([FromForm] string apiToken, [FromForm] int raisedPetID) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - // TODO: result for invalid session - return Ok(); - } - + [VikingSession] + public IActionResult SetSelectedPet(Viking viking, [FromForm] int raisedPetID) { // Find the dragon Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetID); if (dragon is null) { @@ -463,13 +410,9 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")] - public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return null; - } - - RaisedPetData[] dragons = viking.Dragons // TODO (multiplayer) we should use userId + [VikingSession(UseLock=false)] + public RaisedPetData[]? GetAllActivePetsByuserId(Viking viking, [FromForm] string userId, [FromForm] bool active) { + RaisedPetData[] dragons = viking.Dragons // TODO (multiplayer) we should use userId ? .Where(d => d.RaisedPetData is not null) .Select(GetRaisedPetDataFromDragon) .ToArray(); @@ -483,12 +426,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetUnselectedPetByTypes")] - public RaisedPetData[]? GetUnselectedPetByTypes([FromForm] string apiToken, [FromForm] string petTypeIDs, [FromForm] bool active) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return null; - } - + [VikingSession(UseLock=false)] + public RaisedPetData[]? GetUnselectedPetByTypes(Viking viking, [FromForm] string petTypeIDs, [FromForm] bool active) { RaisedPetData[] dragons = viking.Dragons .Where(d => d.RaisedPetData is not null) .Select(GetRaisedPetDataFromDragon) @@ -516,12 +455,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetSelectedRaisedPet")] - public RaisedPetData[]? GetSelectedRaisedPet([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool isActive) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) { - return null; - } - + [VikingSession(UseLock=false)] + public RaisedPetData[]? GetSelectedRaisedPet(Viking viking, [FromForm] string userId, [FromForm] bool isActive) { Dragon? dragon = viking.SelectedDragon; if (dragon is null) { return null; @@ -535,12 +470,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetImage")] - public bool SetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null || viking.Dragons is null) { - return false; - } - + [VikingSession] + public bool SetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) { // TODO: the other properties of contentXML ImageData data = XmlUtil.DeserializeXml(contentXML); @@ -572,12 +503,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetImage")] - public ImageData? GetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null || viking.Images is null) { - return null; - } - + [VikingSession(UseLock=false)] + public ImageData? GetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot) { return GetImageData(viking, ImageType, ImageSlot); } @@ -650,10 +577,10 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/AcceptMission")] - public IActionResult AcceptMission([FromForm] string userId, [FromForm] int missionId) { - Viking? viking = ctx.Vikings.FirstOrDefault(x => x.Id == userId); - if (viking is null) - return Ok(false); + [VikingSession] + public IActionResult AcceptMission(Viking viking, [FromForm] string userId, [FromForm] int missionId) { + if (viking.Id != userId) + return Unauthorized("Can't accept not owned mission"); MissionState? missionState = viking.MissionStates.FirstOrDefault(x => x.MissionId == missionId); if (missionState is null || missionState.MissionStatus != MissionStatus.Upcoming) @@ -668,6 +595,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetUserMissionState")] + //[VikingSession(UseLock=false)] public IActionResult GetUserMissionState([FromForm] string userId, [FromForm] string filter) { MissionRequestFilterV2 filterV2 = XmlUtil.DeserializeXml(filter); Viking? viking = ctx.Vikings.FirstOrDefault(x => x.Id == userId); @@ -686,10 +614,10 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/SetTaskState")] - public IActionResult SetTaskState([FromForm] string apiToken, [FromForm] string userId, [FromForm] int missionId, [FromForm] int taskId, [FromForm] bool completed, [FromForm] string xmlPayload) { - Session? session = ctx.Sessions.FirstOrDefault(s => s.ApiToken == apiToken); - if (session is null || session.VikingId != userId) - return Ok(new SetTaskStateResult { Success = false, Status = SetTaskStateStatus.Unknown }); + [VikingSession] + public IActionResult SetTaskState(Viking viking, [FromForm] string userId, [FromForm] int missionId, [FromForm] int taskId, [FromForm] bool completed, [FromForm] string xmlPayload) { + if (viking.Id != userId) + return Unauthorized("Can't set not owned task"); List results = missionService.UpdateTaskProgress(missionId, taskId, userId, completed, xmlPayload); @@ -715,11 +643,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/PurchaseItems")] - public IActionResult PurchaseItems([FromForm] string apiToken, [FromForm] string purchaseItemRequest) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) - return Ok(); - + [VikingSession] + public IActionResult PurchaseItems(Viking viking, [FromForm] string purchaseItemRequest) { PurchaseStoreItemRequest request = XmlUtil.DeserializeXml(purchaseItemRequest); CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[request.Items.Length]; for (int i = 0; i < request.Items.Length; i++) { @@ -744,11 +669,8 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/PurchaseItems")] - public IActionResult PurchaseItemsV1([FromForm] string apiToken, [FromForm] string itemIDArrayXml) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - if (viking is null) - return Ok(); - + [VikingSession] + public IActionResult PurchaseItemsV1(Viking viking, [FromForm] string itemIDArrayXml) { int[] itemIdArr = XmlUtil.DeserializeXml(itemIDArrayXml); CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[itemIdArr.Length]; for (int i = 0; i < itemIdArr.Length; i++) { @@ -773,10 +695,11 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetUserRoomItemPositions")] - public IActionResult GetUserRoomItemPositions([FromForm] string apiToken, [FromForm] string roomID) { + [VikingSession(UseLock=false)] + public IActionResult GetUserRoomItemPositions(Viking viking, [FromForm] string roomID) { if (roomID is null) roomID = ""; - Room? room = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.FirstOrDefault(x => x.RoomId == roomID); + Room? room = viking.Rooms.FirstOrDefault(x => x.RoomId == roomID); // TODO: this can break visiting farm of another viking's if (room is null) return Ok(new UserItemPositionList { UserItemPosition = new UserItemPosition[0] }); return Ok(roomService.GetUserItemPositionList(room)); @@ -785,16 +708,17 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetUserRoomItemPositions")] - public IActionResult SetUserRoomItemPositions([FromForm] string apiToken, [FromForm] string createXml, [FromForm] string updateXml, [FromForm] string removeXml, [FromForm] string roomID) { + [VikingSession] + public IActionResult SetUserRoomItemPositions(Viking viking, [FromForm] string createXml, [FromForm] string updateXml, [FromForm] string removeXml, [FromForm] string roomID) { if (roomID is null) roomID = ""; - Room? room = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.FirstOrDefault(x => x.RoomId == roomID); + Room? room = viking.Rooms.FirstOrDefault(x => x.RoomId == roomID); if (room is null) { room = new Room { RoomId = roomID, Items = new List() }; - ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.Add(room); + viking.Rooms.Add(room); ctx.SaveChanges(); } @@ -858,16 +782,17 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetUserRoom")] - public IActionResult SetUserRoom([FromForm] string apiToken, [FromForm] string request) { + [VikingSession] + public IActionResult SetUserRoom(Viking viking, [FromForm] string request) { UserRoom roomRequest = XmlUtil.DeserializeXml(request); - Room? room = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.FirstOrDefault(x => x.RoomId == roomRequest.RoomID); + Room? room = viking.Rooms.FirstOrDefault(x => x.RoomId == roomRequest.RoomID); if (room is null) { // setting farm room name can be done before call SetUserRoomItemPositions room = new Room { RoomId = roomRequest.RoomID, Name = roomRequest.Name }; - ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.Add(room); + viking.Rooms.Add(room); } else { room.Name = roomRequest.Name; } @@ -882,21 +807,22 @@ public class ContentController : Controller { [Produces("application/xml")] [Route("ContentWebService.asmx/GetUserActivityByUserID")] public IActionResult GetUserActivityByUserID() { + // TODO: This is a placeholder return Ok(new ArrayOfUserActivity { UserActivity = new UserActivity[0] }); } [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetNextItemState")] - public IActionResult SetNextItemState([FromForm] string apiToken, [FromForm] string setNextItemStateRequest) { + [VikingSession] + public IActionResult SetNextItemState(Viking viking, [FromForm] string setNextItemStateRequest) { SetNextItemStateRequest request = XmlUtil.DeserializeXml(setNextItemStateRequest); RoomItem? item = ctx.RoomItems.FirstOrDefault(x => x.Id == request.UserItemPositionID); if (item is null) return Ok(); - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (item.Room.Viking != viking) - return Unauthorized(); + return Unauthorized("Can't set state not owned item"); // NOTE: The game sets OverrideStateCriteria only if a speedup is used return Ok(roomService.NextItemState(item, request.OverrideStateCriteria)); diff --git a/src/Controllers/Common/ItemStoreController.cs b/src/Controllers/Common/ItemStoreController.cs index f0aadf5..f5569bf 100644 --- a/src/Controllers/Common/ItemStoreController.cs +++ b/src/Controllers/Common/ItemStoreController.cs @@ -11,9 +11,12 @@ public class ItemStoreController : Controller { private readonly DBContext ctx; private StoreService storeService; - public ItemStoreController(DBContext ctx, StoreService storeService) { + private ItemService itemService; + + public ItemStoreController(DBContext ctx, StoreService storeService, ItemService itemService) { this.ctx = ctx; this.storeService = storeService; + this.itemService = itemService; } [HttpPost] @@ -34,6 +37,15 @@ public class ItemStoreController : Controller { return Ok(response); } + [HttpPost] + [Produces("application/xml")] + [Route("ItemStoreWebService.asmx/GetItem")] + public IActionResult GetItem([FromForm] int itemId) { + if (itemId == 0) // For a null item, return an empty item + return Ok(new ItemData()); + return Ok(itemService.GetItem(itemId)); + } + [HttpPost] //[Produces("application/xml")] [Route("ItemStoreWebService.asmx/GetRankAttributeData")] @@ -45,7 +57,8 @@ public class ItemStoreController : Controller { [HttpPost] [Produces("application/xml")] [Route("ItemStoreWebService.asmx/GetAnnouncementsByUser")] - public IActionResult GetAnnouncements([FromForm] string apiToken, [FromForm] int worldObjectID) { + //[VikingSession(UseLock=false)] + public IActionResult GetAnnouncements([FromForm] int worldObjectID) { // TODO: This is a placeholder, although this endpoint seems to be only used to send announcements to the user (such as the server shutdown), so this might be sufficient. return Ok(new AnnouncementList()); } diff --git a/src/Controllers/Common/MembershipController.cs b/src/Controllers/Common/MembershipController.cs index 05c5937..cf88960 100644 --- a/src/Controllers/Common/MembershipController.cs +++ b/src/Controllers/Common/MembershipController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using sodoff.Attributes; using sodoff.Model; using sodoff.Schema; @@ -25,15 +26,8 @@ public class MembershipController : Controller { [HttpPost] [Produces("application/xml")] [Route("MembershipWebService.asmx/GetChildList")] - public IActionResult GetChildList([FromForm] string apiToken) { - User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.User; - if (user is null) - // TODO: what response for not logged in? - return null; - - if (user.Vikings.Count <= 0) - return null; - + [VikingSession(Mode=VikingSession.Modes.USER, UseLock=false)] + public IActionResult GetChildList(User user) { ChildList profiles = new ChildList(); profiles.strings = user.Vikings.Select(viking => viking.Id + ", " + viking.Name).ToArray(); diff --git a/src/Controllers/Common/ProfileController.cs b/src/Controllers/Common/ProfileController.cs index 00148cd..113e225 100644 --- a/src/Controllers/Common/ProfileController.cs +++ b/src/Controllers/Common/ProfileController.cs @@ -1,5 +1,6 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc; +using sodoff.Attributes; using sodoff.Model; using sodoff.Schema; using sodoff.Services; @@ -32,26 +33,16 @@ public class ProfileController : Controller { [HttpPost] [Produces("application/xml")] [Route("ProfileWebService.asmx/GetUserProfile")] - public IActionResult GetUserProfile([FromForm] string apiToken) { - Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; - User? user = viking?.User; - if (user is null || viking is null) { - // TODO: what response for not logged in? - return Ok(); - } - - return Ok(GetProfileDataFromViking(viking)); + [VikingSession(UseLock=false)] + public IActionResult GetUserProfile(Viking viking) { + return Ok(GetProfileDataFromViking(viking)); } [HttpPost] [Produces("application/xml")] [Route("ProfileWebService.asmx/GetDetailedChildList")] - public Schema.UserProfileDataList? GetDetailedChildList([FromForm] string parentApiToken) { - User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == parentApiToken)?.User; - if (user is null) - // TODO: what response for not logged in? - return null; - + [VikingSession(Mode=VikingSession.Modes.USER, ApiToken="parentApiToken", UseLock=false)] + public Schema.UserProfileDataList? GetDetailedChildList(User user) { if (user.Vikings.Count <= 0) return null; @@ -64,7 +55,7 @@ public class ProfileController : Controller { [HttpPost] [Produces("application/xml")] [Route("ProfileWebService.asmx/GetQuestions")] - public IActionResult GetQuestions([FromForm] string apiToken) { + public IActionResult GetQuestions() { return Ok(new ProfileQuestionData { Lists = new ProfileQuestionList[] { new ProfileQuestionList { diff --git a/src/Controllers/Common/RatingController.cs b/src/Controllers/Common/RatingController.cs index 2ade5db..019c583 100644 --- a/src/Controllers/Common/RatingController.cs +++ b/src/Controllers/Common/RatingController.cs @@ -12,7 +12,8 @@ public class RatingController : Controller [HttpPost] [Produces("application/xml")] [Route("V2/Ratingwebservice.asmx/GetAverageRatingForRoom")] - public IActionResult GetAverageRatingForRoom([FromForm] string apiToken, [FromForm] string request) + //[VikingSession(UseLock=false)] + public IActionResult GetAverageRatingForRoom(/*Viking viking,*/ [FromForm] string request) { // TODO: This is a placeholder return Ok(5);