From bce6d1e2effe7ceb55357f35cf3b4b2d7529c421 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 14 Oct 2021 23:49:22 -0400 Subject: [PATCH 1/7] Fix PlanetHash being null on user creation --- ProjectLighthouse/Database.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index a8372e49..dc33f549 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -28,7 +28,8 @@ namespace ProjectLighthouse { Username = username, LocationId = l.Id, Biography = "No biography provided", - Pins = "" + Pins = "", + PlanetHash = "", }; this.Users.Add(user); From 5052d19656fbe2136e1e3f2a241f391613953e87 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 14 Oct 2021 23:50:08 -0400 Subject: [PATCH 2/7] Basic testing framework --- ProjectLighthouse.Tests/DatabaseFact.cs | 11 +++++++ ProjectLighthouse.Tests/LighthouseTest.cs | 19 ++++++++++++ .../ProjectLighthouse.Tests.csproj | 29 +++++++++++++++++++ ...ProjectLighthouse.Tests.csproj.DotSettings | 2 ++ .../Tests/AuthenticationTest.cs | 28 ++++++++++++++++++ ProjectLighthouse.sln | 6 ++++ .../Controllers/LoginController.cs | 3 -- ProjectLighthouse/Types/ServerSettings.cs | 3 +- 8 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 ProjectLighthouse.Tests/DatabaseFact.cs create mode 100644 ProjectLighthouse.Tests/LighthouseTest.cs create mode 100644 ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj create mode 100644 ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj.DotSettings create mode 100644 ProjectLighthouse.Tests/Tests/AuthenticationTest.cs diff --git a/ProjectLighthouse.Tests/DatabaseFact.cs b/ProjectLighthouse.Tests/DatabaseFact.cs new file mode 100644 index 00000000..ecb8216f --- /dev/null +++ b/ProjectLighthouse.Tests/DatabaseFact.cs @@ -0,0 +1,11 @@ +using ProjectLighthouse.Types; +using Xunit; + +namespace ProjectLighthouse.Tests { + public sealed class DatabaseFact : FactAttribute { + public DatabaseFact() { + ServerSettings.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; + if(!ServerSettings.DbConnected) Skip = "Database not available"; + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs new file mode 100644 index 00000000..0cacb69c --- /dev/null +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -0,0 +1,19 @@ +using System; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using ProjectLighthouse.Types; + +namespace ProjectLighthouse.Tests { + public class LighthouseTest { + public readonly TestServer Server; + public readonly HttpClient Client; + + public LighthouseTest() { + this.Server = new TestServer(new WebHostBuilder() + .UseStartup()); + this.Client = this.Server.CreateClient(); + + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj new file mode 100644 index 00000000..cd72611b --- /dev/null +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -0,0 +1,29 @@ + + + + enable + + false + + net5.0;net6.0 + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj.DotSettings b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj.DotSettings new file mode 100644 index 00000000..eccc8454 --- /dev/null +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs new file mode 100644 index 00000000..e06ee7b3 --- /dev/null +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs @@ -0,0 +1,28 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace ProjectLighthouse.Tests { + public class AuthenticationTest : LighthouseTest { + [Fact] + public async Task ShouldReturnErrorOnNoPostData() { + var response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!); + Assert.False(response.IsSuccessStatusCode); + #if NET6_0_OR_GREATER + Assert.True(response.StatusCode == HttpStatusCode.BadRequest); + #else + Assert.True(response.StatusCode == HttpStatusCode.NotAcceptable); + #endif + } + + [DatabaseFact] + public async Task ShouldAuthenticateWithValidData() { + const char nullChar = (char)0x00; + const char sepChar = (char)0x20; + + var response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", new StringContent($"{nullChar}{sepChar}jvyden{nullChar}")); + Assert.True(response.StatusCode == HttpStatusCode.OK); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index 12322461..96db324b 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse", "ProjectLighthouse\ProjectLighthouse.csproj", "{C6CFD4AD-47ED-4C86-B0C4-A4216D82E0DC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests", "ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj", "{AFC74569-B289-4ACC-B21C-313A3A62C017}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {C6CFD4AD-47ED-4C86-B0C4-A4216D82E0DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {C6CFD4AD-47ED-4C86-B0C4-A4216D82E0DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6CFD4AD-47ED-4C86-B0C4-A4216D82E0DC}.Release|Any CPU.Build.0 = Release|Any CPU + {AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index 5b137aa4..dfb6a0fa 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -14,9 +14,6 @@ namespace ProjectLighthouse.Controllers { public class LoginController : ControllerBase { [HttpPost] public async Task Login() { - if(!this.Request.Query.TryGetValue("titleID", out StringValues _)) - return this.BadRequest(""); - string body = await new StreamReader(Request.Body).ReadToEndAsync(); LoginData loginData; diff --git a/ProjectLighthouse/Types/ServerSettings.cs b/ProjectLighthouse/Types/ServerSettings.cs index 39fc79d9..bde98a9c 100644 --- a/ProjectLighthouse/Types/ServerSettings.cs +++ b/ProjectLighthouse/Types/ServerSettings.cs @@ -16,10 +16,11 @@ namespace ProjectLighthouse.Types { public static string DbConnectionString { get { if(dbConnectionString == null) { - return dbConnectionString = Environment.GetEnvironmentVariable("LIGHTHOUSE_DB_CONNECTION_STRING") ?? ""; + return dbConnectionString = Environment.GetEnvironmentVariable("") ?? ""; } return dbConnectionString; } + set => dbConnectionString = value; } public static bool DbConnected { From bd8b86b65cef8c3b555c0c336d48c85702a4a18b Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 15 Oct 2021 00:38:33 -0400 Subject: [PATCH 3/7] Add CanSerializeBack, CanUseToken, and ShouldReturnForbiddenWhenNotAuthenticated authentication tests --- ProjectLighthouse.Tests/LighthouseTest.cs | 34 +++++++++++++- .../Tests/AuthenticationTest.cs | 44 ++++++++++++++++--- ProjectLighthouse/Types/LoginResult.cs | 5 +++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs index 0cacb69c..f76a6e60 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -1,7 +1,10 @@ -using System; +using System.IO; using System.Net.Http; +using System.Threading.Tasks; +using System.Xml.Serialization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using ProjectLighthouse.Serialization; using ProjectLighthouse.Types; namespace ProjectLighthouse.Tests { @@ -12,8 +15,37 @@ namespace ProjectLighthouse.Tests { public LighthouseTest() { this.Server = new TestServer(new WebHostBuilder() .UseStartup()); + this.Client = this.Server.CreateClient(); + } + public async Task AuthenticateResponse(int number = 0) { + const char nullChar = (char)0x00; + const char sepChar = (char)0x20; + const string username = "unitTestUser"; + + string stringContent = $"{nullChar}{sepChar}{username}{number}{nullChar}"; + + HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", new StringContent(stringContent)); + return response; + } + + public async Task Authenticate(int number = 0) { + HttpResponseMessage response = await this.AuthenticateResponse(number); + + string responseContent = LbpSerializer.StringElement("loginResult", await response.Content.ReadAsStringAsync()); + + XmlSerializer serializer = new(typeof(LoginResult)); + return (LoginResult)serializer.Deserialize(new StringReader(responseContent))!; + } + + public Task AuthenticatedRequest(string endpoint, string mmAuth) => AuthenticatedRequest(endpoint, mmAuth, HttpMethod.Get); + + public Task AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method) { + using var requestMessage = new HttpRequestMessage(method, endpoint); + requestMessage.Headers.Add("Cookie", mmAuth); + + return this.Client.SendAsync(requestMessage); } } } \ No newline at end of file diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs index e06ee7b3..2cc09083 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs @@ -1,13 +1,15 @@ +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using ProjectLighthouse.Types; using Xunit; namespace ProjectLighthouse.Tests { public class AuthenticationTest : LighthouseTest { [Fact] public async Task ShouldReturnErrorOnNoPostData() { - var response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!); + HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!); Assert.False(response.IsSuccessStatusCode); #if NET6_0_OR_GREATER Assert.True(response.StatusCode == HttpStatusCode.BadRequest); @@ -17,12 +19,42 @@ namespace ProjectLighthouse.Tests { } [DatabaseFact] - public async Task ShouldAuthenticateWithValidData() { - const char nullChar = (char)0x00; - const char sepChar = (char)0x20; + public async Task ShouldReturnWithValidData() { + HttpResponseMessage response = await this.AuthenticateResponse(); + Assert.True(response.IsSuccessStatusCode); + string responseContent = await response.Content.ReadAsStringAsync(); + Assert.Contains("MM_AUTH=", responseContent); + Assert.Contains(ServerSettings.ServerName, responseContent); + } + + [DatabaseFact] + public async Task CanSerializeBack() { + LoginResult loginResult = await this.Authenticate(); - var response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", new StringContent($"{nullChar}{sepChar}jvyden{nullChar}")); - Assert.True(response.StatusCode == HttpStatusCode.OK); + Assert.NotNull(loginResult); + Assert.NotNull(loginResult.AuthTicket); + Assert.NotNull(loginResult.LbpEnvVer); + + Assert.Contains("MM_AUTH=", loginResult.AuthTicket); + Assert.Equal(ServerSettings.ServerName, loginResult.LbpEnvVer); + } + + [DatabaseFact] + public async Task CanUseToken() { + LoginResult loginResult = await this.Authenticate(); + + HttpResponseMessage response = await AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/eula", loginResult.AuthTicket); + string responseContent = await response.Content.ReadAsStringAsync(); + + Assert.True(response.IsSuccessStatusCode); + Assert.Contains("You are logged in", responseContent); + } + + [DatabaseFact] + public async Task ShouldReturnForbiddenWhenNotAuthenticated() { + HttpResponseMessage response = await this.Client.GetAsync("/LITTLEBIGPLANETPS3_XML/eula"); + Assert.False(response.IsSuccessStatusCode); + Assert.True(response.StatusCode == HttpStatusCode.Forbidden); } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/LoginResult.cs b/ProjectLighthouse/Types/LoginResult.cs index f9c20260..64bc5be0 100644 --- a/ProjectLighthouse/Types/LoginResult.cs +++ b/ProjectLighthouse/Types/LoginResult.cs @@ -1,12 +1,17 @@ using System.Collections.Generic; +using System.Xml.Serialization; using ProjectLighthouse.Serialization; namespace ProjectLighthouse.Types { /// /// Response to POST /login /// + [XmlRoot("loginResult"), XmlType("loginResult")] public class LoginResult { + [XmlElement("authTicket")] public string AuthTicket { get; set; } + + [XmlElement("lbpEnvVer")] public string LbpEnvVer { get; set; } public string Serialize() { From 0df715045dbe4db14119e874cb718c1dcf21d205 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 15 Oct 2021 00:44:08 -0400 Subject: [PATCH 4/7] Cleanup imports --- ProjectLighthouse.Tests/Tests/AuthenticationTest.cs | 1 - ProjectLighthouse/Controllers/LoginController.cs | 3 --- ProjectLighthouse/Controllers/MessageController.cs | 1 - ProjectLighthouse/Database.cs | 1 - ProjectLighthouse/Helpers/BinaryHelper.cs | 1 - 5 files changed, 7 deletions(-) diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs index 2cc09083..42a3ffca 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index dfb6a0fa..00c21c38 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -1,10 +1,7 @@ #nullable enable -using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Primitives; using ProjectLighthouse.Types; namespace ProjectLighthouse.Controllers { diff --git a/ProjectLighthouse/Controllers/MessageController.cs b/ProjectLighthouse/Controllers/MessageController.cs index c6a4089c..89e4b89a 100644 --- a/ProjectLighthouse/Controllers/MessageController.cs +++ b/ProjectLighthouse/Controllers/MessageController.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using ProjectLighthouse.Types; namespace ProjectLighthouse.Controllers { diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index dc33f549..298851aa 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -1,5 +1,4 @@ #nullable enable -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; diff --git a/ProjectLighthouse/Helpers/BinaryHelper.cs b/ProjectLighthouse/Helpers/BinaryHelper.cs index c62d14c8..6b66ff1c 100644 --- a/ProjectLighthouse/Helpers/BinaryHelper.cs +++ b/ProjectLighthouse/Helpers/BinaryHelper.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.IO; using System.Text; From 5e31bb8c3174e95b4410ad77f27347b0b90ab509 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 15 Oct 2021 00:54:21 -0400 Subject: [PATCH 5/7] Add SerializerTests --- ...ticationTest.cs => AuthenticationTests.cs} | 2 +- .../Tests/SerializerTests.cs | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) rename ProjectLighthouse.Tests/Tests/{AuthenticationTest.cs => AuthenticationTests.cs} (97%) create mode 100644 ProjectLighthouse.Tests/Tests/SerializerTests.cs diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs similarity index 97% rename from ProjectLighthouse.Tests/Tests/AuthenticationTest.cs rename to ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index 42a3ffca..e79bf903 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTest.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -5,7 +5,7 @@ using ProjectLighthouse.Types; using Xunit; namespace ProjectLighthouse.Tests { - public class AuthenticationTest : LighthouseTest { + public class AuthenticationTests : LighthouseTest { [Fact] public async Task ShouldReturnErrorOnNoPostData() { HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!); diff --git a/ProjectLighthouse.Tests/Tests/SerializerTests.cs b/ProjectLighthouse.Tests/Tests/SerializerTests.cs new file mode 100644 index 00000000..1f89c2f1 --- /dev/null +++ b/ProjectLighthouse.Tests/Tests/SerializerTests.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using ProjectLighthouse.Serialization; +using Xunit; + +namespace ProjectLighthouse.Tests { + public class SerializerTests : LighthouseTest { + [Fact] + public void BlankElementWorks() { + Assert.Equal("", LbpSerializer.BlankElement("test")); + } + + [Fact] + public void StringElementWorks() { + Assert.Equal("asd", LbpSerializer.StringElement("test", "asd")); + Assert.Equal("asd", LbpSerializer.StringElement(new KeyValuePair("test", "asd"))); + } + + [Fact] + public void TaggedStringElementWorks() { + Assert.Equal("asd", LbpSerializer.TaggedStringElement("test", "asd", "foo", "bar")); + Assert.Equal("asd", LbpSerializer.TaggedStringElement(new KeyValuePair("test", "asd"), + new KeyValuePair("foo", "bar"))); + } + + [Fact] + public void ElementsWorks() { + Assert.Equal("asdbar", LbpSerializer.Elements(new KeyValuePair("test", "asd"), + new KeyValuePair("foo", "bar"))); + } + } +} \ No newline at end of file From b366a41f9071ead0abb039cfab531529ed303d08 Mon Sep 17 00:00:00 2001 From: jvyden Date: Sat, 16 Oct 2021 18:14:17 -0400 Subject: [PATCH 6/7] Update default biography text to match LBP's default --- ProjectLighthouse/Database.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index dc33f549..ce078a7e 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -27,7 +27,7 @@ namespace ProjectLighthouse { User user = new() { Username = username, LocationId = l.Id, - Biography = "No biography provided", + Biography = username + " hasn't introduced themselves yet.", Pins = "", PlanetHash = "", }; From d8e34bcf8cb60ef6f4bd72611071de2364c1ba8f Mon Sep 17 00:00:00 2001 From: jvyden Date: Sat, 16 Oct 2021 19:10:55 -0400 Subject: [PATCH 7/7] Switch to ForeignKeys and dependency injection for EF --- .../Controllers/CommentController.cs | 13 ++++++--- .../Controllers/LoginController.cs | 8 ++++-- .../Controllers/MessageController.cs | 7 ++++- .../Controllers/PublishController.cs | 10 ++++--- .../Controllers/SlotsController.cs | 22 ++++++++++++--- .../Controllers/UserController.cs | 12 ++++++--- ProjectLighthouse/Database.cs | 8 +++--- ProjectLighthouse/Program.cs | 16 ++++++----- ProjectLighthouse/ProjectLighthouse.csproj | 3 ++- ProjectLighthouse/Startup.cs | 5 +++- ProjectLighthouse/Types/Comment.cs | 27 +++++-------------- ProjectLighthouse/Types/Slot.cs | 23 ++++------------ ProjectLighthouse/Types/User.cs | 12 +++------ 13 files changed, 90 insertions(+), 76 deletions(-) diff --git a/ProjectLighthouse/Controllers/CommentController.cs b/ProjectLighthouse/Controllers/CommentController.cs index 2bcb35d3..1b251917 100644 --- a/ProjectLighthouse/Controllers/CommentController.cs +++ b/ProjectLighthouse/Controllers/CommentController.cs @@ -13,11 +13,17 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] public class CommentController : ControllerBase { + private readonly Database database; + public CommentController(Database database) { + this.database = database; + } + [HttpGet("userComments/{username}")] public async Task GetComments(string username) { - // the following is downright retarded, but its 12:48am and i do not give a shit - // ↓ ok... ↓ why does this need to be wrapped ↓ again???? whyyyy - List comments = (await new Database().Comments.ToListAsync()).Where(c => c.TargetUsername == username).ToList(); + List comments = await database.Comments + .Include(c => c.Target) + .Where(c => c.Target.Username == username) + .ToListAsync(); string outputXml = comments.Aggregate(string.Empty, (current, comment) => current + comment.Serialize()); return this.Ok(LbpSerializer.StringElement("comments", outputXml)); @@ -31,7 +37,6 @@ namespace ProjectLighthouse.Controllers { XmlSerializer serializer = new(typeof(Comment)); Comment comment = (Comment)serializer.Deserialize(new StringReader(bodyString)); - await using Database database = new(); User poster = await database.UserFromRequest(Request); if(poster == null) return this.StatusCode(403, ""); diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index 5b137aa4..5f0dd357 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -12,6 +12,12 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/login")] [Produces("text/xml")] public class LoginController : ControllerBase { + private readonly Database database; + + public LoginController(Database database) { + this.database = database; + } + [HttpPost] public async Task Login() { if(!this.Request.Query.TryGetValue("titleID", out StringValues _)) @@ -27,8 +33,6 @@ namespace ProjectLighthouse.Controllers { return this.BadRequest(); } - await using Database database = new(); - Token? token = await database.AuthenticateUser(loginData); if(token == null) return this.StatusCode(403, ""); diff --git a/ProjectLighthouse/Controllers/MessageController.cs b/ProjectLighthouse/Controllers/MessageController.cs index c6a4089c..1a6ac5c7 100644 --- a/ProjectLighthouse/Controllers/MessageController.cs +++ b/ProjectLighthouse/Controllers/MessageController.cs @@ -8,9 +8,14 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] public class MessageController : ControllerBase { + private readonly Database database; + public MessageController(Database database) { + this.database = database; + } + [HttpGet("eula")] public async Task Eula() { - User user = await new Database().UserFromRequest(Request); + User user = await this.database.UserFromRequest(Request); return user == null ? this.StatusCode(403, "") : this.Ok($"You are logged in as user {user.Username} (id {user.UserId})"); } diff --git a/ProjectLighthouse/Controllers/PublishController.cs b/ProjectLighthouse/Controllers/PublishController.cs index 77d92c21..dd1fae0b 100644 --- a/ProjectLighthouse/Controllers/PublishController.cs +++ b/ProjectLighthouse/Controllers/PublishController.cs @@ -11,6 +11,12 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] public class PublishController : ControllerBase { + private readonly Database database; + + public PublishController(Database database) { + this.database = database; + } + /// /// Endpoint the game uses to verify that the level is compatible (?) /// @@ -27,8 +33,6 @@ namespace ProjectLighthouse.Controllers { /// [HttpPost("publish")] public async Task Publish() { - await using Database database = new(); - User user = await database.UserFromRequest(Request); if(user == null) return this.StatusCode(403, ""); @@ -52,8 +56,6 @@ namespace ProjectLighthouse.Controllers { [HttpPost("unpublish/{id:int}")] public async Task Unpublish(int id) { - await using Database database = new(); - Slot slot = await database.Slots.FirstOrDefaultAsync(s => s.SlotId == id); database.Locations.Remove(slot.Location); diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index ba095e09..3f2735d9 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -10,23 +10,39 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] public class SlotsController : ControllerBase { + private readonly Database database; + public SlotsController(Database database) { + this.database = database; + } + [HttpGet("slots/by")] public IActionResult SlotsBy() { - string response = Enumerable.Aggregate(new Database().Slots, string.Empty, (current, slot) => current + slot.Serialize()); + string response = Enumerable.Aggregate( + database.Slots + .Include(s => s.Creator) + .Include(s => s.Location) + , string.Empty, (current, slot) => current + slot.Serialize()); return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", 1)); } [HttpGet("s/user/{id:int}")] public async Task SUser(int id) { - Slot slot = await new Database().Slots.FirstOrDefaultAsync(s => s.SlotId == id); + Slot slot = await this.database.Slots + .Include(s => s.Creator) + .Include(s => s.Location) + .FirstOrDefaultAsync(s => s.SlotId == id); return this.Ok(slot.Serialize()); } [HttpGet("slots/lolcatftw/{username}")] public IActionResult SlotsLolCat(string username) { - string response = Enumerable.Aggregate(new Database().Slots, string.Empty, (current, slot) => current + slot.Serialize()); + string response = Enumerable.Aggregate( + database.Slots + .Include(s => s.Creator) + .Include(s => s.Location) + , string.Empty, (current, slot) => current + slot.Serialize()); return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", 1)); } diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index 244cec20..baebd029 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -12,11 +12,16 @@ namespace ProjectLighthouse.Controllers { [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] public class UserController : ControllerBase { + private readonly Database database; + public UserController(Database database) { + this.database = database; + } + [HttpGet("user/{username}")] public async Task GetUser(string username) { - await using Database database = new(); - - User user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); + User user = await database.Users + .Include(u => u.Location) + .FirstOrDefaultAsync(u => u.Username == username); if(user == null) return this.NotFound(); return this.Ok(user.Serialize()); @@ -30,7 +35,6 @@ namespace ProjectLighthouse.Controllers { [HttpPost("updateUser")] public async Task UpdateUser() { - await using Database database = new(); User user = await database.UserFromRequest(Request); if(user == null) return this.StatusCode(403, ""); diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index ce078a7e..4e702974 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -13,12 +13,12 @@ namespace ProjectLighthouse { public DbSet Slots { get; set; } public DbSet Comments { get; set; } public DbSet Tokens { get; set; } - + protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql( ServerSettings.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion ); - + public async Task CreateUser(string username) { Location l = new(); // store to get id after submitting this.Locations.Add(l); // add to table @@ -60,7 +60,9 @@ namespace ProjectLighthouse { public async Task UserFromAuthToken(string authToken) { Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken); if(token == null) return null; - return await Users.FirstOrDefaultAsync(u => u.UserId == token.UserId); + return await Users + .Include(u => u.Location) + .FirstOrDefaultAsync(u => u.UserId == token.UserId); } public async Task UserFromRequest(HttpRequest request) { diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index d79c24ac..3e74c1f7 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -1,5 +1,7 @@ using System; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using ProjectLighthouse.Types; @@ -9,13 +11,13 @@ namespace ProjectLighthouse { Console.WriteLine("Welcome to Project Lighthouse!"); Console.WriteLine(ServerSettings.DbConnected ? "Connected to the database." : "Database unavailable. Starting in stateless mode."); - CreateHostBuilder(args).Build().Run(); - } + IHostBuilder builder = Host.CreateDefaultBuilder(args); + + builder.ConfigureWebHostDefaults(webBuilder => { + webBuilder.UseStartup(); + }); - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { - webBuilder.UseStartup(); - }); + builder.Build().Run(); + } } } \ No newline at end of file diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 64633e26..18ab9cbb 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -7,7 +7,8 @@ - + + diff --git a/ProjectLighthouse/Startup.cs b/ProjectLighthouse/Startup.cs index 173c5caf..b9e9b518 100644 --- a/ProjectLighthouse/Startup.cs +++ b/ProjectLighthouse/Startup.cs @@ -3,10 +3,12 @@ using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using ProjectLighthouse.Serialization; +using ProjectLighthouse.Types; namespace ProjectLighthouse { public class Startup { @@ -18,10 +20,11 @@ namespace ProjectLighthouse { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); services.AddMvc(options => options.OutputFormatters.Add(new XmlOutputFormatter())); + + services.AddDbContext(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/ProjectLighthouse/Types/Comment.cs b/ProjectLighthouse/Types/Comment.cs index 1faf6dda..d3abdec0 100644 --- a/ProjectLighthouse/Types/Comment.cs +++ b/ProjectLighthouse/Types/Comment.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Xml.Serialization; using ProjectLighthouse.Serialization; @@ -14,25 +15,11 @@ namespace ProjectLighthouse.Types { public int TargetUserId { get; set; } - private string posterUsername; - -// [XmlAttribute("username")] - public string PosterUsername { - get { - if(this.posterUsername != null) return this.posterUsername; - return this.posterUsername = new Database().Users.First(u => u.UserId == PosterUserId).Username; - } - } - - private string targetUsername; - - public string TargetUsername { - get { - if(this.targetUsername != null) return this.targetUsername; - - return this.targetUsername = new Database().Users.First(u => u.UserId == TargetUserId).Username; - } - } + [ForeignKey(nameof(PosterUserId))] + public User Poster { get; set; } + + [ForeignKey(nameof(TargetUserId))] + public User Target { get; set; } public long Timestamp { get; set; } @@ -43,7 +30,7 @@ namespace ProjectLighthouse.Types { private string serialize() { return LbpSerializer.StringElement("id", CommentId) + - LbpSerializer.StringElement("npHandle", this.PosterUsername) + + LbpSerializer.StringElement("npHandle", this.Poster.Username) + LbpSerializer.StringElement("timestamp", Timestamp) + LbpSerializer.StringElement("message", Message) + LbpSerializer.StringElement("thumbsup", ThumbsUp) + diff --git a/ProjectLighthouse/Types/Slot.cs b/ProjectLighthouse/Types/Slot.cs index 4d061dab..eb090eab 100644 --- a/ProjectLighthouse/Types/Slot.cs +++ b/ProjectLighthouse/Types/Slot.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Xml.Serialization; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using ProjectLighthouse.Serialization; namespace ProjectLighthouse.Types { @@ -39,30 +40,16 @@ namespace ProjectLighthouse.Types { [XmlIgnore] public int CreatorId { get; set; } - - private User creator; - public User Creator { - get { - if(this.creator != null) return this.creator; - - return creator = new Database().Users.First(u => u.UserId == CreatorId); - } - } - - private Location location; + [ForeignKey(nameof(CreatorId))] + public User Creator { get; set; } /// /// The location of the level on the creator's earth /// [XmlElement("location")] - public Location Location { - get { - if(location != null) return this.location; - - return location = new Database().Locations.First(l => l.Id == LocationId); - } - } + [ForeignKey(nameof(LocationId))] + public Location Location { get; set; } [XmlElement("initiallyLocked")] public bool InitiallyLocked { get; set; } diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index fdd5b037..0badffc0 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using ProjectLighthouse.Serialization; @@ -23,17 +24,12 @@ namespace ProjectLighthouse.Types { public bool CommentsEnabled { get; set; } public int LocationId { get; set; } - - private Location location; + /// /// The location of the profile card on the user's earth /// - public Location Location { - get { - if(location != null) return this.location; - return location = new Database().Locations.First(l => l.Id == LocationId); - } - } + [ForeignKey("LocationId")] + public Location Location { get; set; } public int FavouriteSlotCount { get; set; } public int FavouriteUserCount { get; set; }