mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-06-10 10:01:26 +00:00
296 lines
No EOL
11 KiB
C#
296 lines
No EOL
11 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Kettu;
|
|
using LBPUnion.ProjectLighthouse.Helpers;
|
|
using LBPUnion.ProjectLighthouse.Logging;
|
|
using LBPUnion.ProjectLighthouse.Types;
|
|
using LBPUnion.ProjectLighthouse.Types.Categories;
|
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
|
using LBPUnion.ProjectLighthouse.Types.Reviews;
|
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace LBPUnion.ProjectLighthouse;
|
|
|
|
public class Database : DbContext
|
|
{
|
|
public DbSet<User> Users { get; set; }
|
|
public DbSet<Location> Locations { get; set; }
|
|
public DbSet<Slot> Slots { get; set; }
|
|
public DbSet<QueuedLevel> QueuedLevels { get; set; }
|
|
public DbSet<HeartedLevel> HeartedLevels { get; set; }
|
|
public DbSet<HeartedProfile> HeartedProfiles { get; set; }
|
|
public DbSet<Comment> Comments { get; set; }
|
|
public DbSet<GameToken> GameTokens { get; set; }
|
|
public DbSet<WebToken> WebTokens { get; set; }
|
|
public DbSet<Score> Scores { get; set; }
|
|
public DbSet<PhotoSubject> PhotoSubjects { get; set; }
|
|
public DbSet<Photo> Photos { get; set; }
|
|
public DbSet<LastContact> LastContacts { get; set; }
|
|
public DbSet<VisitedLevel> VisitedLevels { get; set; }
|
|
public DbSet<RatedLevel> RatedLevels { get; set; }
|
|
public DbSet<AuthenticationAttempt> AuthenticationAttempts { get; set; }
|
|
public DbSet<Review> Reviews { get; set; }
|
|
public DbSet<RatedReview> RatedReviews { get; set; }
|
|
public DbSet<UserApprovedIpAddress> UserApprovedIpAddresses { get; set; }
|
|
public DbSet<DatabaseCategory> CustomCategories { get; set; }
|
|
|
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
|
=> options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
|
|
|
public async Task<User> CreateUser(string username, string password)
|
|
{
|
|
if (!password.StartsWith("$")) throw new ArgumentException(nameof(password) + " is not a BCrypt hash");
|
|
|
|
User user;
|
|
if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null) return user;
|
|
|
|
Location l = new(); // store to get id after submitting
|
|
this.Locations.Add(l); // add to table
|
|
await this.SaveChangesAsync(); // saving to the database returns the id and sets it on this entity
|
|
|
|
user = new User
|
|
{
|
|
Username = username,
|
|
Password = password,
|
|
LocationId = l.Id,
|
|
Biography = username + " hasn't introduced themselves yet.",
|
|
};
|
|
this.Users.Add(user);
|
|
|
|
await this.SaveChangesAsync();
|
|
|
|
return user;
|
|
}
|
|
|
|
#nullable enable
|
|
public async Task<GameToken?> AuthenticateUser(LoginData loginData, string userLocation, string titleId = "")
|
|
{
|
|
User? user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username);
|
|
if (user == null) return null;
|
|
|
|
GameToken gameToken = new()
|
|
{
|
|
UserToken = HashHelper.GenerateAuthToken(),
|
|
User = user,
|
|
UserId = user.UserId,
|
|
UserLocation = userLocation,
|
|
GameVersion = GameVersionHelper.FromTitleId(titleId),
|
|
};
|
|
|
|
if (gameToken.GameVersion == GameVersion.Unknown)
|
|
{
|
|
Logger.Log($"Unknown GameVersion for TitleId {titleId}", LoggerLevelLogin.Instance);
|
|
return null;
|
|
}
|
|
|
|
this.GameTokens.Add(gameToken);
|
|
await this.SaveChangesAsync();
|
|
|
|
return gameToken;
|
|
}
|
|
|
|
#region Hearts & Queues
|
|
|
|
public async Task HeartUser(User user, User heartedUser)
|
|
{
|
|
HeartedProfile? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
|
if (heartedProfile != null) return;
|
|
|
|
this.HeartedProfiles.Add
|
|
(
|
|
new HeartedProfile
|
|
{
|
|
HeartedUserId = heartedUser.UserId,
|
|
UserId = user.UserId,
|
|
}
|
|
);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnheartUser(User user, User heartedUser)
|
|
{
|
|
HeartedProfile? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
|
if (heartedProfile != null) this.HeartedProfiles.Remove(heartedProfile);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task HeartLevel(User user, Slot heartedSlot)
|
|
{
|
|
HeartedLevel? heartedLevel = await this.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == heartedSlot.SlotId);
|
|
if (heartedLevel != null) return;
|
|
|
|
this.HeartedLevels.Add
|
|
(
|
|
new HeartedLevel
|
|
{
|
|
SlotId = heartedSlot.SlotId,
|
|
UserId = user.UserId,
|
|
}
|
|
);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnheartLevel(User user, Slot heartedSlot)
|
|
{
|
|
HeartedLevel? heartedLevel = await this.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == heartedSlot.SlotId);
|
|
if (heartedLevel != null) this.HeartedLevels.Remove(heartedLevel);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task QueueLevel(User user, Slot queuedSlot)
|
|
{
|
|
QueuedLevel? queuedLevel = await this.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == queuedSlot.SlotId);
|
|
if (queuedLevel != null) return;
|
|
|
|
this.QueuedLevels.Add
|
|
(
|
|
new QueuedLevel
|
|
{
|
|
SlotId = queuedSlot.SlotId,
|
|
UserId = user.UserId,
|
|
}
|
|
);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnqueueLevel(User user, Slot queuedSlot)
|
|
{
|
|
QueuedLevel? queuedLevel = await this.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == queuedSlot.SlotId);
|
|
if (queuedLevel != null) this.QueuedLevels.Remove(queuedLevel);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Game Token Shenanigans
|
|
|
|
public async Task<User?> UserFromMMAuth(string authToken, bool allowUnapproved = false)
|
|
{
|
|
if (ServerStatics.IsUnitTesting) allowUnapproved = true;
|
|
GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
|
|
|
|
if (token == null) return null;
|
|
if (!allowUnapproved && !token.Approved) return null;
|
|
|
|
return await this.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
|
}
|
|
|
|
public async Task<User?> UserFromGameToken
|
|
(GameToken gameToken, bool allowUnapproved = false)
|
|
=> await this.UserFromMMAuth(gameToken.UserToken, allowUnapproved);
|
|
|
|
public async Task<User?> UserFromGameRequest(HttpRequest request, bool allowUnapproved = false)
|
|
{
|
|
if (ServerStatics.IsUnitTesting) allowUnapproved = true;
|
|
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null;
|
|
|
|
return await this.UserFromMMAuth(mmAuth, allowUnapproved);
|
|
}
|
|
|
|
public async Task<GameToken?> GameTokenFromRequest(HttpRequest request, bool allowUnapproved = false)
|
|
{
|
|
if (ServerStatics.IsUnitTesting) allowUnapproved = true;
|
|
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null;
|
|
|
|
GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth);
|
|
|
|
if (token == null) return null;
|
|
if (!allowUnapproved && !token.Approved) return null;
|
|
|
|
return token;
|
|
}
|
|
|
|
public async Task<(User, GameToken)?> UserAndGameTokenFromRequest(HttpRequest request, bool allowUnapproved = false)
|
|
{
|
|
if (ServerStatics.IsUnitTesting) allowUnapproved = true;
|
|
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null;
|
|
|
|
GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth);
|
|
if (token == null) return null;
|
|
if (!allowUnapproved && !token.Approved) return null;
|
|
|
|
User? user = await this.UserFromGameToken(token);
|
|
|
|
if (user == null) return null;
|
|
|
|
return (user, token);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Web Token Shenanigans
|
|
|
|
public User? UserFromLighthouseToken(string lighthouseToken)
|
|
{
|
|
WebToken? token = this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken);
|
|
if (token == null) return null;
|
|
|
|
return this.Users.Include(u => u.Location).FirstOrDefault(u => u.UserId == token.UserId);
|
|
}
|
|
|
|
public User? UserFromWebRequest(HttpRequest request)
|
|
{
|
|
if (!request.Cookies.TryGetValue("LighthouseToken", out string? lighthouseToken) || lighthouseToken == null) return null;
|
|
|
|
return this.UserFromLighthouseToken(lighthouseToken);
|
|
}
|
|
|
|
public WebToken? WebTokenFromRequest(HttpRequest request)
|
|
{
|
|
if (!request.Cookies.TryGetValue("LighthouseToken", out string? lighthouseToken) || lighthouseToken == null) return null;
|
|
|
|
return this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken);
|
|
}
|
|
|
|
#endregion
|
|
|
|
public async Task<Photo?> PhotoFromSubject(PhotoSubject subject)
|
|
=> await this.Photos.FirstOrDefaultAsync(p => p.PhotoSubjectIds.Contains(subject.PhotoSubjectId.ToString()));
|
|
public async Task RemoveUser(User? user)
|
|
{
|
|
if (user == null) return;
|
|
|
|
if (user.Location != null) this.Locations.Remove(user.Location);
|
|
LastContact? lastContact = await this.LastContacts.FirstOrDefaultAsync(l => l.UserId == user.UserId);
|
|
if (lastContact != null) this.LastContacts.Remove(lastContact);
|
|
|
|
foreach (Slot slot in this.Slots.Where(s => s.CreatorId == user.UserId)) await this.RemoveSlot(slot, false);
|
|
|
|
this.AuthenticationAttempts.RemoveRange(this.AuthenticationAttempts.Include(a => a.GameToken).Where(a => a.GameToken.UserId == user.UserId));
|
|
this.HeartedProfiles.RemoveRange(this.HeartedProfiles.Where(h => h.UserId == user.UserId));
|
|
this.PhotoSubjects.RemoveRange(this.PhotoSubjects.Where(s => s.UserId == user.UserId));
|
|
this.HeartedLevels.RemoveRange(this.HeartedLevels.Where(h => h.UserId == user.UserId));
|
|
this.VisitedLevels.RemoveRange(this.VisitedLevels.Where(v => v.UserId == user.UserId));
|
|
this.RatedReviews.RemoveRange(this.RatedReviews.Where(r => r.UserId == user.UserId));
|
|
this.QueuedLevels.RemoveRange(this.QueuedLevels.Where(q => q.UserId == user.UserId));
|
|
this.RatedLevels.RemoveRange(this.RatedLevels.Where(r => r.UserId == user.UserId));
|
|
this.GameTokens.RemoveRange(this.GameTokens.Where(t => t.UserId == user.UserId));
|
|
this.WebTokens.RemoveRange(this.WebTokens.Where(t => t.UserId == user.UserId));
|
|
this.Comments.RemoveRange(this.Comments.Where(c => c.PosterUserId == user.UserId));
|
|
this.Reviews.RemoveRange(this.Reviews.Where(r => r.ReviewerId == user.UserId));
|
|
this.Photos.RemoveRange(this.Photos.Where(p => p.CreatorId == user.UserId));
|
|
|
|
this.Users.Remove(user);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task RemoveSlot(Slot slot, bool saveChanges = true)
|
|
{
|
|
if (slot.Location != null) this.Locations.Remove(slot.Location);
|
|
this.Slots.Remove(slot);
|
|
|
|
if (saveChanges) await this.SaveChangesAsync();
|
|
}
|
|
#nullable disable
|
|
} |