mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-06-24 07:51:28 +00:00
183 lines
No EOL
7.2 KiB
C#
183 lines
No EOL
7.2 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using LBPUnion.ProjectLighthouse.Configuration;
|
|
using LBPUnion.ProjectLighthouse.Extensions;
|
|
using LBPUnion.ProjectLighthouse.Helpers;
|
|
using LBPUnion.ProjectLighthouse.Tickets;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Moderation;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace LBPUnion.ProjectLighthouse.Database;
|
|
|
|
public partial class DatabaseContext
|
|
{
|
|
[GeneratedRegex("^[a-zA-Z0-9_.-]{3,16}$")]
|
|
private static partial Regex UsernameRegex();
|
|
|
|
public bool IsUsernameValid(string username) => UsernameRegex().IsMatch(username);
|
|
|
|
#nullable enable
|
|
public async Task<UserEntity> CreateUser(string username, string password, string? emailAddress = null)
|
|
{
|
|
if (!password.StartsWith('$')) throw new ArgumentException(nameof(password) + " is not a BCrypt hash");
|
|
|
|
// 16 is PSN max, 3 is PSN minimum
|
|
if (!ServerStatics.IsUnitTesting || !username.StartsWith("unitTestUser"))
|
|
{
|
|
if (username.Length is > 16 or < 3) throw new ArgumentException(nameof(username) + " is either too long or too short");
|
|
|
|
if (!this.IsUsernameValid(username)) throw new ArgumentException(nameof(username) + " does not match the username regex");
|
|
}
|
|
|
|
UserEntity? user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync();
|
|
if (user != null) return user;
|
|
|
|
user = new UserEntity
|
|
{
|
|
Username = username,
|
|
Password = password,
|
|
Biography = "",
|
|
EmailAddress = emailAddress,
|
|
};
|
|
this.Users.Add(user);
|
|
|
|
await this.SaveChangesAsync();
|
|
|
|
if (!ServerConfiguration.Instance.Mail.MailEnabled || emailAddress == null) return user;
|
|
|
|
string body = "An account for Project Lighthouse has been registered with this email address.\n\n" +
|
|
$"You can login at {ServerConfiguration.Instance.ExternalUrl}.";
|
|
|
|
SMTPHelper.SendEmail(emailAddress, "Project Lighthouse Account Created: " + username, body);
|
|
|
|
return user;
|
|
}
|
|
|
|
public async Task<int> UserIdFromUsername(string? username)
|
|
{
|
|
if (username == null) return 0;
|
|
return await this.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
|
|
}
|
|
|
|
public async Task<GameTokenEntity?> AuthenticateUser(UserEntity? user, NPTicket npTicket, string userLocation)
|
|
{
|
|
if (user == null) return null;
|
|
|
|
GameTokenEntity gameToken = new()
|
|
{
|
|
UserToken = CryptoHelper.GenerateAuthToken(),
|
|
User = user,
|
|
UserId = user.UserId,
|
|
UserLocation = userLocation,
|
|
GameVersion = npTicket.GameVersion,
|
|
Platform = npTicket.Platform,
|
|
TicketHash = npTicket.TicketHash,
|
|
// we can get away with a low expiry here since LBP will just get a new token everytime it gets 403'd
|
|
ExpiresAt = DateTime.Now + TimeSpan.FromHours(1),
|
|
};
|
|
|
|
this.GameTokens.Add(gameToken);
|
|
await this.SaveChangesAsync();
|
|
|
|
return gameToken;
|
|
}
|
|
|
|
public async Task RemoveUser(UserEntity? user)
|
|
{
|
|
if (user == null) return;
|
|
if (user.Username.Length == 0) return; // don't delete the placeholder user
|
|
|
|
LastContactEntity? lastContact = await this.LastContacts.FirstOrDefaultAsync(l => l.UserId == user.UserId);
|
|
if (lastContact != null) this.LastContacts.Remove(lastContact);
|
|
|
|
foreach (ModerationCaseEntity modCase in await this.Cases
|
|
.Where(c => c.CreatorId == user.UserId || c.DismisserId == user.UserId)
|
|
.ToListAsync())
|
|
{
|
|
if(modCase.DismisserId == user.UserId)
|
|
modCase.DismisserId = null;
|
|
if(modCase.CreatorId == user.UserId)
|
|
modCase.CreatorId = await SlotHelper.GetPlaceholderUserId(this);
|
|
}
|
|
|
|
foreach (SlotEntity slot in this.Slots.Where(s => s.CreatorId == user.UserId)) await this.RemoveSlot(slot, false);
|
|
|
|
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.RatedComments.RemoveRange(this.RatedComments.Where(p => p.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 HeartUser(int userId, UserEntity heartedUser)
|
|
{
|
|
HeartedProfileEntity? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == userId && q.HeartedUserId == heartedUser.UserId);
|
|
if (heartedProfile != null) return;
|
|
|
|
this.HeartedProfiles.Add(new HeartedProfileEntity
|
|
{
|
|
HeartedUserId = heartedUser.UserId,
|
|
UserId = userId,
|
|
});
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnheartUser(int userId, UserEntity heartedUser)
|
|
{
|
|
HeartedProfileEntity? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == userId && q.HeartedUserId == heartedUser.UserId);
|
|
if (heartedProfile != null) this.HeartedProfiles.Remove(heartedProfile);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task BlockUser(int userId, UserEntity blockedUser)
|
|
{
|
|
if (userId == blockedUser.UserId) return;
|
|
|
|
UserEntity? user = await this.Users.FindAsync(userId);
|
|
|
|
BlockedProfileEntity blockedProfile = new()
|
|
{
|
|
User = user,
|
|
BlockedUser = blockedUser,
|
|
};
|
|
|
|
await this.BlockedProfiles.AddAsync(blockedProfile);
|
|
|
|
await this.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnblockUser(int userId, UserEntity blockedUser)
|
|
{
|
|
if (userId == blockedUser.UserId) return;
|
|
|
|
await this.BlockedProfiles.RemoveWhere(bp => bp.BlockedUserId == blockedUser.UserId && bp.UserId == userId);
|
|
}
|
|
|
|
public async Task<bool> IsUserBlockedBy(int userId, int targetId)
|
|
{
|
|
if (targetId == userId) return false;
|
|
|
|
return await this.BlockedProfiles.Has(bp => bp.BlockedUserId == userId && bp.UserId == targetId);
|
|
}
|
|
|
|
} |