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,130 +69,66 @@ 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> switch (gameToken.GameVersion)
while (await reader.ReadAsync()) // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault {
switch (reader.NodeType) case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3
{ {
case XmlNodeType.Element: user.PlanetHashLBP2 = update.PlanetHash;
path.Add(reader.Name); user.PlanetHashLBP3 = update.PlanetHash;
break; 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)
{
case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3
{
user.PlanetHashLBP2 = await reader.GetValueAsync();
user.PlanetHashLBP3 = await reader.GetValueAsync();
break;
}
case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here
{
user.PlanetHashLBP3 = await reader.GetValueAsync();
break;
}
case GameVersion.LittleBigPlanetVita:
{
user.PlanetHashLBPVita = await reader.GetValueAsync();
break;
}
case GameVersion.LittleBigPlanet1:
case GameVersion.LittleBigPlanetPSP:
case GameVersion.Unknown:
default: // The rest do not support custom earths.
{
throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth");
}
}
break;
}
case "yay2":
{
user.YayHash = await reader.GetValueAsync();
break;
}
case "meh2":
{
user.MehHash = await reader.GetValueAsync();
break;
}
case "boo2":
{
user.BooHash = await reader.GetValueAsync();
break;
}
}
break;
case XmlNodeType.EndElement:
path.RemoveAt(path.Count - 1);
break;
} }
case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here
{
user.PlanetHashLBP3 = update.PlanetHash;
break;
}
case GameVersion.LittleBigPlanetVita:
{
user.PlanetHashLBPVita = update.PlanetHash;
break;
}
case GameVersion.LittleBigPlanet1:
case GameVersion.LittleBigPlanetPSP:
case GameVersion.Unknown:
default: // The rest do not support custom earths.
{
throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth");
}
}
} }
// 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 (update.Location != null)
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 Location? loc = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId);
if (loc == null) throw new Exception("User loc is null, this should never happen.");
if (l == null) throw new Exception("this shouldn't happen ever but we handle this"); loc.X = update.Location.X;
loc.Y = update.Location.Y;
// 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 if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync();
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>
<p>@Model.ProfileUser.Biography</p> @if (string.IsNullOrWhiteSpace(Model.ProfileUser.Biography))
{
<p>@Model.ProfileUser.Username hasn't introduced themselves yet</p>
}
else
{
<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;
}