Clean up updateUser and some small changes (#246)

* Clean up updateUser and other minor changes

* Check if null or whitespace instead of checking string length

Co-authored-by: jvyden <jvyden@jvyden.xyz>
This commit is contained in:
Josh 2022-03-19 18:05:20 -05:00 committed by GitHub
commit 0d6e40a75d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 118 deletions

View file

@ -82,7 +82,8 @@ public class ResourcesController : ControllerBase
string path = FileHelper.GetResourcePath(hash); string path = FileHelper.GetResourcePath(hash);
FileHelper.EnsureDirectoryCreated(assetsDirectory); FileHelper.EnsureDirectoryCreated(assetsDirectory);
if (FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded // lbp treats code 409 as success and as an indicator that the file is already present
if (FileHelper.ResourceExists(hash)) this.Conflict();
Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance); Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance);
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader)); LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
@ -90,7 +91,7 @@ public class ResourcesController : ControllerBase
if (!FileHelper.IsFileSafe(file)) if (!FileHelper.IsFileSafe(file))
{ {
Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance); Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
return this.UnprocessableEntity(); return this.Conflict();
} }
string calculatedHash = file.Hash; string calculatedHash = file.Hash;

View file

@ -5,7 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles; using LBPUnion.ProjectLighthouse.Types.Profiles;
@ -69,79 +69,44 @@ public class UserController : ControllerBase
User user = userAndToken.Value.Item1; User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2; GameToken gameToken = userAndToken.Value.Item2;
XmlReaderSettings settings = new()
{
Async = true, // this is apparently not default
};
bool locationChanged = false; this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
// xml hack so we can use one class to deserialize different root names
string rootElement = bodyString.Contains("updateUser") ? "updateUser" : "user";
XmlSerializer serializer = new(typeof(UserUpdate), new XmlRootAttribute(rootElement));
UserUpdate? update = (UserUpdate?) serializer.Deserialize(new StringReader(bodyString));
// this is an absolute mess, but necessary because LBP only sends what changed if (update == null) return this.BadRequest();
//
// example for changing profile card location: if (update.Biography != null) user.Biography = update.Biography;
// <updateUser>
// <location> if (update.IconHash != null) user.IconHash = update.IconHash;
// <x>1234</x>
// <y>1234</y> if (update.YayHash != null) user.YayHash = update.YayHash;
// </location>
// </updateUser> if (update.MehHash != null) user.MehHash = update.MehHash;
//
// example for changing biography: if (update.BooHash != null) user.BooHash = update.BooHash;
// <updateUser>
// <biography>biography stuff</biography> if (update.PlanetHash != null)
// </updateUser>
//
// if you find a way to make it not stupid feel free to replace this
using (XmlReader reader = XmlReader.Create(this.Request.Body, settings))
{
List<string> path = new(); // you can think of this as a file path in the XML, like <updateUser> -> <location> -> <x>
while (await reader.ReadAsync()) // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (reader.NodeType)
{
case XmlNodeType.Element:
path.Add(reader.Name);
break;
case XmlNodeType.Text:
switch (path[1])
{
case "biography":
{
user.Biography = await reader.GetValueAsync();
break;
}
case "location":
{
locationChanged = true; // if we're here then we're probably about to change the location.
// ReSharper disable once ConvertIfStatementToSwitchStatement
if (path[2] == "x")
user.Location.X = Convert.ToInt32
(await reader.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
else if (path[2] == "y") user.Location.Y = Convert.ToInt32(await reader.GetValueAsync());
break;
}
case "icon":
{
user.IconHash = await reader.GetValueAsync();
break;
}
case "planets":
{ {
switch (gameToken.GameVersion) switch (gameToken.GameVersion)
{ {
case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3 case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3
{ {
user.PlanetHashLBP2 = await reader.GetValueAsync(); user.PlanetHashLBP2 = update.PlanetHash;
user.PlanetHashLBP3 = await reader.GetValueAsync(); user.PlanetHashLBP3 = update.PlanetHash;
break; break;
} }
case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here
{ {
user.PlanetHashLBP3 = await reader.GetValueAsync(); user.PlanetHashLBP3 = update.PlanetHash;
break; break;
} }
case GameVersion.LittleBigPlanetVita: case GameVersion.LittleBigPlanetVita:
{ {
user.PlanetHashLBPVita = await reader.GetValueAsync(); user.PlanetHashLBPVita = update.PlanetHash;
break; break;
} }
case GameVersion.LittleBigPlanet1: case GameVersion.LittleBigPlanet1:
@ -152,47 +117,18 @@ public class UserController : ControllerBase
throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth"); throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth");
} }
} }
break;
} }
case "yay2":
if (update.Location != null)
{ {
user.YayHash = await reader.GetValueAsync(); Location? loc = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId);
break; if (loc == null) throw new Exception("User loc is null, this should never happen.");
}
case "meh2": loc.X = update.Location.X;
{ loc.Y = update.Location.Y;
user.MehHash = await reader.GetValueAsync();
break;
}
case "boo2":
{
user.BooHash = await reader.GetValueAsync();
break;
}
} }
break; if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync();
case XmlNodeType.EndElement:
path.RemoveAt(path.Count - 1);
break;
}
}
// the way location on a user card works is stupid and will not save with the way below as-is, so we do the following:
if (locationChanged) // only modify the database if we modify here
{
Location? l = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId); // find the location in the database again
if (l == null) throw new Exception("this shouldn't happen ever but we handle this");
// set the location in the database to the one we modified above
l.X = user.Location.X;
l.Y = user.Location.Y;
// now both are in sync, and will update in the database.
}
if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
return this.Ok(); return this.Ok();
} }

View file

@ -75,7 +75,7 @@ public class Database : DbContext
Username = username, Username = username,
Password = password, Password = password,
LocationId = l.Id, LocationId = l.Id,
Biography = username + " hasn't introduced themselves yet.", Biography = "",
EmailAddress = emailAddress, EmailAddress = emailAddress,
}; };
this.Users.Add(user); this.Users.Add(user);

View file

@ -83,7 +83,14 @@
<div class="eight wide column"> <div class="eight wide column">
<div class="ui blue segment"> <div class="ui blue segment">
<h2>Biography</h2> <h2>Biography</h2>
@if (string.IsNullOrWhiteSpace(Model.ProfileUser.Biography))
{
<p>@Model.ProfileUser.Username hasn't introduced themselves yet</p>
}
else
{
<p>@Model.ProfileUser.Biography</p> <p>@Model.ProfileUser.Biography</p>
}
</div> </div>
</div> </div>
<div class="eight wide column"> <div class="eight wide column">

View file

@ -0,0 +1,29 @@
#nullable enable
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Types.Profiles;
namespace LBPUnion.ProjectLighthouse.Types;
public class UserUpdate
{
[XmlElement("location")]
public Location? Location;
[XmlElement("biography")]
public string? Biography;
[XmlElement("icon")]
public string? IconHash;
[XmlElement("planets")]
public string? PlanetHash;
[XmlElement("yay2")]
public string? YayHash;
[XmlElement("meh2")]
public string? MehHash;
[XmlElement("boo2")]
public string? BooHash;
}