Add relationships feature and EF migration
This commit is contained in:
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using RecNet.Application.Common.Security;
|
using RecNet.Application.Common.Security;
|
||||||
using RecNet.Application.Profiles;
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Avatar;
|
||||||
using AvatarEntity = RecNet.Domain.Profiles.Avatar;
|
using AvatarEntity = RecNet.Domain.Profiles.Avatar;
|
||||||
|
|
||||||
namespace API.Controllers.Avatar.V1;
|
namespace API.Controllers.Avatar.V1;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using API.Contracts.Profiles.Responses;
|
using API.Contracts.Profiles.Responses;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using RecNet.Application.Profiles;
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Login;
|
||||||
using LoginRequest = API.Contracts.Profiles.Requests.LoginRequest;
|
using LoginRequest = API.Contracts.Profiles.Requests.LoginRequest;
|
||||||
|
|
||||||
namespace API.Controllers.Profiles.V1;
|
namespace API.Controllers.Profiles.V1;
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using RecNet.Application.Common.Security;
|
||||||
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
|
namespace API.Controllers.Relationships.V1;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]/v1")]
|
||||||
|
public class RelationshipsController(IRelationshipService relationshipService) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet("get")]
|
||||||
|
public async Task<IReadOnlyList<RelationshipDTO>> GetRelationships(CancellationToken ct)
|
||||||
|
{
|
||||||
|
var profileId = User.GetProfileId();
|
||||||
|
|
||||||
|
return await relationshipService.GetRelationshipsAsync(profileId, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("update")]
|
||||||
|
public async Task<ActionResult<RelationshipDTO>> UpdateRelationship(
|
||||||
|
[FromBody] RelationshipDTO request,
|
||||||
|
CancellationToken ct)
|
||||||
|
{
|
||||||
|
var profileId = User.GetProfileId();
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
await relationshipService.UpdateRelationshipAsync
|
||||||
|
(
|
||||||
|
profileId: profileId,
|
||||||
|
command: new UpdateRelationshipCommand(request.ProfileId, request.Muted, request.Ignored),
|
||||||
|
ct: ct
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using RecNet.Application.Common.Security;
|
using RecNet.Application.Common.Security;
|
||||||
using RecNet.Application.Profiles;
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Settings;
|
||||||
|
|
||||||
namespace API.Controllers.Settings.V1;
|
namespace API.Controllers.Settings.V1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using RecNet.Application.Profiles;
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Avatar;
|
||||||
|
using RecNet.Application.Profiles.Relationships;
|
||||||
|
using RecNet.Application.Profiles.Settings;
|
||||||
|
|
||||||
namespace RecNet.Application.Common.Mapping;
|
namespace RecNet.Application.Common.Mapping;
|
||||||
|
|
||||||
@@ -9,6 +12,7 @@ public class ApplicationMappingProfile : Profile
|
|||||||
{
|
{
|
||||||
CreateMap<Domain.Profiles.Profile, ProfileDTO>();
|
CreateMap<Domain.Profiles.Profile, ProfileDTO>();
|
||||||
CreateMap<Domain.Profiles.Avatar, AvatarDTO>();
|
CreateMap<Domain.Profiles.Avatar, AvatarDTO>();
|
||||||
|
CreateMap<Domain.Profiles.Relationship, RelationshipDTO>();
|
||||||
CreateMap<Domain.Profiles.PlayerSetting, PlayerSettingDTO>();
|
CreateMap<Domain.Profiles.PlayerSetting, PlayerSettingDTO>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using RecNet.Application.Neutrino;
|
using RecNet.Application.Neutrino;
|
||||||
using RecNet.Application.Profiles;
|
using RecNet.Application.Profiles;
|
||||||
|
using RecNet.Application.Profiles.Login;
|
||||||
|
using RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
namespace RecNet.Application;
|
namespace RecNet.Application;
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ public static class DependencyInjection
|
|||||||
services.AddScoped<NameGenerator>();
|
services.AddScoped<NameGenerator>();
|
||||||
|
|
||||||
services.AddScoped<IProfileService, ProfileService>();
|
services.AddScoped<IProfileService, ProfileService>();
|
||||||
|
services.AddScoped<IRelationshipService, RelationshipService>();
|
||||||
services.AddScoped<INeutrinoAuthorizationService, NeutrinoAuthorizationService>();
|
services.AddScoped<INeutrinoAuthorizationService, NeutrinoAuthorizationService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Avatar;
|
||||||
|
|
||||||
public class AvatarDTO
|
public class AvatarDTO
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Avatar;
|
||||||
|
|
||||||
public sealed record UpdateAvatarCommand(
|
public sealed record UpdateAvatarCommand(
|
||||||
string? OutfitSelections,
|
string? OutfitSelections,
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
|
using RecNet.Application.Profiles.Avatar;
|
||||||
|
using RecNet.Application.Profiles.Login;
|
||||||
|
using RecNet.Application.Profiles.Settings;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles;
|
||||||
|
|
||||||
public interface IProfileService
|
public interface IProfileService
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using RecNet.Domain.Common;
|
using RecNet.Domain.Common;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Login;
|
||||||
|
|
||||||
public sealed record LoginProfileCommand(
|
public sealed record LoginProfileCommand(
|
||||||
string AppVersion,
|
string AppVersion,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Login;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using RecNet.Application.Common.Interfaces;
|
using RecNet.Application.Common.Interfaces;
|
||||||
using RecNet.Domain.Profiles.Names;
|
using RecNet.Domain.Profiles.Names;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Login;
|
||||||
|
|
||||||
public class NameGenerator(IConfigService configService)
|
public class NameGenerator(IConfigService configService)
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using RecNet.Application.Common.Interfaces;
|
using RecNet.Application.Common.Interfaces;
|
||||||
using RecNet.Application.Common.Security;
|
using RecNet.Application.Common.Security;
|
||||||
|
using RecNet.Application.Profiles.Avatar;
|
||||||
|
using RecNet.Application.Profiles.Login;
|
||||||
|
using RecNet.Application.Profiles.Settings;
|
||||||
using RecNet.Domain.Common;
|
using RecNet.Domain.Common;
|
||||||
using RecNet.Domain.GameVersions;
|
using RecNet.Domain.GameVersions;
|
||||||
using RecNet.Domain.Profiles;
|
using RecNet.Domain.Profiles;
|
||||||
using ProfileEntity = RecNet.Domain.Profiles.Profile;
|
using ProfileEntity = RecNet.Domain.Profiles.Profile;
|
||||||
|
using AvatarEntity = RecNet.Domain.Profiles.Avatar;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles;
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ public class ProfileService(
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
profile.SetAvatar(
|
profile.SetAvatar(
|
||||||
Avatar.Create(
|
AvatarEntity.Create(
|
||||||
command.OutfitSelections,
|
command.OutfitSelections,
|
||||||
command.SkinColor,
|
command.SkinColor,
|
||||||
command.HairColor
|
command.HairColor
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
|
public interface IRelationshipService
|
||||||
|
{
|
||||||
|
Task<IReadOnlyList<RelationshipDTO>> GetRelationshipsAsync(Guid profileId, CancellationToken ct = default);
|
||||||
|
Task<RelationshipDTO> UpdateRelationshipAsync(Guid profileId, UpdateRelationshipCommand command, CancellationToken ct = default);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
|
public class RelationshipDTO
|
||||||
|
{
|
||||||
|
[JsonPropertyName("ProfileId")]
|
||||||
|
public Guid ProfileId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("Muted")]
|
||||||
|
public bool Muted { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("Ignored")]
|
||||||
|
public bool Ignored { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using RecNet.Domain.Profiles;
|
||||||
|
|
||||||
|
namespace RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
|
public class RelationshipService(IRelationshipRepository repository, IMapper mapper) : IRelationshipService
|
||||||
|
{
|
||||||
|
public async Task<IReadOnlyList<RelationshipDTO>> GetRelationshipsAsync(
|
||||||
|
Guid profileId,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var relationships = await repository.GetAllOwnedRelationships(profileId, ct);
|
||||||
|
|
||||||
|
return mapper.Map<List<RelationshipDTO>>(relationships);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RelationshipDTO> UpdateRelationshipAsync(Guid profileId, UpdateRelationshipCommand command, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var relationship = await repository.GetAsync(profileId, command.ProfileId, ct);
|
||||||
|
if (relationship == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
relationship = Relationship.Create(profileId, command.ProfileId);
|
||||||
|
await repository.AddAsync(relationship, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship.Mutate(command.Muted, command.Ignored);
|
||||||
|
|
||||||
|
await repository.SaveChangesAsync(ct);
|
||||||
|
|
||||||
|
return mapper.Map<RelationshipDTO>(relationship);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace RecNet.Application.Profiles.Relationships;
|
||||||
|
|
||||||
|
public record UpdateRelationshipCommand(
|
||||||
|
Guid ProfileId,
|
||||||
|
bool Muted,
|
||||||
|
bool Ignored);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Settings;
|
||||||
|
|
||||||
public class PlayerSettingDTO
|
public class PlayerSettingDTO
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace RecNet.Application.Profiles;
|
namespace RecNet.Application.Profiles.Settings;
|
||||||
|
|
||||||
public sealed record UpdatePlayerSettingCommand(
|
public sealed record UpdatePlayerSettingCommand(
|
||||||
string Key,
|
string Key,
|
||||||
10
src/RecNet.Domain/Profiles/IRelationshipRepository.cs
Normal file
10
src/RecNet.Domain/Profiles/IRelationshipRepository.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace RecNet.Domain.Profiles;
|
||||||
|
|
||||||
|
public interface IRelationshipRepository
|
||||||
|
{
|
||||||
|
Task<Relationship?> GetAsync(Guid ownerId, Guid profileId, CancellationToken ct = default);
|
||||||
|
Task<IReadOnlyList<Relationship>> GetAllOwnedRelationships(Guid ownerId, CancellationToken ct = default);
|
||||||
|
|
||||||
|
Task AddAsync(Relationship relationship, CancellationToken ct = default);
|
||||||
|
Task SaveChangesAsync(CancellationToken ct = default);
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ public class Profile
|
|||||||
|
|
||||||
public Avatar Avatar { get; private set; } = Avatar.Empty;
|
public Avatar Avatar { get; private set; } = Avatar.Empty;
|
||||||
public ICollection<PlayerSetting> Settings { get; } = [];
|
public ICollection<PlayerSetting> Settings { get; } = [];
|
||||||
|
public ICollection<Relationship> Relationships { get; } = [];
|
||||||
|
|
||||||
public static Profile Create(
|
public static Profile Create(
|
||||||
string name,
|
string name,
|
||||||
|
|||||||
35
src/RecNet.Domain/Profiles/Relationship.cs
Normal file
35
src/RecNet.Domain/Profiles/Relationship.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using RecNet.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace RecNet.Domain.Profiles;
|
||||||
|
|
||||||
|
public class Relationship
|
||||||
|
{
|
||||||
|
public Guid OwnerProfileId { get; private set; }
|
||||||
|
|
||||||
|
public Guid ProfileId { get; private set; }
|
||||||
|
|
||||||
|
public bool Muted { get; private set; }
|
||||||
|
public bool Ignored { get; private set; }
|
||||||
|
|
||||||
|
private Relationship()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Relationship Create(Guid ownerProfileId, Guid profileId)
|
||||||
|
{
|
||||||
|
if (ownerProfileId == Guid.Empty || profileId == Guid.Empty)
|
||||||
|
throw new DomainException("Profile IDs cannot be null.");
|
||||||
|
|
||||||
|
return new Relationship
|
||||||
|
{
|
||||||
|
OwnerProfileId = ownerProfileId,
|
||||||
|
ProfileId = profileId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Mutate(bool muted, bool ignored)
|
||||||
|
{
|
||||||
|
Muted = muted;
|
||||||
|
Ignored = ignored;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ public static class DependencyInjection
|
|||||||
|
|
||||||
builder.Services.AddScoped<IGameVersionRepository, GameVersionRepository>();
|
builder.Services.AddScoped<IGameVersionRepository, GameVersionRepository>();
|
||||||
builder.Services.AddScoped<IProfileRepository, ProfileRepository>();
|
builder.Services.AddScoped<IProfileRepository, ProfileRepository>();
|
||||||
|
builder.Services.AddScoped<IRelationshipRepository, RelationshipRepository>();
|
||||||
builder.Services.AddScoped<IServerConfigRepository, ServerConfigRepository>();
|
builder.Services.AddScoped<IServerConfigRepository, ServerConfigRepository>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IConfigService, ConfigService>();
|
builder.Services.AddScoped<IConfigService, ConfigService>();
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ public class ProfileConfiguration : IEntityTypeConfiguration<Profile>
|
|||||||
|
|
||||||
builder.Navigation(x => x.Settings)
|
builder.Navigation(x => x.Settings)
|
||||||
.UsePropertyAccessMode(PropertyAccessMode.Field);
|
.UsePropertyAccessMode(PropertyAccessMode.Field);
|
||||||
|
|
||||||
|
builder.HasMany(x => x.Relationships)
|
||||||
|
.WithOne()
|
||||||
|
.HasForeignKey(x => x.OwnerProfileId);
|
||||||
|
|
||||||
|
builder.Navigation(x => x.Relationships)
|
||||||
|
.UsePropertyAccessMode(PropertyAccessMode.Field);
|
||||||
|
|
||||||
builder.OwnsOne(x => x.Avatar);
|
builder.OwnsOne(x => x.Avatar);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
using RecNet.Domain.Profiles;
|
||||||
|
|
||||||
|
namespace RecNet.Infrastructure.Persistence.Configurations;
|
||||||
|
|
||||||
|
public class RelationshipConfiguration : IEntityTypeConfiguration<Relationship>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Relationship> builder)
|
||||||
|
{
|
||||||
|
builder.HasKey(x => new { x.OwnerProfileId, x.ProfileId });
|
||||||
|
|
||||||
|
builder.Property(x => x.OwnerProfileId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(x => x.ProfileId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasOne<Profile>()
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(x => x.ProfileId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbCont
|
|||||||
{
|
{
|
||||||
public DbSet<Profile> Profiles => Set<Profile>();
|
public DbSet<Profile> Profiles => Set<Profile>();
|
||||||
public DbSet<PlayerSetting> PlayerSettings => Set<PlayerSetting>();
|
public DbSet<PlayerSetting> PlayerSettings => Set<PlayerSetting>();
|
||||||
|
public DbSet<Relationship> Relationships => Set<Relationship>();
|
||||||
public DbSet<GameVersion> GameVersions => Set<GameVersion>();
|
public DbSet<GameVersion> GameVersions => Set<GameVersion>();
|
||||||
public DbSet<ServerConfig> ServerConfigs => Set<ServerConfig>();
|
public DbSet<ServerConfig> ServerConfigs => Set<ServerConfig>();
|
||||||
|
|
||||||
|
|||||||
209
src/RecNet.Infrastructure/Persistence/Migrations/20260626215037_Relationships.Designer.cs
generated
Normal file
209
src/RecNet.Infrastructure/Persistence/Migrations/20260626215037_Relationships.Designer.cs
generated
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using RecNet.Infrastructure.Persistence;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace RecNet.Infrastructure.Persistence.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20260626215037_Relationships")]
|
||||||
|
partial class Relationships
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Configuration.ServerConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("ServerConfigs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.GameVersions.GameVersion", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Version")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsValid")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("Version");
|
||||||
|
|
||||||
|
b.ToTable("GameVersions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.PlayerSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "Key");
|
||||||
|
|
||||||
|
b.ToTable("PlayerSettings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("ProfileId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("DeviceIds")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<bool>("IsBanned")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsDeveloper")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsModerator")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<byte[]>("MetaAuthenticationSecret")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)");
|
||||||
|
|
||||||
|
b.Property<string>("Platform")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("character varying(50)");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("character varying(50)");
|
||||||
|
|
||||||
|
b.HasKey("ProfileId");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Profiles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Relationship", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("OwnerProfileId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProfileId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Ignored")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("Muted")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("OwnerProfileId", "ProfileId");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("Relationships");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.PlayerSetting", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
|
.WithMany("Settings")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Profile", b =>
|
||||||
|
{
|
||||||
|
b.OwnsOne("RecNet.Domain.Profiles.Avatar", "Avatar", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<Guid>("ProfileId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b1.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b1.Property<string>("OutfitSelections")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b1.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b1.HasKey("ProfileId");
|
||||||
|
|
||||||
|
b1.ToTable("Profiles");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("ProfileId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("Avatar")
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Relationship", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
|
.WithMany("Relationships")
|
||||||
|
.HasForeignKey("OwnerProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Relationships");
|
||||||
|
|
||||||
|
b.Navigation("Settings");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace RecNet.Infrastructure.Persistence.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Relationships : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Relationships",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
OwnerProfileId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProfileId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Muted = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
Ignored = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Relationships", x => new { x.OwnerProfileId, x.ProfileId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Relationships_Profiles_OwnerProfileId",
|
||||||
|
column: x => x.OwnerProfileId,
|
||||||
|
principalTable: "Profiles",
|
||||||
|
principalColumn: "ProfileId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Relationships_Profiles_ProfileId",
|
||||||
|
column: x => x.ProfileId,
|
||||||
|
principalTable: "Profiles",
|
||||||
|
principalColumn: "ProfileId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Relationships_ProfileId",
|
||||||
|
table: "Relationships",
|
||||||
|
column: "ProfileId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Relationships");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,27 @@ namespace RecNet.Infrastructure.Persistence.Migrations
|
|||||||
b.ToTable("Profiles");
|
b.ToTable("Profiles");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Relationship", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("OwnerProfileId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProfileId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Ignored")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("Muted")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("OwnerProfileId", "ProfileId");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("Relationships");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("RecNet.Domain.Profiles.PlayerSetting", b =>
|
modelBuilder.Entity("RecNet.Domain.Profiles.PlayerSetting", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
@@ -158,8 +179,25 @@ namespace RecNet.Infrastructure.Persistence.Migrations
|
|||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RecNet.Domain.Profiles.Relationship", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
|
.WithMany("Relationships")
|
||||||
|
.HasForeignKey("OwnerProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("RecNet.Domain.Profiles.Profile", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("RecNet.Domain.Profiles.Profile", b =>
|
modelBuilder.Entity("RecNet.Domain.Profiles.Profile", b =>
|
||||||
{
|
{
|
||||||
|
b.Navigation("Relationships");
|
||||||
|
|
||||||
b.Navigation("Settings");
|
b.Navigation("Settings");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using RecNet.Domain.Profiles;
|
||||||
|
|
||||||
|
namespace RecNet.Infrastructure.Persistence.Repositories;
|
||||||
|
|
||||||
|
public class RelationshipRepository(DatabaseContext dbContext) : IRelationshipRepository
|
||||||
|
{
|
||||||
|
public Task<Relationship?> GetAsync(
|
||||||
|
Guid ownerId,
|
||||||
|
Guid profileId,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
=> dbContext.Relationships
|
||||||
|
.FirstOrDefaultAsync(x =>
|
||||||
|
x.OwnerProfileId == ownerId &&
|
||||||
|
x.ProfileId == profileId,
|
||||||
|
ct);
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<Relationship>> GetAllOwnedRelationships(Guid ownerId, CancellationToken ct = default)
|
||||||
|
=> await dbContext.Relationships
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(x => x.OwnerProfileId == ownerId)
|
||||||
|
.ToListAsync(ct);
|
||||||
|
|
||||||
|
public async Task AddAsync(
|
||||||
|
Relationship relationship,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
=> await dbContext.Relationships.AddAsync(relationship, ct);
|
||||||
|
|
||||||
|
public Task SaveChangesAsync(CancellationToken ct = default)
|
||||||
|
=> dbContext.SaveChangesAsync(ct);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user