Switch to ForeignKeys and dependency injection for EF

This commit is contained in:
jvyden 2021-10-16 19:10:55 -04:00
parent b366a41f90
commit d8e34bcf8c
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
13 changed files with 90 additions and 76 deletions

View file

@ -13,11 +13,17 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/")] [Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")] [Produces("text/xml")]
public class CommentController : ControllerBase { public class CommentController : ControllerBase {
private readonly Database database;
public CommentController(Database database) {
this.database = database;
}
[HttpGet("userComments/{username}")] [HttpGet("userComments/{username}")]
public async Task<IActionResult> GetComments(string username) { public async Task<IActionResult> GetComments(string username) {
// the following is downright retarded, but its 12:48am and i do not give a shit List<Comment> comments = await database.Comments
// ↓ ok... ↓ why does this need to be wrapped ↓ again???? whyyyy .Include(c => c.Target)
List<Comment> comments = (await new Database().Comments.ToListAsync()).Where(c => c.TargetUsername == username).ToList(); .Where(c => c.Target.Username == username)
.ToListAsync();
string outputXml = comments.Aggregate(string.Empty, (current, comment) => current + comment.Serialize()); string outputXml = comments.Aggregate(string.Empty, (current, comment) => current + comment.Serialize());
return this.Ok(LbpSerializer.StringElement("comments", outputXml)); return this.Ok(LbpSerializer.StringElement("comments", outputXml));
@ -31,7 +37,6 @@ namespace ProjectLighthouse.Controllers {
XmlSerializer serializer = new(typeof(Comment)); XmlSerializer serializer = new(typeof(Comment));
Comment comment = (Comment)serializer.Deserialize(new StringReader(bodyString)); Comment comment = (Comment)serializer.Deserialize(new StringReader(bodyString));
await using Database database = new();
User poster = await database.UserFromRequest(Request); User poster = await database.UserFromRequest(Request);
if(poster == null) return this.StatusCode(403, ""); if(poster == null) return this.StatusCode(403, "");

View file

@ -12,6 +12,12 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/login")] [Route("LITTLEBIGPLANETPS3_XML/login")]
[Produces("text/xml")] [Produces("text/xml")]
public class LoginController : ControllerBase { public class LoginController : ControllerBase {
private readonly Database database;
public LoginController(Database database) {
this.database = database;
}
[HttpPost] [HttpPost]
public async Task<IActionResult> Login() { public async Task<IActionResult> Login() {
if(!this.Request.Query.TryGetValue("titleID", out StringValues _)) if(!this.Request.Query.TryGetValue("titleID", out StringValues _))
@ -27,8 +33,6 @@ namespace ProjectLighthouse.Controllers {
return this.BadRequest(); return this.BadRequest();
} }
await using Database database = new();
Token? token = await database.AuthenticateUser(loginData); Token? token = await database.AuthenticateUser(loginData);
if(token == null) return this.StatusCode(403, ""); if(token == null) return this.StatusCode(403, "");

View file

@ -8,9 +8,14 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/")] [Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/plain")] [Produces("text/plain")]
public class MessageController : ControllerBase { public class MessageController : ControllerBase {
private readonly Database database;
public MessageController(Database database) {
this.database = database;
}
[HttpGet("eula")] [HttpGet("eula")]
public async Task<IActionResult> Eula() { public async Task<IActionResult> 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})"); return user == null ? this.StatusCode(403, "") : this.Ok($"You are logged in as user {user.Username} (id {user.UserId})");
} }

View file

@ -11,6 +11,12 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/")] [Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")] [Produces("text/xml")]
public class PublishController : ControllerBase { public class PublishController : ControllerBase {
private readonly Database database;
public PublishController(Database database) {
this.database = database;
}
/// <summary> /// <summary>
/// Endpoint the game uses to verify that the level is compatible (?) /// Endpoint the game uses to verify that the level is compatible (?)
/// </summary> /// </summary>
@ -27,8 +33,6 @@ namespace ProjectLighthouse.Controllers {
/// </summary> /// </summary>
[HttpPost("publish")] [HttpPost("publish")]
public async Task<IActionResult> Publish() { public async Task<IActionResult> Publish() {
await using Database database = new();
User user = await database.UserFromRequest(Request); User user = await database.UserFromRequest(Request);
if(user == null) return this.StatusCode(403, ""); if(user == null) return this.StatusCode(403, "");
@ -52,8 +56,6 @@ namespace ProjectLighthouse.Controllers {
[HttpPost("unpublish/{id:int}")] [HttpPost("unpublish/{id:int}")]
public async Task<IActionResult> Unpublish(int id) { public async Task<IActionResult> Unpublish(int id) {
await using Database database = new();
Slot slot = await database.Slots.FirstOrDefaultAsync(s => s.SlotId == id); Slot slot = await database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
database.Locations.Remove(slot.Location); database.Locations.Remove(slot.Location);

View file

@ -10,23 +10,39 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/")] [Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")] [Produces("text/xml")]
public class SlotsController : ControllerBase { public class SlotsController : ControllerBase {
private readonly Database database;
public SlotsController(Database database) {
this.database = database;
}
[HttpGet("slots/by")] [HttpGet("slots/by")]
public IActionResult SlotsBy() { 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)); return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", 1));
} }
[HttpGet("s/user/{id:int}")] [HttpGet("s/user/{id:int}")]
public async Task<IActionResult> SUser(int id) { public async Task<IActionResult> 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()); return this.Ok(slot.Serialize());
} }
[HttpGet("slots/lolcatftw/{username}")] [HttpGet("slots/lolcatftw/{username}")]
public IActionResult SlotsLolCat(string 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)); return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", 1));
} }

View file

@ -12,11 +12,16 @@ namespace ProjectLighthouse.Controllers {
[Route("LITTLEBIGPLANETPS3_XML/")] [Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")] [Produces("text/xml")]
public class UserController : ControllerBase { public class UserController : ControllerBase {
private readonly Database database;
public UserController(Database database) {
this.database = database;
}
[HttpGet("user/{username}")] [HttpGet("user/{username}")]
public async Task<IActionResult> GetUser(string username) { public async Task<IActionResult> GetUser(string username) {
await using Database database = new(); User user = await database.Users
.Include(u => u.Location)
User user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); .FirstOrDefaultAsync(u => u.Username == username);
if(user == null) return this.NotFound(); if(user == null) return this.NotFound();
return this.Ok(user.Serialize()); return this.Ok(user.Serialize());
@ -30,7 +35,6 @@ namespace ProjectLighthouse.Controllers {
[HttpPost("updateUser")] [HttpPost("updateUser")]
public async Task<IActionResult> UpdateUser() { public async Task<IActionResult> UpdateUser() {
await using Database database = new();
User user = await database.UserFromRequest(Request); User user = await database.UserFromRequest(Request);
if(user == null) return this.StatusCode(403, ""); if(user == null) return this.StatusCode(403, "");

View file

@ -13,12 +13,12 @@ namespace ProjectLighthouse {
public DbSet<Slot> Slots { get; set; } public DbSet<Slot> Slots { get; set; }
public DbSet<Comment> Comments { get; set; } public DbSet<Comment> Comments { get; set; }
public DbSet<Token> Tokens { get; set; } public DbSet<Token> Tokens { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql( protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(
ServerSettings.DbConnectionString, ServerSettings.DbConnectionString,
MySqlServerVersion.LatestSupportedServerVersion MySqlServerVersion.LatestSupportedServerVersion
); );
public async Task<User> CreateUser(string username) { public async Task<User> CreateUser(string username) {
Location l = new(); // store to get id after submitting Location l = new(); // store to get id after submitting
this.Locations.Add(l); // add to table this.Locations.Add(l); // add to table
@ -60,7 +60,9 @@ namespace ProjectLighthouse {
public async Task<User?> UserFromAuthToken(string authToken) { public async Task<User?> UserFromAuthToken(string authToken) {
Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken); Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
if(token == null) return null; 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<User?> UserFromRequest(HttpRequest request) { public async Task<User?> UserFromRequest(HttpRequest request) {

View file

@ -1,5 +1,7 @@
using System; using System;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using ProjectLighthouse.Types; using ProjectLighthouse.Types;
@ -9,13 +11,13 @@ namespace ProjectLighthouse {
Console.WriteLine("Welcome to Project Lighthouse!"); Console.WriteLine("Welcome to Project Lighthouse!");
Console.WriteLine(ServerSettings.DbConnected ? "Connected to the database." : "Database unavailable. Starting in stateless mode."); 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<Startup>();
});
public static IHostBuilder CreateHostBuilder(string[] args) => builder.Build().Run();
Host.CreateDefaultBuilder(args) }
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
} }
} }

View file

@ -7,7 +7,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" /> <PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup> </ItemGroup>

View file

@ -3,10 +3,12 @@ using System.IO;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using ProjectLighthouse.Serialization; using ProjectLighthouse.Serialization;
using ProjectLighthouse.Types;
namespace ProjectLighthouse { namespace ProjectLighthouse {
public class Startup { 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. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) { public void ConfigureServices(IServiceCollection services) {
services.AddControllers(); services.AddControllers();
services.AddMvc(options => services.AddMvc(options =>
options.OutputFormatters.Add(new XmlOutputFormatter())); options.OutputFormatters.Add(new XmlOutputFormatter()));
services.AddDbContext<Database>();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq; using System.Linq;
using System.Xml.Serialization; using System.Xml.Serialization;
using ProjectLighthouse.Serialization; using ProjectLighthouse.Serialization;
@ -14,25 +15,11 @@ namespace ProjectLighthouse.Types {
public int TargetUserId { get; set; } public int TargetUserId { get; set; }
private string posterUsername; [ForeignKey(nameof(PosterUserId))]
public User Poster { get; set; }
// [XmlAttribute("username")]
public string PosterUsername { [ForeignKey(nameof(TargetUserId))]
get { public User Target { get; set; }
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;
}
}
public long Timestamp { get; set; } public long Timestamp { get; set; }
@ -43,7 +30,7 @@ namespace ProjectLighthouse.Types {
private string serialize() { private string serialize() {
return LbpSerializer.StringElement("id", CommentId) + return LbpSerializer.StringElement("id", CommentId) +
LbpSerializer.StringElement("npHandle", this.PosterUsername) + LbpSerializer.StringElement("npHandle", this.Poster.Username) +
LbpSerializer.StringElement("timestamp", Timestamp) + LbpSerializer.StringElement("timestamp", Timestamp) +
LbpSerializer.StringElement("message", Message) + LbpSerializer.StringElement("message", Message) +
LbpSerializer.StringElement("thumbsup", ThumbsUp) + LbpSerializer.StringElement("thumbsup", ThumbsUp) +

View file

@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Linq; using System.Linq;
using System.Xml.Serialization; using System.Xml.Serialization;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using ProjectLighthouse.Serialization; using ProjectLighthouse.Serialization;
namespace ProjectLighthouse.Types { namespace ProjectLighthouse.Types {
@ -39,30 +40,16 @@ namespace ProjectLighthouse.Types {
[XmlIgnore] [XmlIgnore]
public int CreatorId { get; set; } public int CreatorId { get; set; }
private User creator;
public User Creator { [ForeignKey(nameof(CreatorId))]
get { public User Creator { get; set; }
if(this.creator != null) return this.creator;
return creator = new Database().Users.First(u => u.UserId == CreatorId);
}
}
private Location location;
/// <summary> /// <summary>
/// The location of the level on the creator's earth /// The location of the level on the creator's earth
/// </summary> /// </summary>
[XmlElement("location")] [XmlElement("location")]
public Location Location { [ForeignKey(nameof(LocationId))]
get { public Location Location { get; set; }
if(location != null) return this.location;
return location = new Database().Locations.First(l => l.Id == LocationId);
}
}
[XmlElement("initiallyLocked")] [XmlElement("initiallyLocked")]
public bool InitiallyLocked { get; set; } public bool InitiallyLocked { get; set; }

View file

@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq; using System.Linq;
using ProjectLighthouse.Serialization; using ProjectLighthouse.Serialization;
@ -23,17 +24,12 @@ namespace ProjectLighthouse.Types {
public bool CommentsEnabled { get; set; } public bool CommentsEnabled { get; set; }
public int LocationId { get; set; } public int LocationId { get; set; }
private Location location;
/// <summary> /// <summary>
/// The location of the profile card on the user's earth /// The location of the profile card on the user's earth
/// </summary> /// </summary>
public Location Location { [ForeignKey("LocationId")]
get { public Location Location { get; set; }
if(location != null) return this.location;
return location = new Database().Locations.First(l => l.Id == LocationId);
}
}
public int FavouriteSlotCount { get; set; } public int FavouriteSlotCount { get; set; }
public int FavouriteUserCount { get; set; } public int FavouriteUserCount { get; set; }