Viking session via ActionFilter (#29)

This commit is contained in:
rpaciorek 2023-08-31 19:01:55 +00:00 committed by GitHub
parent 81e5718e05
commit e3314ae1f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 203 deletions

View File

@ -1,37 +1,63 @@
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using sodoff.Model; using sodoff.Model;
using sodoff.Controllers.Common;
namespace sodoff.Attributes; namespace sodoff.Attributes;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class VikingSession : Attribute, IAsyncActionFilter { 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) { 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 }; context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 };
return; return;
} }
Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == context.HttpContext.Request.Form["apiToken"].ToString()); Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == context.HttpContext.Request.Form[ApiToken].ToString());
if (session?.VikingId is null) {
// 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 }; context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 };
return; return;
} }
// NOTE: we can't refer to session.Viking here, because it may cause to ignore modifications from the threads we are waiting for // call next (with lock if requested)
// we can use session.Viking only after vikingMutex.WaitOne()
Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + session.VikingId); if (UseLock) {
try { // NOTE: we can't refer to session.User / session.Viking here,
vikingMutex.WaitOne(); // 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; context.ActionArguments["viking"] = session.Viking;
await next(); await next();
} finally {
vikingMutex.ReleaseMutex();
} }
} }
} }

View File

@ -20,14 +20,8 @@ public class AchievementController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("AchievementWebService.asmx/GetPetAchievementsByUserID")] [Route("AchievementWebService.asmx/GetPetAchievementsByUserID")]
public IActionResult GetPetAchievementsByUserID([FromForm] string apiToken, [FromForm] string userId) { [VikingSession(UseLock=false)]
// TODO: check session public IActionResult GetPetAchievementsByUserID(Viking viking, [FromForm] string userId) {
Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Id == userId);
if (viking is null) {
return null;
}
List<UserAchievementInfo> dragonsAchievement = new List<UserAchievementInfo>(); List<UserAchievementInfo> dragonsAchievement = new List<UserAchievementInfo>();
foreach (Dragon dragon in viking.Dragons) { foreach (Dragon dragon in viking.Dragons) {
dragonsAchievement.Add( dragonsAchievement.Add(
@ -68,12 +62,8 @@ public class AchievementController : Controller {
[HttpPost] [HttpPost]
[Route("AchievementWebService.asmx/SetDragonXP")] // used by dragonrescue-import [Route("AchievementWebService.asmx/SetDragonXP")] // used by dragonrescue-import
public IActionResult SetDragonXP([FromForm] string apiToken, [FromForm] string dragonId, [FromForm] int value) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult SetDragonXP(Viking viking, [FromForm] string dragonId, [FromForm] int value) {
if (viking is null) {
return Unauthorized();
}
Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.EntityId == dragonId); Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.EntityId == dragonId);
if (dragon is null) { if (dragon is null) {
return Conflict("Dragon not found"); return Conflict("Dragon not found");
@ -87,12 +77,8 @@ public class AchievementController : Controller {
[HttpPost] [HttpPost]
[Route("AchievementWebService.asmx/SetPlayerXP")] // used by dragonrescue-import [Route("AchievementWebService.asmx/SetPlayerXP")] // used by dragonrescue-import
public IActionResult SetDragonXP([FromForm] string apiToken, [FromForm] int type, [FromForm] int value) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult SetDragonXP(Viking viking, [FromForm] int type, [FromForm] int value) {
if (viking is null) {
return Unauthorized();
}
if (!Enum.IsDefined(typeof(AchievementPointTypes), type)) { if (!Enum.IsDefined(typeof(AchievementPointTypes), type)) {
return Conflict("Invalid XP type"); return Conflict("Invalid XP type");
} }
@ -138,7 +124,7 @@ public class AchievementController : Controller {
[Produces("application/xml")] [Produces("application/xml")]
[Route("AchievementWebService.asmx/SetAchievementAndGetReward")] [Route("AchievementWebService.asmx/SetAchievementAndGetReward")]
[Route("AchievementWebService.asmx/SetUserAchievementAndGetReward")] [Route("AchievementWebService.asmx/SetUserAchievementAndGetReward")]
[VikingSession()] [VikingSession(UseLock=true)]
public IActionResult SetAchievementAndGetReward(Viking viking, [FromForm] int achievementID) { public IActionResult SetAchievementAndGetReward(Viking viking, [FromForm] int achievementID) {
var rewards = achievementService.ApplyAchievementRewardsByID(viking, achievementID); var rewards = achievementService.ApplyAchievementRewardsByID(viking, achievementID);
@ -151,7 +137,7 @@ public class AchievementController : Controller {
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/AchievementWebService.asmx/SetUserAchievementTask")] [Route("V2/AchievementWebService.asmx/SetUserAchievementTask")]
[DecryptRequest("achievementTaskSetRequest")] [DecryptRequest("achievementTaskSetRequest")]
[VikingSession()] [VikingSession(UseLock=true)]
public IActionResult SetUserAchievementTask(Viking viking) { public IActionResult SetUserAchievementTask(Viking viking) {
AchievementTaskSetRequest request = XmlUtil.DeserializeXml<AchievementTaskSetRequest>(Request.Form["achievementTaskSetRequest"]); AchievementTaskSetRequest request = XmlUtil.DeserializeXml<AchievementTaskSetRequest>(Request.Form["achievementTaskSetRequest"]);
@ -178,9 +164,9 @@ public class AchievementController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("AchievementWebService.asmx/SetAchievementByEntityIDs")] [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 // TODO: This is a placeholder
Viking? viking = ctx.Sessions.FirstOrDefault(x => x.ApiToken == apiToken).Viking;
return Ok(new AchievementReward[1] { return Ok(new AchievementReward[1] {
new AchievementReward { new AchievementReward {
Amount = 25, Amount = 25,

View File

@ -31,7 +31,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetDefaultNameSuggestion")] [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 string[] adjs = { //Adjectives used to generate suggested names
"Adventurous", "Active", "Alert", "Attentive", "Adventurous", "Active", "Alert", "Attentive",
"Beautiful", "Berkian", "Berserker", "Bold", "Brave", "Beautiful", "Berkian", "Berserker", "Bold", "Brave",
@ -60,13 +61,8 @@ public class ContentController : Controller {
"Zealous", "Zealot" "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) if (user is null)
user = session.Viking?.User; user = viking.User;
string uname = user.Username; string uname = user.Username;
Random choice = new Random(); //Randomizer for selecting random adjectives Random choice = new Random(); //Randomizer for selecting random adjectives
@ -87,13 +83,7 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/ValidateName")] [Route("V2/ContentWebService.asmx/ValidateName")]
public IActionResult ValidateName([FromForm] string apiToken,[FromForm] string nameValidationRequest) { public IActionResult ValidateName([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 });
}
// Check if name populated // Check if name populated
NameValidationRequest request = XmlUtil.DeserializeXml<NameValidationRequest>(nameValidationRequest); NameValidationRequest request = XmlUtil.DeserializeXml<NameValidationRequest>(nameValidationRequest);
@ -173,15 +163,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetCommonInventory")] [Route("ContentWebService.asmx/GetCommonInventory")]
public IActionResult GetCommonInventory([FromForm] string apiToken) { [VikingSession(Mode=VikingSession.Modes.VIKING_OR_USER, UseLock=false)]
// TODO: what is the difference between this and v2? this can be called with user apiToken and v2 not? maybe it should be unified? public IActionResult GetCommonInventory(User? user, Viking? viking) {
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> userItemData;
if (viking != null) { if (viking != null) {
return Ok( inventoryService.GetCommonInventoryData(viking) ); return Ok( inventoryService.GetCommonInventoryData(viking) );
} else { } else {
@ -205,22 +188,17 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/GetCommonInventory")] [Route("V2/ContentWebService.asmx/GetCommonInventory")]
public IActionResult GetCommonInventoryV2([FromForm] string apiToken) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult GetCommonInventoryV2(Viking viking) {
if (viking is null || viking.Inventory is null) return Ok();
return Ok(inventoryService.GetCommonInventoryData(viking)); return Ok(inventoryService.GetCommonInventoryData(viking));
} }
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetCommonInventory")] [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<CommonInventoryRequest[]>(commonInventoryRequestXml); CommonInventoryRequest[] request = XmlUtil.DeserializeXml<CommonInventoryRequest[]>(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<CommonInventoryResponseItem> responseItems = new(); List<CommonInventoryResponseItem> responseItems = new();
// SetCommonInventory can remove any number of items from the inventory, this checks if it's possible // 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] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/UseInventory")] [Route("ContentWebService.asmx/UseInventory")]
public IActionResult UseInventory([FromForm] string apiToken, [FromForm] int userInventoryId, [FromForm] int numberOfUses) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult UseInventory(Viking viking, [FromForm] int userInventoryId, [FromForm] int numberOfUses) {
InventoryItem? item = viking.Inventory.InventoryItems.FirstOrDefault(e => e.Id == userInventoryId); InventoryItem? item = viking.Inventory.InventoryItems.FirstOrDefault(e => e.Id == userInventoryId);
if (item is null) if (item is null)
return Ok(false); return Ok(false);
@ -289,27 +267,11 @@ public class ContentController : Controller {
return Ok(new DateTime(DateTime.Now.Ticks)); 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] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/SetAvatar")] [Route("V2/ContentWebService.asmx/SetAvatar")]
public IActionResult SetAvatar([FromForm] string apiToken, [FromForm] string contentXML) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult SetAvatar(Viking viking, [FromForm] string contentXML) {
if (viking is null) {
return Ok(new SetAvatarResult {
Success = false,
StatusCode = AvatarValidationResult.Error
});
}
AvatarData avatarData = XmlUtil.DeserializeXml<AvatarData>(contentXML); AvatarData avatarData = XmlUtil.DeserializeXml<AvatarData>(contentXML);
foreach (AvatarDataPart part in avatarData.Part) { foreach (AvatarDataPart part in avatarData.Part) {
if (part.PartType == "Version") { if (part.PartType == "Version") {
@ -331,22 +293,17 @@ public class ContentController : Controller {
ctx.SaveChanges(); ctx.SaveChanges();
return Ok(new SetAvatarResult { return Ok(new SetAvatarResult {
Success = true, Success = true,
DisplayName = viking.Name, DisplayName = viking.Name,
StatusCode = AvatarValidationResult.Valid StatusCode = AvatarValidationResult.Valid
}); });
} }
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/CreatePet")] [Route("V2/ContentWebService.asmx/CreatePet")]
public IActionResult CreatePet([FromForm] string apiToken, [FromForm] string request) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult CreatePet(Viking viking, [FromForm] string request) {
if (viking is null) {
// TODO: result for invalid session
return Ok();
}
RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml<RaisedPetRequest>(request); RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml<RaisedPetRequest>(request);
// TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything // TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything
@ -406,14 +363,9 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("v3/ContentWebService.asmx/SetRaisedPet")] [Route("v3/ContentWebService.asmx/SetRaisedPet")]
public IActionResult SetRaisedPet([FromForm] string apiToken, [FromForm] string request, [FromForm] bool? import) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult SetRaisedPet(Viking viking, [FromForm] string request, [FromForm] bool? import) {
if (viking is null) { RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml<RaisedPetRequest>(request);
// TODO: result for invalid session
return Ok();
}
RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml<RaisedPetRequest>(request);
// Find the dragon // Find the dragon
Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetRequest.RaisedPetData.RaisedPetID); Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetRequest.RaisedPetData.RaisedPetID);
@ -437,13 +389,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetSelectedPet")] [Route("ContentWebService.asmx/SetSelectedPet")]
public IActionResult SetSelectedPet([FromForm] string apiToken, [FromForm] int raisedPetID) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult SetSelectedPet(Viking viking, [FromForm] int raisedPetID) {
if (viking is null) {
// TODO: result for invalid session
return Ok();
}
// Find the dragon // Find the dragon
Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetID); Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetID);
if (dragon is null) { if (dragon is null) {
@ -463,13 +410,9 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")] [Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")]
public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public RaisedPetData[]? GetAllActivePetsByuserId(Viking viking, [FromForm] string userId, [FromForm] bool active) {
if (viking is null) { RaisedPetData[] dragons = viking.Dragons // TODO (multiplayer) we should use userId ?
return null;
}
RaisedPetData[] dragons = viking.Dragons // TODO (multiplayer) we should use userId
.Where(d => d.RaisedPetData is not null) .Where(d => d.RaisedPetData is not null)
.Select(GetRaisedPetDataFromDragon) .Select(GetRaisedPetDataFromDragon)
.ToArray(); .ToArray();
@ -483,12 +426,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetUnselectedPetByTypes")] [Route("ContentWebService.asmx/GetUnselectedPetByTypes")]
public RaisedPetData[]? GetUnselectedPetByTypes([FromForm] string apiToken, [FromForm] string petTypeIDs, [FromForm] bool active) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public RaisedPetData[]? GetUnselectedPetByTypes(Viking viking, [FromForm] string petTypeIDs, [FromForm] bool active) {
if (viking is null) {
return null;
}
RaisedPetData[] dragons = viking.Dragons RaisedPetData[] dragons = viking.Dragons
.Where(d => d.RaisedPetData is not null) .Where(d => d.RaisedPetData is not null)
.Select(GetRaisedPetDataFromDragon) .Select(GetRaisedPetDataFromDragon)
@ -516,12 +455,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetSelectedRaisedPet")] [Route("ContentWebService.asmx/GetSelectedRaisedPet")]
public RaisedPetData[]? GetSelectedRaisedPet([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool isActive) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public RaisedPetData[]? GetSelectedRaisedPet(Viking viking, [FromForm] string userId, [FromForm] bool isActive) {
if (viking is null) {
return null;
}
Dragon? dragon = viking.SelectedDragon; Dragon? dragon = viking.SelectedDragon;
if (dragon is null) { if (dragon is null) {
return null; return null;
@ -535,12 +470,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetImage")] [Route("ContentWebService.asmx/SetImage")]
public bool SetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public bool SetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) {
if (viking is null || viking.Dragons is null) {
return false;
}
// TODO: the other properties of contentXML // TODO: the other properties of contentXML
ImageData data = XmlUtil.DeserializeXml<ImageData>(contentXML); ImageData data = XmlUtil.DeserializeXml<ImageData>(contentXML);
@ -572,12 +503,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetImage")] [Route("ContentWebService.asmx/GetImage")]
public ImageData? GetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public ImageData? GetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot) {
if (viking is null || viking.Images is null) {
return null;
}
return GetImageData(viking, ImageType, ImageSlot); return GetImageData(viking, ImageType, ImageSlot);
} }
@ -650,10 +577,10 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/AcceptMission")] [Route("ContentWebService.asmx/AcceptMission")]
public IActionResult AcceptMission([FromForm] string userId, [FromForm] int missionId) { [VikingSession]
Viking? viking = ctx.Vikings.FirstOrDefault(x => x.Id == userId); public IActionResult AcceptMission(Viking viking, [FromForm] string userId, [FromForm] int missionId) {
if (viking is null) if (viking.Id != userId)
return Ok(false); return Unauthorized("Can't accept not owned mission");
MissionState? missionState = viking.MissionStates.FirstOrDefault(x => x.MissionId == missionId); MissionState? missionState = viking.MissionStates.FirstOrDefault(x => x.MissionId == missionId);
if (missionState is null || missionState.MissionStatus != MissionStatus.Upcoming) if (missionState is null || missionState.MissionStatus != MissionStatus.Upcoming)
@ -668,6 +595,7 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/GetUserMissionState")] [Route("V2/ContentWebService.asmx/GetUserMissionState")]
//[VikingSession(UseLock=false)]
public IActionResult GetUserMissionState([FromForm] string userId, [FromForm] string filter) { public IActionResult GetUserMissionState([FromForm] string userId, [FromForm] string filter) {
MissionRequestFilterV2 filterV2 = XmlUtil.DeserializeXml<MissionRequestFilterV2>(filter); MissionRequestFilterV2 filterV2 = XmlUtil.DeserializeXml<MissionRequestFilterV2>(filter);
Viking? viking = ctx.Vikings.FirstOrDefault(x => x.Id == userId); Viking? viking = ctx.Vikings.FirstOrDefault(x => x.Id == userId);
@ -686,10 +614,10 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/SetTaskState")] [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) { [VikingSession]
Session? session = ctx.Sessions.FirstOrDefault(s => s.ApiToken == apiToken); public IActionResult SetTaskState(Viking viking, [FromForm] string userId, [FromForm] int missionId, [FromForm] int taskId, [FromForm] bool completed, [FromForm] string xmlPayload) {
if (session is null || session.VikingId != userId) if (viking.Id != userId)
return Ok(new SetTaskStateResult { Success = false, Status = SetTaskStateStatus.Unknown }); return Unauthorized("Can't set not owned task");
List<MissionCompletedResult> results = missionService.UpdateTaskProgress(missionId, taskId, userId, completed, xmlPayload); List<MissionCompletedResult> results = missionService.UpdateTaskProgress(missionId, taskId, userId, completed, xmlPayload);
@ -715,11 +643,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/ContentWebService.asmx/PurchaseItems")] [Route("V2/ContentWebService.asmx/PurchaseItems")]
public IActionResult PurchaseItems([FromForm] string apiToken, [FromForm] string purchaseItemRequest) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult PurchaseItems(Viking viking, [FromForm] string purchaseItemRequest) {
if (viking is null)
return Ok();
PurchaseStoreItemRequest request = XmlUtil.DeserializeXml<PurchaseStoreItemRequest>(purchaseItemRequest); PurchaseStoreItemRequest request = XmlUtil.DeserializeXml<PurchaseStoreItemRequest>(purchaseItemRequest);
CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[request.Items.Length]; CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[request.Items.Length];
for (int i = 0; i < request.Items.Length; i++) { for (int i = 0; i < request.Items.Length; i++) {
@ -744,11 +669,8 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/PurchaseItems")] [Route("ContentWebService.asmx/PurchaseItems")]
public IActionResult PurchaseItemsV1([FromForm] string apiToken, [FromForm] string itemIDArrayXml) { [VikingSession]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult PurchaseItemsV1(Viking viking, [FromForm] string itemIDArrayXml) {
if (viking is null)
return Ok();
int[] itemIdArr = XmlUtil.DeserializeXml<int[]>(itemIDArrayXml); int[] itemIdArr = XmlUtil.DeserializeXml<int[]>(itemIDArrayXml);
CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[itemIdArr.Length]; CommonInventoryResponseItem[] items = new CommonInventoryResponseItem[itemIdArr.Length];
for (int i = 0; i < itemIdArr.Length; i++) { for (int i = 0; i < itemIdArr.Length; i++) {
@ -773,10 +695,11 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetUserRoomItemPositions")] [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) if (roomID is null)
roomID = ""; 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) if (room is null)
return Ok(new UserItemPositionList { UserItemPosition = new UserItemPosition[0] }); return Ok(new UserItemPositionList { UserItemPosition = new UserItemPosition[0] });
return Ok(roomService.GetUserItemPositionList(room)); return Ok(roomService.GetUserItemPositionList(room));
@ -785,16 +708,17 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetUserRoomItemPositions")] [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) if (roomID is null)
roomID = ""; 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) { if (room is null) {
room = new Room { room = new Room {
RoomId = roomID, RoomId = roomID,
Items = new List<RoomItem>() Items = new List<RoomItem>()
}; };
ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.Add(room); viking.Rooms.Add(room);
ctx.SaveChanges(); ctx.SaveChanges();
} }
@ -858,16 +782,17 @@ public class ContentController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetUserRoom")] [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<UserRoom>(request); UserRoom roomRequest = XmlUtil.DeserializeXml<UserRoom>(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) { if (room is null) {
// setting farm room name can be done before call SetUserRoomItemPositions // setting farm room name can be done before call SetUserRoomItemPositions
room = new Room { room = new Room {
RoomId = roomRequest.RoomID, RoomId = roomRequest.RoomID,
Name = roomRequest.Name Name = roomRequest.Name
}; };
ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.Add(room); viking.Rooms.Add(room);
} else { } else {
room.Name = roomRequest.Name; room.Name = roomRequest.Name;
} }
@ -882,21 +807,22 @@ public class ContentController : Controller {
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/GetUserActivityByUserID")] [Route("ContentWebService.asmx/GetUserActivityByUserID")]
public IActionResult GetUserActivityByUserID() { public IActionResult GetUserActivityByUserID() {
// TODO: This is a placeholder
return Ok(new ArrayOfUserActivity { UserActivity = new UserActivity[0] }); return Ok(new ArrayOfUserActivity { UserActivity = new UserActivity[0] });
} }
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ContentWebService.asmx/SetNextItemState")] [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>(setNextItemStateRequest); SetNextItemStateRequest request = XmlUtil.DeserializeXml<SetNextItemStateRequest>(setNextItemStateRequest);
RoomItem? item = ctx.RoomItems.FirstOrDefault(x => x.Id == request.UserItemPositionID); RoomItem? item = ctx.RoomItems.FirstOrDefault(x => x.Id == request.UserItemPositionID);
if (item is null) if (item is null)
return Ok(); return Ok();
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking;
if (item.Room.Viking != 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 // NOTE: The game sets OverrideStateCriteria only if a speedup is used
return Ok(roomService.NextItemState(item, request.OverrideStateCriteria)); return Ok(roomService.NextItemState(item, request.OverrideStateCriteria));

View File

@ -11,9 +11,12 @@ public class ItemStoreController : Controller {
private readonly DBContext ctx; private readonly DBContext ctx;
private StoreService storeService; private StoreService storeService;
public ItemStoreController(DBContext ctx, StoreService storeService) { private ItemService itemService;
public ItemStoreController(DBContext ctx, StoreService storeService, ItemService itemService) {
this.ctx = ctx; this.ctx = ctx;
this.storeService = storeService; this.storeService = storeService;
this.itemService = itemService;
} }
[HttpPost] [HttpPost]
@ -34,6 +37,15 @@ public class ItemStoreController : Controller {
return Ok(response); 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] [HttpPost]
//[Produces("application/xml")] //[Produces("application/xml")]
[Route("ItemStoreWebService.asmx/GetRankAttributeData")] [Route("ItemStoreWebService.asmx/GetRankAttributeData")]
@ -45,7 +57,8 @@ public class ItemStoreController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ItemStoreWebService.asmx/GetAnnouncementsByUser")] [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. // 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()); return Ok(new AnnouncementList());
} }

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using sodoff.Attributes;
using sodoff.Model; using sodoff.Model;
using sodoff.Schema; using sodoff.Schema;
@ -25,15 +26,8 @@ public class MembershipController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("MembershipWebService.asmx/GetChildList")] [Route("MembershipWebService.asmx/GetChildList")]
public IActionResult GetChildList([FromForm] string apiToken) { [VikingSession(Mode=VikingSession.Modes.USER, UseLock=false)]
User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.User; public IActionResult GetChildList(User user) {
if (user is null)
// TODO: what response for not logged in?
return null;
if (user.Vikings.Count <= 0)
return null;
ChildList profiles = new ChildList(); ChildList profiles = new ChildList();
profiles.strings = user.Vikings.Select(viking => viking.Id + ", " + viking.Name).ToArray(); profiles.strings = user.Vikings.Select(viking => viking.Id + ", " + viking.Name).ToArray();

View File

@ -1,5 +1,6 @@
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using sodoff.Attributes;
using sodoff.Model; using sodoff.Model;
using sodoff.Schema; using sodoff.Schema;
using sodoff.Services; using sodoff.Services;
@ -32,26 +33,16 @@ public class ProfileController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ProfileWebService.asmx/GetUserProfile")] [Route("ProfileWebService.asmx/GetUserProfile")]
public IActionResult GetUserProfile([FromForm] string apiToken) { [VikingSession(UseLock=false)]
Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; public IActionResult GetUserProfile(Viking viking) {
User? user = viking?.User; return Ok(GetProfileDataFromViking(viking));
if (user is null || viking is null) {
// TODO: what response for not logged in?
return Ok();
}
return Ok(GetProfileDataFromViking(viking));
} }
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ProfileWebService.asmx/GetDetailedChildList")] [Route("ProfileWebService.asmx/GetDetailedChildList")]
public Schema.UserProfileDataList? GetDetailedChildList([FromForm] string parentApiToken) { [VikingSession(Mode=VikingSession.Modes.USER, ApiToken="parentApiToken", UseLock=false)]
User? user = ctx.Sessions.FirstOrDefault(e => e.ApiToken == parentApiToken)?.User; public Schema.UserProfileDataList? GetDetailedChildList(User user) {
if (user is null)
// TODO: what response for not logged in?
return null;
if (user.Vikings.Count <= 0) if (user.Vikings.Count <= 0)
return null; return null;
@ -64,7 +55,7 @@ public class ProfileController : Controller {
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("ProfileWebService.asmx/GetQuestions")] [Route("ProfileWebService.asmx/GetQuestions")]
public IActionResult GetQuestions([FromForm] string apiToken) { public IActionResult GetQuestions() {
return Ok(new ProfileQuestionData { return Ok(new ProfileQuestionData {
Lists = new ProfileQuestionList[] { Lists = new ProfileQuestionList[] {
new ProfileQuestionList { new ProfileQuestionList {

View File

@ -12,7 +12,8 @@ public class RatingController : Controller
[HttpPost] [HttpPost]
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/Ratingwebservice.asmx/GetAverageRatingForRoom")] [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 // TODO: This is a placeholder
return Ok(5); return Ok(5);